[automerger skipped] Merge "Import translations. DO NOT MERGE ANYWHERE" into stage-aosp-master am: 0477a27ad4 -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Car/+/20628676

Change-Id: Ie6cd95d1f3bdb325f4545d4fc954ef0c1ffdb102
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/FrameworkPackageStubs/res/values-en-rCA/strings.xml b/FrameworkPackageStubs/res/values-en-rCA/strings.xml
index 92b3376..97c9277 100644
--- a/FrameworkPackageStubs/res/values-en-rCA/strings.xml
+++ b/FrameworkPackageStubs/res/values-en-rCA/strings.xml
@@ -3,6 +3,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6179574017413146651">"Activity Stub"</string>
     <string name="message_not_supported" msgid="133939962837892495">"No application can handle this action"</string>
-    <string name="pip_not_supported" msgid="8681268258599412706">"Picture in Picture is not supported on this device"</string>
+    <string name="pip_not_supported" msgid="8681268258599412706">"Picture-in-picture is not supported on this device"</string>
     <string name="stub_name" msgid="3987164490218189006">"None"</string>
 </resources>
diff --git a/apex_car_framework/Android.bp b/apex_car_framework/Android.bp
index 0043ed5..24f6401 100644
--- a/apex_car_framework/Android.bp
+++ b/apex_car_framework/Android.bp
@@ -128,6 +128,7 @@
             "android.car.media",
             "android.car.navigation",
             "android.car.occupantawareness",
+            "android.car.oem",
             "android.car.os",
             "android.car.projection",
             "android.car.settings",
diff --git a/car-evs-helper-lib/Android.bp b/car-evs-helper-lib/Android.bp
new file mode 100644
index 0000000..f383376
--- /dev/null
+++ b/car-evs-helper-lib/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This project contains libraries that are used internally, mostly by
+// CarService and CarServiceHelperService.
+//
+// They're not meant to be used by other system apps and hence are not
+// supported.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_library {
+    name: "car-evs-helper-lib",
+    srcs: [
+        "src/**/*.java",
+    ],
+    libs: [
+        "android.car",
+    ],
+    platform_apis: true,
+    required : [
+        "libcarevsglrenderer_jni",
+    ],
+}
diff --git a/car-evs-helper-lib/AndroidManifest.xml b/car-evs-helper-lib/AndroidManifest.xml
new file mode 100644
index 0000000..ba31871
--- /dev/null
+++ b/car-evs-helper-lib/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.car.internal.evs" >
+</manifest>
diff --git a/car-evs-helper-lib/README.md b/car-evs-helper-lib/README.md
new file mode 100644
index 0000000..416a8a8
--- /dev/null
+++ b/car-evs-helper-lib/README.md
@@ -0,0 +1,82 @@
+<!--
+  Copyright (C) 2022 The Android Open Source Project
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+       http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License
+  -->
+# car-evs-helper-lib
+This directory contains two modules that are used by other apps to process
+CarEvsBufferDescriptor and render its contents to the display with EGL.
+* `car-evs-helper-lib:` This library contains `CarEvsGLSurfaceView` and
+  `CarEvsBufferRenderer` classes.
+* `libcarevsglrenderer_jni`: This is a JNI library `CarEvsBufferRenderer` uses
+  to render the contents of `CarEvsBufferDescriptor` with EGL.
+## How to use
+Please follow below instructions to delegate a `CarEvsBufferDescriptor` rendering
+to this library.  A reference implementation is also available at
+`packages/services/Car/tests/CarEvsCameraPreviewApp`.
+1. Make the application refer to `car-evs-helper-lib` and
+   `libcarevsglrenderer_jni` libraries by adding below lines to `Android.bp`.
+```
+static_libs: ["car-evs-helper-lib"],
+jni_libs: ["libcarevsglrenderer_jni"],
+```
+2. Implement `CarEvsGLSurfaceView.Callback` interface. For example,
+```
+/**
+ * This method is called by the renderer to fetch a new frame to draw.
+ */
+@Override
+public CarEvsBufferDescriptor getNewFrame() {
+    synchronized(mLock) {
+        // Return a buffer to render.
+        return mBufferToRender;
+    }
+}
+/**
+ * This method is called by the renderer when it is done with a passed
+ * CarEvsBufferDescriptor object.
+ */
+@Override
+public void returnBuffer(CarEvsBufferDescriptor buffer) {
+    // Return a buffer to CarEvsService.
+    try {
+        mEvsManager.returnFrameBuffer(buffer);
+    } catch (Exception e) {
+        ...
+    }
+    ...
+}
+```
+3. Create `CarEvsGLSurfaceView` with the application context,
+   `CarEvsGLSurfaceView.Callback` object, and, optionally, a desired in-plane
+   rotation angle.
+```
+private CarEvsGLSurfaceView mView;
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+    ...
+    mView = CarEvsGLSurfaceView(getAppliation(), this, /* angleInDegree= */ 0);
+    ...
+}
+```
+4. Start a video stream and update wheneven new frame buffer arrives.  For
+   example,
+```
+private final CarEvsManager.CarEvsStreamCallback mStreamHandler =
+    new CarEvsManager.CarEvsStreamCallback() {
+    ...
+    @Override
+    public void onNewFrame(CarEvsBufferDescriptor buffer) {
+      synchronized(mLock) {
+        mBufferToRender = buffer;
+      }
+    }
+}
+```
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp b/car-evs-helper-lib/jni/Android.bp
similarity index 91%
rename from tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp
rename to car-evs-helper-lib/jni/Android.bp
index d06620a..702a23e 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp
+++ b/car-evs-helper-lib/jni/Android.bp
@@ -23,9 +23,7 @@
 
     sdk_version: "current",
 
-    srcs: [
-        "CarEvsCameraPreviewRenderer.cpp",
-    ],
+    srcs: ["./**/*.cpp"],
 
     header_libs: ["jni_headers"],
 
@@ -43,7 +41,7 @@
     },
 
     cflags: [
-        "-DLOG_TAG=\"CarEvsCameraRendererJNI\"",
+        "-DLOG_TAG=\"CarEvsBufferRendererJNI\"",
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
         "-Wall",
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/CarEvsCameraPreviewRenderer.cpp b/car-evs-helper-lib/jni/CarEvsBufferRenderer.cpp
similarity index 84%
rename from tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/CarEvsCameraPreviewRenderer.cpp
rename to car-evs-helper-lib/jni/CarEvsBufferRenderer.cpp
index 91ca40b..654703f 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/CarEvsCameraPreviewRenderer.cpp
+++ b/car-evs-helper-lib/jni/CarEvsBufferRenderer.cpp
@@ -20,19 +20,18 @@
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
 #include <GLES3/gl3ext.h>
-
 #include <android/hardware_buffer_jni.h>
+
 #include <jni.h>
 
 namespace {
 
-const char kClassName[] = "com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer";
+const char kClassName[] = "com/android/car/internal/evs/GLES20CarEvsBufferRenderer";
 
 EGLImageKHR gKHRImage = EGL_NO_IMAGE_KHR;
 
-jboolean nativeUpdateTexture(
-        JNIEnv* env, jobject /*thiz*/, jobject hardwareBufferObj, jint textureId) {
-
+jboolean nativeUpdateTexture(JNIEnv* env, jobject /*thiz*/, jobject hardwareBufferObj,
+                             jint textureId) {
     EGLDisplay eglCurrentDisplay = eglGetCurrentDisplay();
     if (gKHRImage != EGL_NO_IMAGE_KHR) {
         // Release a previous EGL image
@@ -49,11 +48,8 @@
     // Create EGL image from a native hardware buffer
     EGLClientBuffer eglBuffer = eglGetNativeClientBufferANDROID(nativeBuffer);
     EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-    gKHRImage = eglCreateImageKHR(eglCurrentDisplay,
-                                  EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID,
-                                  eglBuffer,
-                                  eglImageAttributes);
+    gKHRImage = eglCreateImageKHR(eglCurrentDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                  eglBuffer, eglImageAttributes);
     if (gKHRImage == EGL_NO_IMAGE_KHR) {
         return JNI_FALSE;
     }
@@ -74,7 +70,7 @@
     return JNI_TRUE;
 }
 
-} // namespace unnamed
+}  // namespace
 
 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
     JNIEnv* env;
@@ -85,7 +81,7 @@
     // Registers native methods
     static const JNINativeMethod methods[] = {
             {"nUpdateTexture", "(Landroid/hardware/HardwareBuffer;I)Z",
-                reinterpret_cast<void*>(nativeUpdateTexture)},
+             reinterpret_cast<void*>(nativeUpdateTexture)},
     };
 
     jclass clazz = env->FindClass(kClassName);
diff --git a/car-evs-helper-lib/src/com/android/car/internal/evs/CarEvsGLSurfaceView.java b/car-evs-helper-lib/src/com/android/car/internal/evs/CarEvsGLSurfaceView.java
new file mode 100644
index 0000000..c798ee3
--- /dev/null
+++ b/car-evs-helper-lib/src/com/android/car/internal/evs/CarEvsGLSurfaceView.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.internal.evs;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.evs.CarEvsBufferDescriptor;
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.view.MotionEvent;
+
+import com.android.internal.util.Preconditions;
+import com.android.car.internal.evs.GLES20CarEvsBufferRenderer;
+
+/**
+ * GPU-backed SurfaceView to render a hardware buffer described by {@link CarEvsBufferDescriptor}.
+ */
+public final class CarEvsGLSurfaceView extends GLSurfaceView {
+    private static final String TAG = CarEvsGLSurfaceView.class.getSimpleName();
+    private static final int DEFAULT_IN_PLANE_ROTATION_ANGLE = 0;
+
+    private final GLES20CarEvsBufferRenderer mRenderer;
+
+    /** An interface to pull and return {@code CarEvsBufferDescriptor} object to render. */
+    public interface BufferCallback {
+        /**
+         * Requests a new {@link CarEvsBufferDescriptor} to draw.
+         *
+         * This method may return a {@code null} if no new frame has been prepared since the last
+         * frame was drawn.
+         *
+         * @return {@link CarEvsBufferDescriptor} object to process.
+         */
+        @Nullable CarEvsBufferDescriptor onBufferRequested();
+
+        /**
+         * Notifies that the buffer is processed.
+         *
+         * @param buffer {@link CarEvsBufferDescriptor} object we are done with.
+         */
+        void onBufferProcessed(@NonNull CarEvsBufferDescriptor buffer);
+    }
+
+    private CarEvsGLSurfaceView(Context context, BufferCallback callback, int angleInDegree) {
+        super(context);
+        setEGLContextClientVersion(2);
+
+        mRenderer = new GLES20CarEvsBufferRenderer(context, callback, angleInDegree);
+        setRenderer(mRenderer);
+
+        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+    }
+
+    /**
+     * Returns all buffers held by the renderer.
+     */
+    public void reset() {
+        mRenderer.clearBuffer();
+    }
+
+    /**
+     * Creates a {@link CarEvsGLSurfaceView} object with the default in-plane rotation angle.
+     *
+     * @param context Current appliation context.
+     * @param callback {@link CarEvsGLSurfaceView.BufferCallback} object.
+     *
+     */
+    public static CarEvsGLSurfaceView create(Context context, BufferCallback callback) {
+        return create(context, callback, DEFAULT_IN_PLANE_ROTATION_ANGLE);
+    }
+
+    /**
+     * Creates a {@link CarEvsGLSurfaceView} object with a given in-plane rotation angle in degree.
+     *
+     * @param context Current appliation context.
+     * @param callback {@link CarEvsGLSurfaceView.BufferCallback} object.
+     * @param angleInDegree In-plane counter-clockwise rotation angle in degree.
+     */
+    public static CarEvsGLSurfaceView create(Context context, BufferCallback callback,
+            int angleInDegree) {
+
+        Preconditions.checkArgument(context != null, "Context cannot be null.");
+        Preconditions.checkArgument(callback != null, "BufferCallback cannot be null.");
+
+        return new CarEvsGLSurfaceView(context, callback, angleInDegree);
+    }
+}
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer.java b/car-evs-helper-lib/src/com/android/car/internal/evs/GLES20CarEvsBufferRenderer.java
similarity index 70%
rename from tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer.java
rename to car-evs-helper-lib/src/com/android/car/internal/evs/GLES20CarEvsBufferRenderer.java
index f04d15b..8de69f1 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer.java
+++ b/car-evs-helper-lib/src/com/android/car/internal/evs/GLES20CarEvsBufferRenderer.java
@@ -14,37 +14,36 @@
  * limitations under the License.
  */
 
-package com.google.android.car.evs;
+package com.android.car.internal.evs;
 
 import static android.opengl.GLU.gluErrorString;
 
+import android.annotation.NonNull;
 import android.car.evs.CarEvsBufferDescriptor;
 import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
 import android.hardware.HardwareBuffer;
 import android.opengl.GLES20;
 import android.opengl.GLSurfaceView;
-import android.opengl.GLUtils;
 import android.util.Log;
 
-import androidx.annotation.GuardedBy;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
-import java.util.Random;
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
 /**
- * GLES20 SurfaceView Renderer
+ * GLES20 SurfaceView Renderer for CarEvsBufferDescriptor.
  */
-public final class GLES20CarEvsCameraPreviewRenderer implements GLSurfaceView.Renderer {
-    private static final String TAG = GLES20CarEvsCameraPreviewRenderer.class.getSimpleName();
+public final class GLES20CarEvsBufferRenderer implements GLSurfaceView.Renderer {
+
+    private static final String TAG = GLES20CarEvsBufferRenderer.class.getSimpleName()
+            .replace("GLES20", "");
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private static final int FLOAT_SIZE_BYTES = 4;
 
     private static final float[] sVertCarPosData = {
@@ -66,49 +65,58 @@
             0.0f, 0.0f, 0.0f, 1.0f };
 
     private final String mVertexShader =
-        "#version 300 es                    \n" +
-        "layout(location = 0) in vec4 pos;  \n" +
-        "layout(location = 1) in vec2 tex;  \n" +
-        "uniform mat4 cameraMat;            \n" +
-        "out vec2 uv;                       \n" +
-        "void main()                        \n" +
-        "{                                  \n" +
-        "   gl_Position = cameraMat * pos;  \n" +
-        "   uv = tex;                       \n" +
-        "}                                  \n";
+        "attribute vec4 pos;                    \n" +
+        "attribute vec2 tex;                    \n" +
+        "uniform mat4 cameraMat;                \n" +
+        "varying vec2 uv;                       \n" +
+        "void main()                            \n" +
+        "{                                      \n" +
+        "   gl_Position = cameraMat * pos;      \n" +
+        "   uv = tex;                           \n" +
+        "}                                      \n";
 
     private final String mFragmentShader =
-        "#version 300 es                    \n" +
-        "precision mediump float;           \n" +
-        "uniform sampler2D tex;             \n" +
-        "in vec2 uv;                        \n" +
-        "out vec4 color;                    \n" +
-        "void main()                        \n" +
-        "{                                  \n" +
-        "    vec4 texel = texture(tex, uv); \n" +
-        "    color = texel;                 \n" +
-        "}                                  \n";
+        "precision mediump float;               \n" +
+        "uniform sampler2D tex;                 \n" +
+        "varying vec2 uv;                       \n" +
+        "void main()                            \n" +
+        "{                                      \n" +
+        "    gl_FragColor = texture2D(tex, uv); \n" +
+        "}                                      \n";
 
     private final Object mLock = new Object();
+    private final CarEvsGLSurfaceView.BufferCallback mCallback;
+    private final Context mContext;
+    private final FloatBuffer mVertCarPos;
+    private final FloatBuffer mVertCarTex;
 
-    private CarEvsCameraPreviewActivity mActivity;
+    private int mProgram;
+    private int mTextureId;
+    private int mWidth;
+    private int mHeight;
 
+    // Native method to update the texture with a received frame buffer
     @GuardedBy("mLock")
-    private CarEvsBufferDescriptor mBufferInUse = null;
+    private CarEvsBufferDescriptor mBufferInUse;
 
-    public GLES20CarEvsCameraPreviewRenderer(Context context,
-            CarEvsCameraPreviewActivity activity) {
+    /** Load jni on initialization. */
+    static {
+        System.loadLibrary("carevsglrenderer_jni");
+    }
+
+    public GLES20CarEvsBufferRenderer(@NonNull Context context,
+            @NonNull CarEvsGLSurfaceView.BufferCallback callback, int angleInDegree) {
+
+        Preconditions.checkArgument(context != null, "Context cannot be null.");
+        Preconditions.checkArgument(callback != null, "Callback cannot be null.");
 
         mContext = context;
-        mActivity = activity;
+        mCallback = callback;
 
         mVertCarPos = ByteBuffer.allocateDirect(sVertCarPosData.length * FLOAT_SIZE_BYTES)
                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
         mVertCarPos.put(sVertCarPosData).position(0);
 
-        // Rotates the matrix in counter-clockwise
-        int angleInDegree = mContext.getResources().getInteger(
-                R.integer.config_evsRearviewCameraInPlaneRotationAngle);
         double angleInRadian = Math.toRadians(angleInDegree);
         float[] rotated = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
         float sin = (float)Math.sin(angleInRadian);
@@ -140,7 +148,7 @@
         }
 
         // bufferToReturn is not null here.
-        mActivity.returnBuffer(bufferToReturn);
+        mCallback.onBufferProcessed(bufferToReturn);
     }
 
     @Override
@@ -149,7 +157,8 @@
 
         CarEvsBufferDescriptor bufferToRender = null;
         CarEvsBufferDescriptor bufferToReturn = null;
-        CarEvsBufferDescriptor newFrame = mActivity.getNewFrame();
+        CarEvsBufferDescriptor newFrame = mCallback.onBufferRequested();
+
         synchronized (mLock) {
             if (newFrame != null) {
                 // If a new frame has not been delivered yet, we're using a previous frame.
@@ -161,8 +170,15 @@
             bufferToRender = mBufferInUse;
         }
 
+        if (bufferToRender == null) {
+            if (DBG) {
+                Log.d(TAG, "No buffer to draw.");
+            }
+            return;
+        }
+
         if (bufferToReturn != null) {
-            mActivity.returnBuffer(bufferToReturn);
+            mCallback.onBufferProcessed(bufferToReturn);
         }
 
         // Specify a shader program to use
@@ -175,22 +191,13 @@
         }
         GLES20.glUniformMatrix4fv(matrix, 1, false, sIdentityMatrix, 0);
 
-        if (bufferToRender == null) {
-            // Show the default screen
-            drawDefaultScreen();
-        } else {
-            // Retrieve a hardware buffer from a descriptor and update the texture
-            HardwareBuffer buffer = bufferToRender.getHardwareBuffer();
-            if (buffer == null) {
-                Log.e(TAG, "HardwareBuffer is invalid.");
-                drawDefaultScreen();
-            } else {
-                // Update the texture with a given hardware buffer
-                if (!nUpdateTexture(buffer, mTextureId)) {
-                    throw new RuntimeException(
-                            "Failed to update the texture with the preview frame");
-                }
-            }
+        // Retrieve a hardware buffer from a descriptor and update the texture
+        HardwareBuffer buffer = bufferToRender.getHardwareBuffer();
+
+        // Update the texture with a given hardware buffer
+        if (!nUpdateTexture(buffer, mTextureId)) {
+            throw new RuntimeException(
+                    "Failed to update the texture with the preview frame");
         }
 
         GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
@@ -239,7 +246,8 @@
         mHeight = height;
     }
 
-    @Override public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+    @Override
+    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
         // Use the GLES20 class's static methods instead of a passed GL10 interface.
         mProgram = buildShaderProgram(mVertexShader, mFragmentShader);
         if (mProgram == 0) {
@@ -270,34 +278,6 @@
                 GLES20.GL_CLAMP_TO_EDGE);
     }
 
-    public void setTextLocation(float x, float y) {
-        mTextX = x;
-        mTextY = y;
-    }
-
-    private void drawDefaultScreen() {
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.rearview);
-        Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
-        Canvas canvas = new Canvas(bitmap);
-        drawable.setBounds(0, 0, mWidth, mHeight);
-        drawable.draw(canvas);
-
-        Paint fontColor = new Paint();
-        fontColor.setTextSize(Math.min(mWidth, mHeight) * 0.10f);
-        fontColor.setAntiAlias(true);
-
-        // Pick a font color randomly
-        fontColor.setColor((0xFF << 24) + (mRandom.nextInt(0xFF) << 16)
-                + (mRandom.nextInt(0xFF) << 8) + mRandom.nextInt(0xFF));
-
-        // Set a location of the text relative to the surface size
-        canvas.drawText("The rearview is not available.", mTextX, mTextY, fontColor);
-
-        // Draw
-        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, /* level = */ 0, bitmap, /* border = */ 0);
-        bitmap.recycle();
-    }
-
     private int loadShader(int shaderType, String source) {
         int shader = GLES20.glCreateShader(shaderType);
         if (shader == 0) {
@@ -342,6 +322,10 @@
         checkGlError("glAttachShader");
         GLES20.glAttachShader(program, fragmentShader);
         checkGlError("glAttachShader");
+
+        GLES20.glBindAttribLocation(program, 0, "pos");
+        GLES20.glBindAttribLocation(program, 1, "tex");
+
         GLES20.glLinkProgram(program);
         int[] linkStatus = new int[1];
         GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
@@ -363,21 +347,5 @@
         }
     }
 
-    private Context mContext;
-    private int mProgram;
-    private int mTextureId;
-    private FloatBuffer mVertCarPos;
-    private FloatBuffer mVertCarTex;
-    private int mWidth;
-    private int mHeight;
-    private float mTextX;
-    private float mTextY;
-    private Random mRandom = new Random();
-
-    static {
-        System.loadLibrary("carevsglrenderer_jni");
-    }
-
-    // Native method to update the texture with a received frame buffer
     private native boolean nUpdateTexture(HardwareBuffer buffer, int textureId);
 }
diff --git a/car-lib-module/api/current.txt b/car-lib-module/api/current.txt
index 05464e4..bae9a95 100644
--- a/car-lib-module/api/current.txt
+++ b/car-lib-module/api/current.txt
@@ -164,6 +164,7 @@
   public static class CarVersion.VERSION_CODES {
     field @NonNull public static final android.car.CarVersion TIRAMISU_0;
     field @NonNull public static final android.car.CarVersion TIRAMISU_1;
+    field @NonNull public static final android.car.CarVersion TIRAMISU_2;
   }
 
   @Deprecated public final class EvConnectorType {
@@ -214,6 +215,7 @@
   public static class PlatformVersion.VERSION_CODES {
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
+    field @NonNull public static final android.car.PlatformVersion TIRAMISU_2;
   }
 
   public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
diff --git a/car-lib-module/api/system-current.txt b/car-lib-module/api/system-current.txt
index 2ffe202..54792a8 100644
--- a/car-lib-module/api/system-current.txt
+++ b/car-lib-module/api/system-current.txt
@@ -1137,6 +1137,31 @@
 
 }
 
+package android.car.oem {
+
+  public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
+    method public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+  }
+
+  public abstract class OemCarService extends android.app.Service {
+    ctor public OemCarService();
+    method @CallSuper public void dump(@Nullable java.io.FileDescriptor, @Nullable java.io.PrintWriter, @Nullable String[]);
+    method @Nullable public android.car.oem.OemCarAudioFocusService getOemAudioFocusService();
+    method @NonNull public abstract android.car.CarVersion getSupportedCarVersion();
+    method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public abstract void onCarServiceReady();
+    method public final int onStartCommand(@Nullable android.content.Intent, int, int);
+  }
+
+  public interface OemCarServiceComponent {
+    method public void dump(@Nullable java.io.PrintWriter, @Nullable String[]);
+    method public void init();
+    method public void onCarServiceReady();
+    method public void release();
+  }
+
+}
+
 package android.car.os {
 
   public final class CarPerformanceManager {
diff --git a/car-lib-module/api/test-current.txt b/car-lib-module/api/test-current.txt
index bcbc685..eeadc93 100644
--- a/car-lib-module/api/test-current.txt
+++ b/car-lib-module/api/test-current.txt
@@ -94,12 +94,14 @@
     method public android.car.CarVersion get();
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
+    enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_2;
   }
 
   public enum ApiRequirements.PlatformVersion {
     method public android.car.PlatformVersion get();
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
+    enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_2;
   }
 
 }
@@ -188,6 +190,7 @@
 
   public final class CarTestManager {
     ctor public CarTestManager(@NonNull android.car.Car, @NonNull android.os.IBinder);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void startCarService(@NonNull android.os.IBinder);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void stopCarService(@NonNull android.os.IBinder);
   }
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 05464e4..bae9a95 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -164,6 +164,7 @@
   public static class CarVersion.VERSION_CODES {
     field @NonNull public static final android.car.CarVersion TIRAMISU_0;
     field @NonNull public static final android.car.CarVersion TIRAMISU_1;
+    field @NonNull public static final android.car.CarVersion TIRAMISU_2;
   }
 
   @Deprecated public final class EvConnectorType {
@@ -214,6 +215,7 @@
   public static class PlatformVersion.VERSION_CODES {
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
+    field @NonNull public static final android.car.PlatformVersion TIRAMISU_2;
   }
 
   public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 2ffe202..54792a8 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -1137,6 +1137,31 @@
 
 }
 
+package android.car.oem {
+
+  public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
+    method public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+  }
+
+  public abstract class OemCarService extends android.app.Service {
+    ctor public OemCarService();
+    method @CallSuper public void dump(@Nullable java.io.FileDescriptor, @Nullable java.io.PrintWriter, @Nullable String[]);
+    method @Nullable public android.car.oem.OemCarAudioFocusService getOemAudioFocusService();
+    method @NonNull public abstract android.car.CarVersion getSupportedCarVersion();
+    method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public abstract void onCarServiceReady();
+    method public final int onStartCommand(@Nullable android.content.Intent, int, int);
+  }
+
+  public interface OemCarServiceComponent {
+    method public void dump(@Nullable java.io.PrintWriter, @Nullable String[]);
+    method public void init();
+    method public void onCarServiceReady();
+    method public void release();
+  }
+
+}
+
 package android.car.os {
 
   public final class CarPerformanceManager {
diff --git a/car-lib/api/system-lint-baseline.txt b/car-lib/api/system-lint-baseline.txt
index cb1a48d..4aee850 100644
--- a/car-lib/api/system-lint-baseline.txt
+++ b/car-lib/api/system-lint-baseline.txt
@@ -65,6 +65,8 @@
     Must override both equals and hashCode; missing one in android.car.vms.VmsAvailableLayers
 
 
+ExecutorRegistration: android.car.CarBugreportManager#requestBugreport(android.os.ParcelFileDescriptor, android.os.ParcelFileDescriptor, android.car.CarBugreportManager.CarBugreportManagerCallback):
+    Registration methods should have overload that accepts delivery Executor: `requestBugreport`
 ExecutorRegistration: android.car.CarProjectionManager#registerProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int):
     Registration methods should have overload that accepts delivery Executor: `registerProjectionListener`
 ExecutorRegistration: android.car.CarProjectionManager#registerProjectionStatusListener(android.car.CarProjectionManager.ProjectionStatusListener):
@@ -75,6 +77,8 @@
     Registration methods should have overload that accepts delivery Executor: `registerListener`
 ExecutorRegistration: android.car.drivingstate.CarDrivingStateManager#registerListener(android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener):
     Registration methods should have overload that accepts delivery Executor: `registerListener`
+ExecutorRegistration: android.car.drivingstate.CarUxRestrictionsManager#setListener(int, android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener):
+    Registration methods should have overload that accepts delivery Executor: `setListener`
 ExecutorRegistration: android.car.hardware.CarVendorExtensionManager#registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback):
     Registration methods should have overload that accepts delivery Executor: `registerCallback`
 ExecutorRegistration: android.car.hardware.cabin.CarCabinManager#registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback):
@@ -643,8 +647,16 @@
     Missing nullability on parameter `out` in method `writeToParcel`
 
 
+NotCloseable: android.car.oem.OemCarServiceComponent:
+    Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.car.oem.OemCarServiceComponent
+
+
 NullableCollection: android.car.cluster.ClusterActivityState#getExtras():
     Return type of method android.car.cluster.ClusterActivityState.getExtras() is a nullable collection (`android.os.Bundle`); must be non-null
+NullableCollection: android.car.drivingstate.CarUxRestrictionsManager#getConfigs():
+    Return type of method android.car.drivingstate.CarUxRestrictionsManager.getConfigs() is a nullable collection (`java.util.List`); must be non-null
+NullableCollection: android.car.drivingstate.CarUxRestrictionsManager#getStagedConfigs():
+    Return type of method android.car.drivingstate.CarUxRestrictionsManager.getStagedConfigs() is a nullable collection (`java.util.List`); must be non-null
 NullableCollection: android.car.telemetry.CarTelemetryManager.MetricsReportCallback#onResult(String, android.os.PersistableBundle, byte[], int) parameter #1:
     Type of parameter report in android.car.telemetry.CarTelemetryManager.MetricsReportCallback.onResult(String metricsConfigName, android.os.PersistableBundle report, byte[] telemetryError, int status) is a nullable collection (`android.os.PersistableBundle`); must be non-null
 NullableCollection: android.car.watchdog.CarWatchdogManager#getResourceOveruseConfigurations(int):
@@ -677,6 +689,14 @@
     If implemented by developer, should follow the on<Something> style; otherwise consider marking final
 OnNameExpected: android.car.content.pm.CarAppBlockingPolicyService#getAppBlockingPolicy():
     Methods implemented by developers should follow the on<Something> style, was `getAppBlockingPolicy`
+OnNameExpected: android.car.oem.OemCarService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.oem.OemCarService#getOemAudioFocusService():
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.oem.OemCarService#getSupportedCarVersion():
+    Methods implemented by developers should follow the on<Something> style, was `getSupportedCarVersion`
+OnNameExpected: android.car.oem.OemCarService#isOemServiceReady():
+    Methods implemented by developers should follow the on<Something> style, was `isOemServiceReady`
 
 
 ParcelConstructor: android.car.content.pm.AppBlockingPackageInfo#AppBlockingPackageInfo(android.os.Parcel):
@@ -791,6 +811,12 @@
     Builder must be final: android.car.hardware.CarPropertyConfig.Builder
 
 
+UseParcelFileDescriptor: android.car.oem.OemCarServiceComponent#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    Must use ParcelFileDescriptor instead of FileDescriptor in parameter fd in android.car.oem.OemCarServiceComponent.dump(java.io.FileDescriptor fd, java.io.PrintWriter writer, String[] args)
+
+
+UserHandle: android.car.CarOccupantZoneManager#assignVisibleUserToOccupantZone(android.car.CarOccupantZoneManager.OccupantZoneInfo, android.os.UserHandle, int):
+    When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
 UserHandle: android.car.admin.CarDevicePolicyManager#removeUser(android.os.UserHandle):
     When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
 UserHandle: android.car.watchdog.CarWatchdogManager#getPackageKillableStatesAsUser(android.os.UserHandle):
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index 0923067..dd7151e 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -312,12 +312,14 @@
     method public android.car.CarVersion get();
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
+    enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_2;
   }
 
   public enum ApiRequirements.PlatformVersion {
     method public android.car.PlatformVersion get();
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
+    enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_2;
   }
 
 }
@@ -1203,6 +1205,31 @@
 
 }
 
+package android.car.oem {
+
+  public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+  }
+
+  public abstract class OemCarService extends android.app.Service {
+    ctor public OemCarService();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @CallSuper public void dump(@Nullable java.io.FileDescriptor, @Nullable java.io.PrintWriter, @Nullable String[]);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @Nullable public android.car.oem.OemCarAudioFocusService getOemAudioFocusService();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public abstract android.car.CarVersion getSupportedCarVersion();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public abstract void onCarServiceReady();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public final int onStartCommand(@Nullable android.content.Intent, int, int);
+  }
+
+  public interface OemCarServiceComponent {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void dump(@Nullable java.io.PrintWriter, @Nullable String[]);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void init();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void onCarServiceReady();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void release();
+  }
+
+}
+
 package android.car.os {
 
   public final class CarPerformanceManager {
@@ -1467,6 +1494,7 @@
 
   public final class CarTestManager {
     ctor public CarTestManager(@NonNull android.car.Car, @NonNull android.os.IBinder);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void startCarService(@NonNull android.os.IBinder);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void stopCarService(@NonNull android.os.IBinder);
   }
diff --git a/car-lib/src/android/car/CarVersion.java b/car-lib/src/android/car/CarVersion.java
index 8723bd3..712c104 100644
--- a/car-lib/src/android/car/CarVersion.java
+++ b/car-lib/src/android/car/CarVersion.java
@@ -54,6 +54,15 @@
         public static final CarVersion TIRAMISU_1 =
                 new CarVersion("TIRAMISU_1", Build.VERSION_CODES.TIRAMISU, 1);
 
+        /**
+         * Helper object for second minor upgrade of Android 13.
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public static final CarVersion TIRAMISU_2 =
+                new CarVersion("TIRAMISU_2", Build.VERSION_CODES.TIRAMISU, 2);
+
         private VERSION_CODES() {
             throw new UnsupportedOperationException("Only provide constants");
         }
diff --git a/car-lib/src/android/car/PlatformVersion.java b/car-lib/src/android/car/PlatformVersion.java
index 6e360fe..9eea3a6 100644
--- a/car-lib/src/android/car/PlatformVersion.java
+++ b/car-lib/src/android/car/PlatformVersion.java
@@ -54,6 +54,15 @@
         public static final PlatformVersion TIRAMISU_1 =
                 new PlatformVersion("TIRAMISU_1", Build.VERSION_CODES.TIRAMISU, 1);
 
+        /**
+         * Helper object for second minor upgrade of Android 13.
+         */
+        @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public static final PlatformVersion TIRAMISU_2 =
+                new PlatformVersion("TIRAMISU_2", Build.VERSION_CODES.TIRAMISU, 2);
+
         private VERSION_CODES() {
             throw new UnsupportedOperationException("Only provide constants");
         }
diff --git a/car-lib/src/android/car/annotation/ApiRequirements.java b/car-lib/src/android/car/annotation/ApiRequirements.java
index f5cfcda..1764ac6 100644
--- a/car-lib/src/android/car/annotation/ApiRequirements.java
+++ b/car-lib/src/android/car/annotation/ApiRequirements.java
@@ -57,7 +57,8 @@
     enum CarVersion {
 
         TIRAMISU_0(android.car.CarVersion.VERSION_CODES.TIRAMISU_0),
-        TIRAMISU_1(android.car.CarVersion.VERSION_CODES.TIRAMISU_1);
+        TIRAMISU_1(android.car.CarVersion.VERSION_CODES.TIRAMISU_1),
+        TIRAMISU_2(android.car.CarVersion.VERSION_CODES.TIRAMISU_2);
 
         private final android.car.CarVersion mVersion;
 
@@ -77,7 +78,8 @@
     enum PlatformVersion {
 
         TIRAMISU_0(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_0),
-        TIRAMISU_1(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_1);
+        TIRAMISU_1(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_1),
+        TIRAMISU_2(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_2);
 
         private final android.car.PlatformVersion mVersion;
 
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index 3320319..0ba250a 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -371,10 +371,10 @@
         if (carPropertyEventCallbackController == null) {
             return;
         }
-        boolean allCallbacksRemoved = carPropertyEventCallbackController.remove(
-                carPropertyEventCallback);
-        if (allCallbacksRemoved) {
-            synchronized (mLock) {
+        synchronized (mLock) {
+            boolean allCallbacksRemoved = carPropertyEventCallbackController.remove(
+                    carPropertyEventCallback);
+            if (allCallbacksRemoved) {
                 mPropertyIdToCarPropertyEventCallbackController.remove(propertyId);
             }
         }
diff --git a/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl b/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl
new file mode 100644
index 0000000..385b84d
--- /dev/null
+++ b/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import android.media.AudioFocusInfo;
+
+/** @hide */
+interface IOemCarAudioFocusService {
+    void audioFocusChanged(in List<AudioFocusInfo> currentFocusHolders,
+           in List<AudioFocusInfo> currentFocusLosers, int zoneId);
+}
diff --git a/car-lib/src/android/car/oem/IOemCarService.aidl b/car-lib/src/android/car/oem/IOemCarService.aidl
new file mode 100644
index 0000000..ffc7125
--- /dev/null
+++ b/car-lib/src/android/car/oem/IOemCarService.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import android.car.CarVersion;
+import android.car.oem.IOemCarAudioFocusService;
+import android.car.oem.IOemCarServiceCallback;
+
+/*
+ * Binder for communicating with OEM Car Service.
+ */
+
+/** @hide */
+interface IOemCarService {
+    // Life cycle methods
+    /*
+     * Called when CarService is ready to take request. OemCarService is initialized before
+     * Car Service is ready. This signals OEM Service that CarService is ready.
+     * OemCarServiceCallback is passed from Car Service to OEM Service. One important call in the
+     * callback is sendOemCarServiceReady() which should be called to inform that OEM service is
+     * ready.
+     */
+    void onCarServiceReady(in IOemCarServiceCallback callback);
+
+    /*
+     * Gets the supported CarVersion for the OEM service. It is possible that CarModule is updated
+     * but OEM service is not updated. CarService needs to be aware of that.
+     */
+    CarVersion getSupportedCarVersion();
+
+    /*
+     * Gets the supported CarVersion for the OEM service. It is possible that CarModule is updated
+     * but OEM service is not updated. CarService needs to be aware of that.
+     */
+    String getAllStackTraces();
+
+    // Component services
+    IOemCarAudioFocusService getOemAudioFocusService();
+}
diff --git a/car-lib/src/android/car/oem/IOemCarServiceCallback.aidl b/car-lib/src/android/car/oem/IOemCarServiceCallback.aidl
new file mode 100644
index 0000000..13a0813
--- /dev/null
+++ b/car-lib/src/android/car/oem/IOemCarServiceCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import android.os.Bundle;
+
+/** @hide */
+interface IOemCarServiceCallback {
+    void sendOemCarServiceReady();
+}
\ No newline at end of file
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusService.java b/car-lib/src/android/car/oem/OemCarAudioFocusService.java
new file mode 100644
index 0000000..2625c42
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.oem;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+import android.media.AudioFocusInfo;
+
+import java.util.List;
+
+/*
+ * OemCarAudioFocusServiceInterface would expose all the method from IOemCarAudioFocusService. It
+ * should always be in sync with IOemCarAudioFocusService. Oem will implement
+ * OemCarAudioFocusServiceInterface which would be used by OemCarAudioFocusService.
+ */
+/**
+ * Interface for Audio focus for OEM Service.
+ *
+ * @hide
+ */
+@SystemApi
+public interface OemCarAudioFocusService extends OemCarServiceComponent {
+    /**
+     * Updates audio focus change. It is one way call for OEM Service.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    void audioFocusChanged(@NonNull List<AudioFocusInfo> currentFocusHolders,
+            @NonNull List<AudioFocusInfo> currentFocusLosers, int zoneId);
+}
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java b/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java
new file mode 100644
index 0000000..0a1f0ee
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.oem;
+
+import android.annotation.NonNull;
+import android.car.annotation.ApiRequirements;
+import android.media.AudioFocusInfo;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * This code will be running as part of the OEM Service. This implements
+ * {@code IOemCarAudioFocusService} as hidden class. It is exposed as IBinder from {@link
+ * OemCarService#getOemAudioFocusService()}
+ *
+ * @hide
+ */
+final class OemCarAudioFocusServiceImpl extends IOemCarAudioFocusService.Stub
+        implements OemCarServiceComponent {
+
+    private final OemCarAudioFocusService mOemCarAudioFocusService;
+
+    OemCarAudioFocusServiceImpl(
+            @NonNull OemCarAudioFocusService oemCarAudioFocusService) {
+        mOemCarAudioFocusService = oemCarAudioFocusService;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void audioFocusChanged(@NonNull List<AudioFocusInfo> currentFocusHolders,
+            @NonNull List<AudioFocusInfo> currentFocusLosers, int zoneId) {
+        mOemCarAudioFocusService.audioFocusChanged(currentFocusHolders, currentFocusLosers,
+                zoneId);
+    }
+
+    @Override
+    public void init() {
+        mOemCarAudioFocusService.init();
+    }
+
+    @Override
+    public void release() {
+        mOemCarAudioFocusService.release();
+    }
+
+    @Override
+    public void dump(PrintWriter writer, String[] args) {
+        mOemCarAudioFocusService.dump(writer, args);
+    }
+
+    @Override
+    public void onCarServiceReady() {
+        mOemCarAudioFocusService.onCarServiceReady();
+    }
+}
diff --git a/car-lib/src/android/car/oem/OemCarService.java b/car-lib/src/android/car/oem/OemCarService.java
new file mode 100644
index 0000000..de62ab6
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarService.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.car.CarVersion;
+import android.car.annotation.ApiRequirements;
+import android.car.builtin.util.Slogf;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Map;
+
+/**
+ * This code will be running as part of the OEM Service. This provides basic implementation for OEM
+ * Service. OEMs should extend this class and override relevant methods.
+ *
+ * <p>
+ * OEM service implementation should have {@code android.car.permission.BIND_OEM_CAR_SERVICE} as
+ * required permission in manifest to connect to the OEM service.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class OemCarService extends Service {
+
+    private static final String TAG = OemCarService.class.getSimpleName();
+    private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+    private static final String PERMISSION_BIND_OEM_CAR_SERVICE =
+            "android.car.permission.BIND_OEM_CAR_SERVICE";
+
+    // OEM Service components
+    // Note: Change the size as more components are added.
+    @GuardedBy("mLock")
+    private final ArrayMap<Class<?>, OemCarServiceComponent> mOemCarServiceComponents =
+            new ArrayMap<Class<?>, OemCarServiceComponent>(1);
+
+    private final Object mLock = new Object();
+
+    private final IOemCarService mInterface = new IOemCarService.Stub() {
+        // Component services
+        @Override
+        public IOemCarAudioFocusService getOemAudioFocusService() {
+            assertPermission();
+            synchronized (mLock) {
+                return (IOemCarAudioFocusService) mOemCarServiceComponents
+                        .getOrDefault(IOemCarAudioFocusService.class, null);
+            }
+        }
+
+        @Override
+        public void onCarServiceReady(IOemCarServiceCallback callback) throws RemoteException {
+            assertPermission();
+            OemCarService.this.onCarServiceReady();
+            synchronized (mLock) {
+                for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+                    if (DBG) {
+                        Slogf.d(TAG, "Calling onCarServiceReady for %s\n",
+                                mOemCarServiceComponents.keyAt(i).getSimpleName());
+                    }
+                    mOemCarServiceComponents.valueAt(i).onCarServiceReady();
+                }
+            }
+            callback.sendOemCarServiceReady();
+        }
+
+        @Override
+        public CarVersion getSupportedCarVersion() {
+            assertPermission();
+            return OemCarService.this.getSupportedCarVersion();
+        }
+
+        @Override
+        public String getAllStackTraces() {
+            assertPermission();
+            Map<Thread, StackTraceElement[]> tracesMap = Thread.getAllStackTraces();
+            StringBuilder sb = new StringBuilder();
+            sb.append("OemService stack trace:\n");
+            int i = 0;
+            for (Map.Entry<Thread, StackTraceElement[]> entry : tracesMap.entrySet()) {
+                sb.append("Thread: ").append(i++).append('\n');
+                StackTraceElement[] stack = entry.getValue();
+                for (int j = 0; j < stack.length; j++) {
+                    sb.append(stack[j].toString()).append('\n');
+                }
+            }
+
+            return sb.toString();
+        }
+
+        private void assertPermission() {
+            if (checkCallingPermission(
+                    PERMISSION_BIND_OEM_CAR_SERVICE) != PackageManager.PERMISSION_GRANTED) {
+                String errorMsg = "Caller with uid:" + Binder.getCallingUid()
+                        + " doesn't have permission " + PERMISSION_BIND_OEM_CAR_SERVICE;
+                Slogf.e(TAG, errorMsg);
+                throw new SecurityException(errorMsg);
+            }
+        }
+    };
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>
+     * OEM should override this method and do the initialization. OEM should also call super after
+     * initialization as this method would call {@link OemCarServiceComponent#init()} for each
+     * component implemented by OEM.
+     *
+     * <p>
+     * Car Service will not be available at the time of this initialization. If the OEM needs
+     * anything from CarService, they should wait for the CarServiceReady() call. It is expected
+     * that most of the initialization will finish in this call.
+     */
+    @Override
+    @CallSuper
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void onCreate() {
+        if (DBG) {
+            Slogf.d(TAG, "OnCreate");
+        }
+
+        // Create all components
+        OemCarAudioFocusService oemCarAudioFocusService = getOemAudioFocusService();
+        synchronized (mLock) {
+            if (oemCarAudioFocusService != null) {
+                mOemCarServiceComponents.put(IOemCarAudioFocusService.class,
+                        new OemCarAudioFocusServiceImpl(oemCarAudioFocusService));
+            }
+
+            // Initialize them
+            for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+                if (DBG) {
+                    Slogf.d(TAG, "Initializing %s\n",
+                            mOemCarServiceComponents.keyAt(i).getSimpleName());
+                }
+                mOemCarServiceComponents.valueAt(i).init();
+            }
+        }
+        super.onCreate();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>
+     * OEM should override this method and do all the resources deallocation. OEM should also call
+     * super after resource deallocation as this method would call
+     * {@link OemCarServiceComponent#release()} for each component implemented by OEM.
+     */
+    @Override
+    @CallSuper
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void onDestroy() {
+        if (DBG) {
+            Slogf.d(TAG, "OnDestroy");
+        }
+
+        // Destroy all components and release the resources
+        synchronized (mLock) {
+            for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+                mOemCarServiceComponents.valueAt(i).release();
+            }
+        }
+
+        super.onDestroy();
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public final int onStartCommand(@Nullable Intent intent, int flags, int startId) {
+        if (DBG) {
+            Slogf.d(TAG, "onStartCommand");
+        }
+        return START_STICKY;
+    }
+
+    @NonNull
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public final IBinder onBind(@Nullable Intent intent) {
+        if (DBG) {
+            Slogf.d(TAG, "onBind");
+        }
+        return mInterface.asBinder();
+    }
+
+    /**
+     * Gets Audio Focus Service implemented by OEM Service.
+     *
+     * @return audio focus service if implemented by OEM service, else return {@code null}.
+     */
+    @Nullable
+    @SuppressWarnings("[OnNameExpected]")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public OemCarAudioFocusService getOemAudioFocusService() {
+        if (DBG) {
+            Slogf.d(TAG, "getOemUserService");
+        }
+        return null;
+    }
+
+    @CallSuper
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void dump(@Nullable FileDescriptor fd, @Nullable PrintWriter writer,
+            @Nullable String[] args) {
+        writer.println("**** Dump OemCarService ****");
+        synchronized (mLock) {
+            for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+                mOemCarServiceComponents.valueAt(i).dump(writer, args);
+            }
+        }
+    }
+
+    /**
+     * Checks the supported CarVersion by the OEM service.
+     */
+    @SuppressWarnings("[OnNameExpected]")
+    @NonNull
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public abstract CarVersion getSupportedCarVersion();
+
+    /**
+     * Informs OEM service that CarService is now ready for communication.
+     *
+     * <p>
+     * OEM should override this method if there is any initialization depending on CarService.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public abstract void onCarServiceReady();
+}
diff --git a/car-lib/src/android/car/oem/OemCarServiceComponent.java b/car-lib/src/android/car/oem/OemCarServiceComponent.java
new file mode 100644
index 0000000..e0e5960
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarServiceComponent.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.oem;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+
+import java.io.PrintWriter;
+
+/**
+ * Contains life cycle methods for the OEM Service.
+ *
+ * <p>This is to enforce structure on the OEM Service components. {link OemCarService} would call
+ * these methods.
+ *
+ * @hide
+ */
+@SystemApi
+@SuppressWarnings("[NotCloseable]")
+public interface OemCarServiceComponent {
+    /**
+     * Initializes required resources.
+     *
+     * <p>This is called for each service component during {@link OemCarService#onCreate()}
+     * call of OemCarService.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    void init();
+
+    /**
+     * Releases required resources.
+     *
+     * <p>This is called for each service component during {@link OemCarService#onDestroy()}
+     * call of OemCarService.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    void release();
+
+    /**
+     * Dumps the service component details.
+     *
+     * <p>Each service component should implement a dump command to dump. It is called from
+     * {@link OemCarService#dump(java.io.FileDescriptor, PrintWriter, String[])} call.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    void dump(@Nullable PrintWriter writer, @Nullable String[] args);
+
+    /**
+     * Informs if CarService is ready.
+     *
+     * <p> Each service component should do the necessary initialization depending on CarService. It
+     * is called from {@link OemCarService#onCarServiceReady()} call.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    void onCarServiceReady();
+}
diff --git a/car-lib/src/android/car/telemetry/telemetry.proto b/car-lib/src/android/car/telemetry/telemetry.proto
index 48b4c77..e384e83 100644
--- a/car-lib/src/android/car/telemetry/telemetry.proto
+++ b/car-lib/src/android/car/telemetry/telemetry.proto
@@ -84,6 +84,7 @@
     // Collects all the app start events with the initial used RSS/CACHE/SWAP memory.
     APP_START_MEMORY_STATE_CAPTURED = 1;
     // Collects memory state of processes in 5-minute buckets (1 memory measurement per bucket).
+    // Consider using PROCESS_MEMORY_SNAPSHOT instead for smaller data size.
     PROCESS_MEMORY_STATE = 2;
     // Collects activity foreground/background transition events.
     ACTIVITY_FOREGROUND_STATE_CHANGED = 3;
@@ -95,6 +96,10 @@
     ANR_OCCURRED = 6;
     // Collects "wtf"-level log events.
     WTF_OCCURRED = 7;
+    // Collects memory snapshot of processes in 5-minute buckets (1 memory measurement per bucket).
+    // It differs from PROCESS_MEMORY_STATE in that the snapshot can be used for leaked memory
+    // detection by tracking anon RSS + swap usage.
+    PROCESS_MEMORY_SNAPSHOT = 8;
   }
 
   // Required.
@@ -127,12 +132,23 @@
   optional OemType oem_type = 2;
 }
 
-// Publisher for device-wide memory statistics.
-// It pulls data from /proc/meminfo every N seconds, where N is the read_interval_sec.
+// Publisher for device-wide memory statistics as well as process memory statistics.
+// It pulls data every N seconds, where N is the read_interval_sec.
+// Only one declaration of MemoryPublisher is allowed across all MetricsConfigs.
+// Performance on a device with 8GB RAM:
+// Collecting device meminfo takes 1-3ms.
+// Collecting process meminfo takes 70ms and up, depending on how many package names are specified.
+// For reference, collecting process memory on 1 process takes ~70ms, and for 10 processes it takes
+// ~200ms.
 message MemoryPublisher {
   // Required.
   // The number of seconds in between each memory snapshot.
   // The smallest acceptable read interval is 1, which means one snapshot per second.
+  // If only device meminfo is collected, i.e., leaving the package_names field as empty, then
+  // one snapshot per second is lightweight enough to be supported.
+  // However, collecting additional process meminfo is an expensive operation and has adverse
+  // system health impact. Client should consider increasing read_interval_sec to reduce the
+  // data collection frequency if package_names field is non-empty.
   optional int32 read_interval_sec = 1;
 
   // Optional.
@@ -145,6 +161,17 @@
   // The maximum number of pending script execution tasks that the MemoryPublisher can produce
   // before the publisher is throttled (rate-limited).
   optional int32 max_pending_tasks = 3;
+
+  // Optional.
+  // The package names to get process memory statistics on. If specified, it will be published
+  // along with device memory.
+  // Important: Specifying package_names will increase the cost of data collection in
+  // MemoryPublisher. So it should be done carefully and only when necessary. Some remedies
+  // include increasing the read_interval_sec to reduce data collection frequency, and to use a
+  // small number for max_pending_tasks to throttle the publisher. Client should remove the
+  // MetricsConfig once enough process memory data has been collected. It is not intended to be
+  // used as continuous monitoring on process memory because it is an expensive call.
+  repeated string package_names = 4;
 }
 
 // Specifies data publisher and its parameters.
diff --git a/car-lib/src/android/car/test/CarTestManager.java b/car-lib/src/android/car/test/CarTestManager.java
index 41a0200..118317c 100644
--- a/car-lib/src/android/car/test/CarTestManager.java
+++ b/car-lib/src/android/car/test/CarTestManager.java
@@ -21,6 +21,7 @@
 import android.car.Car;
 import android.car.CarManagerBase;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -90,4 +91,17 @@
             handleRemoteExceptionFromCarService(e);
         }
     }
+
+    /**
+     * Returns OEM service name.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Car.PERMISSION_CAR_TEST_SERVICE)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public String getOemServiceName() throws RemoteException {
+        return mService.getOemServiceName();
+    }
 }
diff --git a/car-lib/src/android/car/test/ICarTest.aidl b/car-lib/src/android/car/test/ICarTest.aidl
index 90153cd..10388c8 100644
--- a/car-lib/src/android/car/test/ICarTest.aidl
+++ b/car-lib/src/android/car/test/ICarTest.aidl
@@ -31,4 +31,9 @@
 
     /** Re initializes car services that was previously released by #releaseCarService method. */
     void startCarService(IBinder token) = 2;
+
+    /**
+     * Returns OEM service name.
+     */
+    String getOemServiceName() = 3;
 }
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java b/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
index 9be12ec..0bc17c1 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
@@ -118,6 +118,7 @@
         mHandlersList.setOnItemClickListener(mHandlerClickListener);
         mController = new UsbHostController(this, new UsbCallbacks());
         mPackageManager = getPackageManager();
+        hideDialog();
     }
 
     @Override
@@ -150,6 +151,21 @@
         }
     }
 
+    private void hideDialog() {
+        setTheme(android.R.style.Theme_Translucent);
+        if (mUsbHandlersDialog != null) {
+            mUsbHandlersDialog.setVisibility(View.GONE);
+        }
+    }
+
+    private void showDialog() {
+        setTranslucent(false);
+        setTheme(android.R.style.Theme_DeviceDefault_Dialog);
+        if (mUsbHandlersDialog != null) {
+            mUsbHandlersDialog.setVisibility(View.VISIBLE);
+        }
+    }
+
     class UsbCallbacks implements UsbHostController.UsbHostControllerCallbacks {
         private boolean mProcessing = false;
 
@@ -170,7 +186,7 @@
                 @Override
                 public void run() {
                     if (mProcessing && !mListAdapter.isEmpty()) {
-                        mUsbHandlersDialog.setVisibility(View.VISIBLE);
+                        showDialog();
                     }
                 }
             });
@@ -188,7 +204,7 @@
                     @Override
                     public void run() {
                         if (mProcessing) {
-                            mUsbHandlersDialog.setVisibility(View.VISIBLE);
+                            showDialog();
                         }
                         mListAdapter.clear();
                         mListAdapter.addAll(options);
diff --git a/car_product/app_overlays/car-ui-customizations/res/color/car_ui_preference_primary_switch_background_color.xml b/car_product/app_overlays/car-ui-customizations/res/color/car_ui_preference_primary_switch_background_color.xml
new file mode 100644
index 0000000..8e1245a
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/color/car_ui_preference_primary_switch_background_color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="false"
+        android:color="#202124"/>
+    <item android:color="?android:attr/colorAccent"
+        android:alpha="0.24"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_background.xml b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_background.xml
new file mode 100644
index 0000000..a537f00
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:gravity="center">
+        <shape android:shape="rectangle">
+            <corners android:radius="24dp" />
+            <solid android:color="@color/car_ui_preference_primary_switch_background_color" />
+        </shape>
+    </item>
+    <item android:drawable="@drawable/car_ui_preference_primary_switch_rotary_highlight" />
+</layer-list>
\ No newline at end of file
diff --git a/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_rotary_highlight.xml b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_rotary_highlight.xml
new file mode 100644
index 0000000..5cdde96
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_rotary_highlight.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <corners android:radius="24dp" />
+            <solid android:color="#8A94CBFF" />
+            <stroke
+                android:width="4dp"
+                android:color="#94CBFF" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape android:shape="rectangle">
+            <corners android:radius="24dp" />
+            <solid android:color="#3D94CBFF" />
+            <stroke
+                android:width="8dp"
+                android:color="#94CBFF" />
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="?android:attr/colorControlHighlight" />
+    </item>
+</selector>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference.xml
new file mode 100644
index 0000000..17325bd
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<com.android.car.ui.uxr.DrawableStateRelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:clipToPadding="false"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:tag="carUiPreference"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+    <com.android.car.ui.uxr.DrawableStateImageView
+        android:id="@android:id/icon"
+        android:layout_width="44dp"
+        android:layout_height="44dp"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_marginBottom="16dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginTop="16dp"
+        android:scaleType="fitCenter"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:layout_toEndOf="@android:id/icon"
+        android:layout_toStartOf="@android:id/widget_frame"
+        android:orientation="vertical">
+
+        <com.android.car.ui.uxr.DrawableStateTextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="2"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+        <com.android.car.ui.uxr.DrawableStateTextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+
+    </LinearLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <FrameLayout
+        android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"/>
+
+</com.android.car.ui.uxr.DrawableStateRelativeLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_category.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_category.xml
new file mode 100644
index 0000000..717bf4d
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_category.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:focusable="true"
+    android:gravity="center_vertical"
+    android:minHeight="76dp"
+    android:orientation="horizontal"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="44dp"
+        android:layout_height="44dp"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="16dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginTop="16dp"
+        android:scaleType="fitCenter"
+        android:tint="@color/car_ui_preference_icon_color"
+        tools:ignore="UseAppTint" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="viewStart"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceCategoryTitle" />
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_footer.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_footer.xml
new file mode 100644
index 0000000..db9c216
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_footer.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<com.android.car.ui.uxr.DrawableStateLinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="left"
+    android:clipToPadding="false"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingBottom="16dp">
+
+    <com.android.car.ui.uxr.DrawableStateLinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="left"
+        android:orientation="horizontal">
+
+        <com.android.car.ui.uxr.DrawableStateImageView
+            android:id="@android:id/icon"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_marginTop="16dp"
+            android:layout_marginEnd="16dp"
+            android:padding="3dp"
+            android:alpha="72"/>
+
+        <com.android.car.ui.uxr.DrawableStateTextView
+            android:id="@android:id/title"
+            android:textColor="@color/car_ui_text_color_secondary"
+            android:textStyle="bold"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:ellipsize="end"
+            android:maxLines="2"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceCategoryTitle"/>
+    </com.android.car.ui.uxr.DrawableStateLinearLayout>
+
+    <com.android.car.ui.uxr.DrawableStateTextView
+        android:id="@android:id/summary"
+        android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"/>
+
+    <com.android.car.ui.uxr.DrawableStateTextView
+        android:id="@+id/car_ui_link"
+        android:textColor="?android:attr/colorAccent"
+        android:textStyle="bold"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"/>
+</com.android.car.ui.uxr.DrawableStateLinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_primary_switch.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_primary_switch.xml
new file mode 100644
index 0000000..89b78ee
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_primary_switch.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<com.android.car.ui.uxr.DrawableStateRelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/car_ui_preference_primary_switch_background"
+    android:clipToPadding="false"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:tag="carUiPreference"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+    <com.android.car.ui.uxr.DrawableStateImageView
+        android:id="@android:id/icon"
+        android:layout_width="44dp"
+        android:layout_height="44dp"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_marginBottom="16dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginTop="16dp"
+        android:scaleType="fitCenter"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:layout_toEndOf="@android:id/icon"
+        android:layout_toStartOf="@android:id/widget_frame"
+        android:orientation="vertical">
+
+        <com.android.car.ui.uxr.DrawableStateTextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="2"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+        <com.android.car.ui.uxr.DrawableStateTextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+
+    </LinearLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <FrameLayout
+        android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"/>
+
+</com.android.car.ui.uxr.DrawableStateRelativeLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
index f32af91..f8a9e49 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
@@ -59,7 +59,8 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:textAlignment="viewStart"
-                    android:singleLine="true"
+                    android:maxLines="2"
+                    android:ellipsize="end"
                     android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
 
                 <com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
index 1907b85..6f48698 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
@@ -59,7 +59,8 @@
                     android:id="@android:id/title"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:maxLines="2"
                     android:textAlignment="viewStart"
                     android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle" />
 
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
index cde0c0f..3ef880f 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
@@ -59,7 +59,8 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:textAlignment="viewStart"
-                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:maxLines="2"
                     android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
 
                 <com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
index 2084de2..5fdf3d6 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
@@ -59,7 +59,8 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:textAlignment="viewStart"
-                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:maxLines="2"
                     android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
 
                 <com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml
index 9ff3564..54b9ebd 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml
@@ -51,7 +51,8 @@
             android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:singleLine="true"
+            android:ellipsize="end"
+            android:maxLines="2"
             android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
 
         <com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_two_action_preference.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_two_action_preference.xml
new file mode 100644
index 0000000..6f4d992
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_two_action_preference.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@android:color/transparent"
+    android:gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall">
+    <com.android.car.ui.uxr.DrawableStateLinearLayout
+        android:id="@+id/car_ui_preference_container_without_widget"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:background="?android:attr/selectableItemBackground"
+        android:clipToPadding="false"
+        android:gravity="start|center_vertical"
+        android:paddingBottom="16dp"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:paddingTop="16dp">
+        <androidx.preference.internal.PreferenceImageView
+            android:id="@android:id/icon"
+            android:layout_width="44dp"
+            android:layout_height="44dp"
+            android:layout_marginEnd="16dp"/>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:orientation="vertical">
+            <com.android.car.ui.uxr.DrawableStateTextView
+                android:id="@android:id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ellipsize="end"
+                android:maxLines="2"
+                android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+            <com.android.car.ui.uxr.DrawableStateTextView
+                android:id="@android:id/summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+        </LinearLayout>
+    </com.android.car.ui.uxr.DrawableStateLinearLayout>
+    <LinearLayout
+        android:id="@+id/action_widget_container"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent">
+        <View
+            android:layout_width="1dp"
+            android:layout_height="match_parent"
+            android:layout_marginBottom="16dp"
+            android:layout_marginTop="16dp"
+            android:background="#75ffffff"/>
+        <!-- Preference should place its actual preference widget here. -->
+        <com.android.car.ui.uxr.DrawableStateFrameLayout
+            android:id="@android:id/widget_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:background="?android:attr/selectableItemBackground"
+            android:minWidth="?android:attr/listPreferredItemHeightSmall"
+            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+            android:paddingStart="?android:attr/listPreferredItemPaddingStart"/>
+    </LinearLayout>
+</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/values/colors.xml b/car_product/app_overlays/car-ui-customizations/res/values/colors.xml
index 39bb196..e208ec7 100644
--- a/car_product/app_overlays/car-ui-customizations/res/values/colors.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/values/colors.xml
@@ -32,4 +32,6 @@
     <color name="car_ui_seekbar_thumb">#FFFFFF</color>
     <!-- The SeekBar thumb color when disabled. Use for the dark theme. -->
     <color name="car_ui_seekbar_thumb_disabled_on_dark">#757575</color>
+    <!-- The preference category icon color-->
+    <color name="car_ui_preference_icon_color">@color/car_ui_text_color_primary</color>
 </resources>
diff --git a/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml b/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
index 85a6598..4bcbc1f 100644
--- a/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
@@ -64,6 +64,9 @@
     <item target="id/car_ui_second_action_container" value="@id/car_ui_second_action_container" />
     <item target="id/car_ui_secondary_action" value="@id/car_ui_secondary_action" />
     <item target="id/car_ui_secondary_action_concrete" value="@id/car_ui_secondary_action_concrete" />
+    <item target="id/car_ui_link" value="@id/car_ui_link" />
+    <item target="id/car_ui_preference_container_without_widget" value="@id/car_ui_preference_container_without_widget" />
+    <item target="id/action_widget_container" value="@id/action_widget_container" />
     <item target="id/car_ui_toolbar_background" value="@id/car_ui_toolbar_background" />
     <item target="id/car_ui_toolbar_logo" value="@id/car_ui_toolbar_logo" />
     <item target="id/car_ui_toolbar_menu_item_icon_container" value="@id/car_ui_toolbar_menu_item_icon_container"/>
@@ -88,12 +91,17 @@
 
     <item target="layout/car_ui_alert_dialog_list" value="@layout/car_ui_alert_dialog_list"/>
     <item target="layout/car_ui_base_layout_toolbar" value="@layout/car_ui_base_layout_toolbar"/>
+    <item target="layout/car_ui_preference" value="@layout/car_ui_preference"/>
+    <item target="layout/car_ui_preference_category" value="@layout/car_ui_preference_category"/>
+    <item target="layout/car_ui_preference_footer" value="@layout/car_ui_preference_footer"/>
+    <item target="layout/car_ui_preference_primary_switch" value="@layout/car_ui_preference_primary_switch"/>
     <item target="layout/car_ui_preference_two_action_icon" value="@layout/car_ui_preference_two_action_icon"/>
     <item target="layout/car_ui_preference_two_action_switch" value="@layout/car_ui_preference_two_action_switch"/>
     <item target="layout/car_ui_preference_two_action_text" value="@layout/car_ui_preference_two_action_text"/>
     <item target="layout/car_ui_preference_two_action_text_borderless" value="@layout/car_ui_preference_two_action_text_borderless"/>
     <item target="layout/car_ui_preference_widget_switch" value="@layout/car_ui_preference_widget_switch"/>
     <item target="layout/car_ui_preference_widget_seekbar" value="@layout/car_ui_preference_widget_seekbar"/>
+    <item target="layout/car_ui_two_action_preference" value="@layout/car_ui_two_action_preference"/>
     <item target="layout/car_ui_toolbar_menu_item_primary" value="@layout/car_ui_toolbar_menu_item_primary"/>
     <item target="layout/car_ui_toolbar_menu_item" value="@layout/car_ui_toolbar_menu_item"/>
     <item target="layout/car_ui_toolbar_two_row" value="@layout/car_ui_toolbar_two_row"/>
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index 7d5367c..cb25868 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -134,7 +134,7 @@
     ro.android.car.carservice.package?=com.android.car.updatable
 
 # Update with PLATFORM_VERSION_MINOR_INT update
-PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=1
+PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=2
 
 # Automotive specific packages
 PRODUCT_PACKAGES += \
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 8a8fff1..a7fcfde 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -354,6 +354,7 @@
     </install-in-user-type>
     <install-in-user-type package="com.android.permissioncontroller.car.rro">
         <install-in user-type="FULL" />
+        <install-in user-type="PROFILE" />
     </install-in-user-type>
     <install-in-user-type package="com.android.uwb.resources">
         <install-in user-type="FULL" />
@@ -402,5 +403,6 @@
     <install-in-user-type package="com.android.permissioncontroller">
         <install-in user-type="FULL" />
         <install-in user-type="SYSTEM" />
+        <install-in user-type="PROFILE" />
     </install-in-user-type>
 </config>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
index 43a611b..86742c3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
@@ -55,6 +55,7 @@
         <item>com.google.android.car.setupwizard/.welcome.WelcomeActivity</item>
         <item>com.google.android.car.setupwizard/.libs.uicommon.TrampolineActivity</item>
         <item>com.google.android.apps.maps/com.google.android.apps.gmm.car.embedded.auxiliarymap.EmbeddedClusterActivity</item>
+        <item>com.android.mtp/com.android.mtp.ReceiverActivity</item>
     </string-array>
 
     <string name="config_controlBarActivity" translatable="false">
@@ -63,6 +64,9 @@
     <string name="config_notificationCenterActivity" translatable="false">
         com.android.car.notification/.CarNotificationCenterActivity
     </string>
+    <string name="config_homeActivity" translatable="false">
+        com.android.car.carlauncher/.CarLauncher
+    </string>
     <!--  default relaunch will be the first item  -->
     <string-array name="config_backgroundActivities" translatable="false">
         <item>com.google.android.apps.maps/com.google.android.maps.MapsActivity</item>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
index 038de27..a848f99 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
@@ -133,6 +133,7 @@
     private final CarDisplayAreaOrganizer mOrganizer;
     private final CarFullscreenTaskListener mCarFullscreenTaskListener;
     private final ComponentName mControlBarActivityComponent;
+    private final ComponentName mHomeActivityComponent;
     private final CarUiPortraitDisplaySystemBarsController mCarUiDisplaySystemBarsController;
     private final CarDeviceProvisionedController mCarDeviceProvisionedController;
     private final List<ComponentName> mBackgroundActivityComponent;
@@ -179,6 +180,7 @@
     private boolean mIsForegroundAppRequestingImmersiveMode = false;
     private boolean mIsUiModeNight = false;
     private boolean mIsUserSetupInProgress;
+    private DisplayAreaComponent.FOREGROUND_DA_STATE mCurrentForegroundDaState;
     // contains the list of activities that will be displayed on feature {@link
     // CarDisplayAreaOrganizer.FEATURE_VOICE_PLATE)
     private final Set<ComponentName> mVoicePlateActivitySet;
@@ -415,6 +417,8 @@
                         R.string.config_controlBarActivity));
         mNotificationCenterComponent = ComponentName.unflattenFromString(resources.getString(
                 R.string.config_notificationCenterActivity));
+        mHomeActivityComponent = ComponentName.unflattenFromString(resources.getString(
+                R.string.config_homeActivity));
         mBackgroundActivityComponent = new ArrayList<>();
         mVoicePlateActivitySet = new ArraySet<>();
         String[] backgroundActivities = mApplicationContext.getResources().getStringArray(
@@ -815,12 +819,20 @@
 
         boolean isControlBar = componentName.equals(mControlBarActivityComponent);
         boolean isBackgroundApp = mBackgroundActivityComponent.contains(componentName);
+        boolean isHomeActivity = componentName.equals(mHomeActivityComponent);
+
         if (isBackgroundApp) {
             // we don't want to change the state of the foreground DA when background
             // apps are launched.
             return;
         }
 
+        if (isHomeActivity && (mCurrentForegroundDaState != CONTROL_BAR)) {
+            // close the foreground DA
+            startAnimation(CONTROL_BAR);
+            return;
+        }
+
         if (isControlBar) {
             // we don't want to change the state of the foreground DA when
             // controlbar apps are launched.
@@ -844,10 +856,12 @@
         // 3. for the current user ONLY. System user launches some tasks on cluster that should
         //    not affect the state of the foreground DA
         // 4. any task that is manually defined to be ignored
+        // 5. home activity. We use this activity as the wallpaper.
         if (!(taskInfo.displayAreaFeatureId == FEATURE_DEFAULT_TASK_CONTAINER
                 && taskInfo.isVisible()
                 && taskInfo.userId == ActivityManager.getCurrentUser()
-                && !shouldIgnoreOpeningForegroundDA(taskInfo))) {
+                && !shouldIgnoreOpeningForegroundDA(taskInfo)
+                && !isHomeActivity)) {
             return;
         }
 
@@ -1002,6 +1016,7 @@
         // TODO: currently the animations are only bottom/up. Make it more generic animations here.
         int fromPos = 0;
         int toPos = 0;
+        mCurrentForegroundDaState = toState;
 
         switch (toState) {
             case CONTROL_BAR:
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
index a883ed3..8eaad69 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
@@ -26,6 +26,7 @@
 import android.car.app.CarActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
@@ -144,6 +145,12 @@
                             updateForegroundDisplayBounds(wct);
                             updateBackgroundDisplayBounds(wct);
                         }
+                        else if (mToState == DisplayAreaComponent.FOREGROUND_DA_STATE.CONTROL_BAR) {
+                            Intent homeActivityIntent = new Intent(Intent.ACTION_MAIN);
+                            homeActivityIntent.addCategory(Intent.CATEGORY_HOME);
+                            homeActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                            mContext.startActivity(homeActivityIntent);
+                        }
                     }
                 }
 
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
index d14287b..3d47945 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
@@ -34,7 +34,7 @@
  * Dagger Subcomponent for DisplayAreas within SysUI.
  */
 @SysUISingleton
-public class DisplayAreaComponent extends CoreStartable {
+public class DisplayAreaComponent implements CoreStartable {
     public static final String TAG = "DisplayAreaComponent";
     // action name for the intent when to update the foreground DA visibility
     public static final String DISPLAY_AREA_VISIBILITY_CHANGED =
@@ -50,7 +50,6 @@
     @Inject
     public DisplayAreaComponent(Context context,
             CarDisplayAreaController carDisplayAreaController) {
-        super(context);
         mContext = context;
         mCarDisplayAreaController = carDisplayAreaController;
     }
@@ -62,6 +61,23 @@
             // Register the DA's
             mCarDisplayAreaController.register();
 
+            IntentFilter filter = new IntentFilter();
+            // add a receiver to listen to ACTION_BOOT_COMPLETED where we will perform tasks that
+            // require system to be ready. For example, search list of activities with a specific
+            // Intent. This cannot be done while the component is created as that is too early in
+            // the lifecycle of system starting and the results returned by package manager is
+            // not reliable. So we want to wait until system is ready before we query for list of
+            // activities.
+            filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+            mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+                        mCarDisplayAreaController.updateVoicePlateActivityMap();
+                    }
+                }
+            }, filter, /* broadcastPermission= */ null, /* scheduler= */ null);
+
             IntentFilter packageChangeFilter = new IntentFilter();
             // add a receiver to listen to ACTION_PACKAGE_ADDED to perform any action when a new
             // application is installed on the system.
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml
new file mode 100644
index 0000000..0cb41cd
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="?android:attr/colorBackground"
+    android:layoutDirection="ltr"
+    tools:context=".CarLauncher" />
+
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-night/bools.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-night/bools.xml
new file mode 100644
index 0000000..68c681c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-night/bools.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <!-- Specifies that the app theme has a dark background with light text on top -->
+    <bool name="car_ui_is_light_theme">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/bools.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/bools.xml
new file mode 100644
index 0000000..685d2e6
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/bools.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <!-- Specifies that the app theme has a light background with dark text on top -->
+    <bool name="car_ui_is_light_theme">true</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
index 4ae10f2..1c53d75 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
@@ -42,6 +42,7 @@
     <item target="drawable/car_ui_toolbar_menu_item_divider" value="@drawable/car_ui_toolbar_menu_item_divider" />
     <item target="drawable/car_ui_toolbar_menu_item_icon_ripple" value="@drawable/car_ui_toolbar_menu_item_icon_ripple" />
     <item target="bool/car_ui_scrollbar_enable" value="@bool/car_ui_scrollbar_enable" />
+    <item target="bool/car_ui_is_light_theme" value="@bool/car_ui_is_light_theme" />
 
     <item target="style/TextAppearance_CarUi_AlertDialog_Title" value="@style/TextAppearance_CarUi_AlertDialog_Title" />
     <item target="style/TextAppearance_CarUi_AlertDialog_Subtitle" value="@style/TextAppearance_CarUi_AlertDialog_Subtitle" />
diff --git a/cpp/evs/manager/aidl/include/VirtualCamera.h b/cpp/evs/manager/aidl/include/VirtualCamera.h
index 04e64aa..2007215 100644
--- a/cpp/evs/manager/aidl/include/VirtualCamera.h
+++ b/cpp/evs/manager/aidl/include/VirtualCamera.h
@@ -27,6 +27,7 @@
 #include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
 #include <aidl/android/hardware/automotive/evs/ParameterRange.h>
 #include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <android-base/thread_annotations.h>
 
 #include <condition_variable>
 #include <deque>
@@ -78,7 +79,10 @@
     virtual ~VirtualCamera();
 
     unsigned getAllowedBuffers() { return mFramesAllowed; };
-    bool isStreaming() { return mStreamState == RUNNING; }
+    bool isStreaming() {
+        std::lock_guard lock(mMutex);
+        return mStreamState == RUNNING;
+    }
     std::vector<std::shared_ptr<HalCamera>> getHalCameras();
     void setDescriptor(aidlevs::CameraDesc* desc) { mDesc = desc; }
 
@@ -87,7 +91,7 @@
     bool deliverFrame(const aidlevs::BufferDesc& bufDesc);
 
     // Dump current status to a given file descriptor
-    std::string toString(const char* indent = "") const;
+    std::string toString(const char* indent = "") const NO_THREAD_SAFETY_ANALYSIS;
 
 private:
     void shutdown();
@@ -104,7 +108,7 @@
         STOPPED,
         RUNNING,
         STOPPING,
-    } mStreamState = STOPPED;
+    } mStreamState GUARDED_BY(mMutex) = STOPPED;
 
     std::unordered_map<std::string, std::deque<aidlevs::BufferDesc>> mFramesHeld;
     std::thread mCaptureThread;
diff --git a/cpp/evs/manager/aidl/src/VirtualCamera.cpp b/cpp/evs/manager/aidl/src/VirtualCamera.cpp
index e1b2968..7aa6dd1 100644
--- a/cpp/evs/manager/aidl/src/VirtualCamera.cpp
+++ b/cpp/evs/manager/aidl/src/VirtualCamera.cpp
@@ -463,8 +463,16 @@
         constexpr auto kFrameTimeout = 5s;  // timeout in seconds.
         int64_t lastFrameTimestamp = -1;
         EvsResult status = EvsResult::OK;
-        while (mStreamState == RUNNING) {
+        while (true) {
             std::unique_lock lock(mMutex);
+            ::android::base::ScopedLockAssertion assume_lock(mMutex);
+
+            if (mStreamState != RUNNING) {
+                // A video stream is stopped while a capture thread is acquiring
+                // a lock.
+                LOG(DEBUG) << "Requested to stop capturing frames";
+                break;
+            }
 
             unsigned count = 0;
             for (auto&& [key, hwCamera] : mHalCamera) {
@@ -485,7 +493,7 @@
                 break;
             }
 
-            if (!mFramesReadySignal.wait_for(lock, kFrameTimeout, [this]() {
+            if (!mFramesReadySignal.wait_for(lock, kFrameTimeout, [this]() REQUIRES(mMutex) {
                     // Stops waiting if
                     // 1) we've requested to stop capturing
                     //    new frames
@@ -498,35 +506,43 @@
                 LOG(DEBUG) << "Timer for a new frame expires";
                 status = EvsResult::UNDERLYING_SERVICE_ERROR;
                 break;
-            } else if (mStreamState == RUNNING) {
-                // Fetch frames and forward to the client
-                if (!mFramesHeld.empty() && mStream) {
-                    // Pass this buffer through to our client
-                    std::vector<BufferDesc> frames;
-                    frames.resize(count);
-                    unsigned i = 0;
-                    for (auto&& [key, hwCamera] : mHalCamera) {
-                        std::shared_ptr<HalCamera> pHwCamera = hwCamera.lock();
-                        if (!pHwCamera || mFramesHeld[key].empty()) {
-                            continue;
-                        }
+            }
 
-                        // Duplicate the latest buffer and forward it to the
-                        // active clients
-                        auto frame = Utils::dupBufferDesc(mFramesHeld[key].back(),
-                                                          /* doDup= */ true);
-                        if (frame.timestamp > lastFrameTimestamp) {
-                            lastFrameTimestamp = frame.timestamp;
-                        }
-                        frames[i++] = std::move(frame);
-                    }
+            if (mStreamState != RUNNING || !mStream) {
+                // A video stream is stopped while a capture thread is waiting
+                // for a new frame or we have lost a client.
+                LOG(DEBUG) << "Requested to stop capturing frames or lost a client";
+                break;
+            }
 
-                    if (!mStream->deliverFrame(frames).isOk()) {
-                        LOG(WARNING) << "Failed to forward frames";
-                    }
+            // Fetch frames and forward to the client
+            if (mFramesHeld.empty()) {
+                // We do not have any frame to forward.
+                continue;
+            }
+
+            // Pass this buffer through to our client
+            std::vector<BufferDesc> frames;
+            frames.resize(count);
+            unsigned i = 0;
+            for (auto&& [key, hwCamera] : mHalCamera) {
+                std::shared_ptr<HalCamera> pHwCamera = hwCamera.lock();
+                if (!pHwCamera || mFramesHeld[key].empty()) {
+                    continue;
                 }
-            } else if (mStreamState != RUNNING) {
-                LOG(DEBUG) << "Requested to stop capturing frames";
+
+                // Duplicate the latest buffer and forward it to the
+                // active clients
+                auto frame = Utils::dupBufferDesc(mFramesHeld[key].back(),
+                                                  /* doDup= */ true);
+                if (frame.timestamp > lastFrameTimestamp) {
+                    lastFrameTimestamp = frame.timestamp;
+                }
+                frames[i++] = std::move(frame);
+            }
+
+            if (!mStream->deliverFrame(frames).isOk()) {
+                LOG(WARNING) << "Failed to forward frames";
             }
         }
 
@@ -554,6 +570,10 @@
 ScopedAStatus VirtualCamera::stopVideoStream() {
     {
         std::lock_guard lock(mMutex);
+        if (mStreamState != RUNNING) {
+            // No action is required.
+            return ScopedAStatus::ok();
+        }
 
         if (!mStream || mStreamState != RUNNING) {
             // Safely ignore a request to stop video stream
@@ -570,7 +590,7 @@
         EvsEventDesc event{
                 .aType = EvsEventType::STREAM_STOPPED,
         };
-        if (!mStream->notify(std::move(event)).isOk()) {
+        if (mStream && !mStream->notify(std::move(event)).isOk()) {
             LOG(WARNING) << "Error delivering end of stream event";
         }
 
@@ -579,20 +599,20 @@
         // Note, however, that there still might be frames already queued that client will see
         // after returning from the client side of this call.
         mStreamState = STOPPED;
-
-        // Give the underlying hardware camera the heads up that it might be time to stop
-        for (auto&& [_, hwCamera] : mHalCamera) {
-            auto pHwCamera = hwCamera.lock();
-            if (pHwCamera) {
-                pHwCamera->clientStreamEnding(this);
-            }
-        }
-
-        // Signal a condition to unblock a capture thread and then join
-        mSourceCameras.clear();
-        mFramesReadySignal.notify_all();
     }
 
+    // Give the underlying hardware camera the heads up that it might be time to stop
+    for (auto&& [_, hwCamera] : mHalCamera) {
+        auto pHwCamera = hwCamera.lock();
+        if (pHwCamera) {
+            pHwCamera->clientStreamEnding(this);
+        }
+    }
+
+    // Signal a condition to unblock a capture thread and then join
+    mSourceCameras.clear();
+    mFramesReadySignal.notify_all();
+
     if (mCaptureThread.joinable()) {
         mCaptureThread.join();
     }
@@ -740,18 +760,23 @@
 
 bool VirtualCamera::notify(const EvsEventDesc& event) {
     switch (event.aType) {
-        case EvsEventType::STREAM_STOPPED:
-            if (mStreamState != STOPPING) {
+        case EvsEventType::STREAM_STOPPED: {
+            {
+                std::lock_guard lock(mMutex);
+                if (mStreamState != RUNNING) {
+                    // We're not actively consuming a video stream or already in
+                    // a process to stop a video stream.
+                    return true;
+                }
+
                 // Warn if we got an unexpected stream termination
                 LOG(WARNING) << "Stream unexpectedly stopped, current status " << mStreamState;
-
-                // Clean up the resource and forward an event to the client
-                stopVideoStream();
-
-                // This event is handled properly.
-                return true;
             }
-            break;
+
+            // Clean up the resource and forward an event to the client
+            stopVideoStream();
+            return true;
+        }
 
         // v1.0 client will ignore all other events.
         case EvsEventType::PARAMETER_CHANGED:
diff --git a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
index 049b68c..c6746af 100644
--- a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
+++ b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
@@ -237,7 +237,7 @@
       mSilentModeHandler(this),
       mIsPowerPolicyLocked(false),
       mIsCarServiceInOperation(false),
-      mIsFirstConnectionToVhal(false) {
+      mIsFirstConnectionToVhal(true) {
     mMessageHandler = new MessageHandlerImpl(this);
     mDeathRecipient = ScopedAIBinder_DeathRecipient(
             AIBinder_DeathRecipient_new(&CarPowerPolicyServer::onBinderDied));
@@ -713,6 +713,7 @@
         !ret.ok()) {
         ALOGW("Cannot apply the initial power policy(%s): %s", policyId.c_str(),
               ret.error().message().c_str());
+        return;
     }
     ALOGD("Policy(%s) is applied as the initial one", policyId.c_str());
 }
diff --git a/cpp/powerpolicy/server/src/PolicyManager.cpp b/cpp/powerpolicy/server/src/PolicyManager.cpp
index 33a8f80..6100056 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.cpp
+++ b/cpp/powerpolicy/server/src/PolicyManager.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "carpowerpolicyd"
+#define DEBUG false  // STOPSHIP if true.
 
 #include "PolicyManager.h"
 
@@ -66,6 +67,7 @@
 constexpr const char kAttrBehavior[] = "behavior";
 constexpr const char kAttrId[] = "id";
 constexpr const char kAttrState[] = "state";
+constexpr const char kAttrDefaultPolicyGroup[] = "defaultPolicyGroup";
 
 // Power states.
 constexpr const char kPowerStateOn[] = "on";
@@ -324,14 +326,27 @@
     return policyGroup;
 }
 
-Result<std::unordered_map<std::string, PolicyGroup>> readPolicyGroups(
+struct PolicyGroups {
+    std::unordered_map<std::string, PolicyGroup> groups;
+    std::string defaultGroup;
+};
+
+Result<PolicyGroups> readPolicyGroups(
         const XMLElement* pRoot,
         const std::unordered_map<std::string, CarPowerPolicyPtr>& registeredPowerPolicies) {
     const XMLElement* pPolicyGroups = pRoot->FirstChildElement(kTagPolicyGroups);
+
+    PolicyGroups policyGroups;
+
     if (pPolicyGroups == nullptr) {
-        return std::unordered_map<std::string, PolicyGroup>();
+        return policyGroups;
     }
-    std::unordered_map<std::string, PolicyGroup> policyGroups;
+
+    const char* pDefaultPolicyGroupId = nullptr;
+    pPolicyGroups->QueryStringAttribute(kAttrDefaultPolicyGroup, &pDefaultPolicyGroupId);
+    if (pDefaultPolicyGroupId != nullptr) {
+        policyGroups.defaultGroup = pDefaultPolicyGroupId;
+    }
 
     for (const XMLElement* pPolicyGroup = pPolicyGroups->FirstChildElement(kTagPolicyGroup);
          pPolicyGroup != nullptr;
@@ -345,7 +360,7 @@
         if (!policyGroup.ok()) {
             return Error() << policyGroup.error();
         }
-        policyGroups.emplace(policyGroupId, *policyGroup);
+        policyGroups.groups.emplace(policyGroupId, *policyGroup);
     }
     return policyGroups;
 }
@@ -475,10 +490,13 @@
 
 Result<CarPowerPolicyPtr> PolicyManager::getDefaultPowerPolicyForState(
         const std::string& groupId, VehicleApPowerStateReport state) const {
-    if (mPolicyGroups.count(groupId) == 0) {
-        return Error() << StringPrintf("Power policy group(%s) is not available", groupId.c_str());
+    auto groupIdToUse = groupId.empty() ? mDefaultPolicyGroup : groupId;
+
+    if (mPolicyGroups.count(groupIdToUse) == 0) {
+        return Error() << StringPrintf("Power policy group %s is not found", groupIdToUse.c_str());
     }
-    PolicyGroup policyGroup = mPolicyGroups.at(groupId);
+
+    PolicyGroup policyGroup = mPolicyGroups.at(groupIdToUse);
     int32_t key = static_cast<int32_t>(state);
     if (policyGroup.count(key) == 0) {
         return Error() << StringPrintf("Policy for %s is not found", toString(state).c_str());
@@ -572,6 +590,7 @@
     for (auto policy : *registeredPolicies) {
         registeredPoliciesMap.emplace(policy->policyId, policy);
     }
+
     const auto& policyGroups = readPolicyGroups(pRootElement, registeredPoliciesMap);
     if (!policyGroups.ok()) {
         logXmlError(StringPrintf("Reading power policy groups for power state failed: %s",
@@ -587,7 +606,8 @@
 
     mRegisteredPowerPolicies = registeredPoliciesMap;
     initRegularPowerPolicy(/*override=*/false);
-    mPolicyGroups = *policyGroups;
+    mPolicyGroups = policyGroups->groups;
+    mDefaultPolicyGroup = policyGroups->defaultGroup;
     reconstructNoUserInteractionPolicy(*systemPolicyOverrides);
 }
 
@@ -633,6 +653,10 @@
                                                   kSuspendPrepDisabledComponents));
 }
 
+std::string PolicyManager::getDefaultPolicyGroup() const {
+    return mDefaultPolicyGroup;
+}
+
 }  // namespace powerpolicy
 }  // namespace automotive
 }  // namespace frameworks
diff --git a/cpp/powerpolicy/server/src/PolicyManager.h b/cpp/powerpolicy/server/src/PolicyManager.h
index 7c1e7fa..fe5ed50 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.h
+++ b/cpp/powerpolicy/server/src/PolicyManager.h
@@ -48,7 +48,7 @@
 
 constexpr const char kSystemPolicyIdNoUserInteraction[] = "system_power_policy_no_user_interaction";
 constexpr const char kSystemPolicyIdAllOn[] = "system_power_policy_all_on";
-constexpr const char kSystemPolicyIdInitialOn[] = "system_power_policy_initiall_on";
+constexpr const char kSystemPolicyIdInitialOn[] = "system_power_policy_initial_on";
 constexpr const char kSystemPolicyIdSuspendPrep[] = "system_power_policy_suspend_prep";
 
 // Forward declaration for testing use only.
@@ -83,6 +83,7 @@
             const std::string& policyId, const std::vector<std::string>& enabledComponents,
             const std::vector<std::string>& disabledComponents);
     android::base::Result<void> dump(int fd, const android::Vector<String16>& args);
+    std::string getDefaultPolicyGroup() const;
 
 private:
     void initRegularPowerPolicy(bool override);
@@ -95,6 +96,7 @@
     std::unordered_map<std::string, CarPowerPolicyPtr> mRegisteredPowerPolicies;
     std::unordered_map<std::string, CarPowerPolicyPtr> mPreemptivePowerPolicies;
     std::unordered_map<std::string, PolicyGroup> mPolicyGroups;
+    std::string mDefaultPolicyGroup;
 
     // For unit tests.
     friend class internal::PolicyManagerPeer;
diff --git a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
index 40837df..ad61627 100644
--- a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
+++ b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
@@ -33,7 +33,7 @@
 using ::tinyxml2::XML_SUCCESS;
 using ::tinyxml2::XMLDocument;
 
-namespace {
+namespace test {
 
 constexpr const char* kDirPrefix = "/tests/data/";
 
@@ -46,10 +46,15 @@
         "valid_power_policy_policies_only.xml";
 constexpr const char* kValidPowerPolicySystemPowerPolicyOnlyXmlFile =
         "valid_power_policy_system_power_policy_only.xml";
+constexpr const char* kValidPowerPolicyWithDefaultPolicyGroup =
+        "valid_power_policy_default_policy_group.xml";
+constexpr const char* kValidPowerPolicyWithInvalidDefaultPolicyGroup =
+        "invalid_system_power_policy_incorrect_default_power_policy_group_id.xml";
 const std::vector<const char*> kInvalidPowerPolicyXmlFiles =
         {"invalid_power_policy_incorrect_id.xml",
          "invalid_power_policy_incorrect_othercomponent.xml",
-         "invalid_power_policy_incorrect_value.xml", "invalid_power_policy_unknown_component.xml"};
+         "invalid_power_policy_incorrect_value.xml", "invalid_power_policy_unknown_component.xml",
+         "invalid_system_power_policy_incorrect_default_power_policy_group_id.xml"};
 const std::vector<const char*> kInvalidPowerPolicyGroupXmlFiles =
         {"invalid_power_policy_group_incorrect_state.xml",
          "invalid_power_policy_group_missing_policy.xml"};
@@ -69,6 +74,7 @@
 constexpr const char* kSystemPolicyIdInitialOn = "system_power_policy_initial_on";
 constexpr const char* kSystemPolicyIdInitialAllOn = "system_power_policy_all_on";
 constexpr const char* kSystemPolicyIdSuspendPrep = "system_power_policy_suspend_prep";
+constexpr const char* kMixedPolicyGroupName = "mixed_policy_group";
 
 const VehicleApPowerStateReport kExistingTransition = VehicleApPowerStateReport::WAIT_FOR_VHAL;
 const VehicleApPowerStateReport kNonExistingTransition = static_cast<VehicleApPowerStateReport>(-1);
@@ -227,7 +233,7 @@
     ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdInitialAllOn).ok());
 }
 
-}  // namespace
+}  // namespace test
 
 namespace internal {
 
@@ -244,7 +250,7 @@
 private:
     void readXmlFile(const char* filename) {
         XMLDocument xmlDoc;
-        std::string path = getTestDataPath(filename);
+        std::string path = test::getTestDataPath(filename);
         xmlDoc.LoadFile(path.c_str());
         ASSERT_TRUE(xmlDoc.ErrorID() == XML_SUCCESS);
         mManager->readPowerPolicyFromXml(xmlDoc);
@@ -256,6 +262,8 @@
 
 }  // namespace internal
 
+namespace test {
+
 class PolicyManagerTest : public ::testing::Test {};
 
 TEST_F(PolicyManagerTest, TestValidXml_PowerPolicy) {
@@ -344,6 +352,27 @@
     checkSystemPowerPolicy(policyManager, kModifiedSystemPowerPolicy);
 }
 
+TEST_F(PolicyManagerTest, TestValidXml_TestDefaultPowerPolicyGroupId) {
+    PolicyManager policyManager;
+    internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+    policyManagerPeer.expectValidPowerPolicyXML(kValidPowerPolicyWithDefaultPolicyGroup);
+
+    ASSERT_TRUE(policyManager.getDefaultPolicyGroup() == kMixedPolicyGroupName);
+}
+
+TEST_F(PolicyManagerTest, TestValidXml_TestInvalidDefaultPowerPolicyGroupId) {
+    PolicyManager policyManager;
+    internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+    policyManagerPeer.expectValidPowerPolicyXML(kValidPowerPolicyWithInvalidDefaultPolicyGroup);
+
+    ASSERT_EQ(policyManager.getDefaultPolicyGroup(), "");
+
+    ASSERT_FALSE(
+            policyManager
+                    .getDefaultPowerPolicyForState(kInvalidPowerPolicyGroupId, kExistingTransition)
+                    .ok());
+}
+
 TEST_F(PolicyManagerTest, TestDefaultPowerPolicies) {
     PolicyManager policyManager;
     internal::PolicyManagerPeer policyManagerPeer(&policyManager);
@@ -419,6 +448,7 @@
     ASSERT_TRUE(systemPolicyDefault->disabledComponents.empty());
 }
 
+}  // namespace test
 }  // namespace powerpolicy
 }  // namespace automotive
 }  // namespace frameworks
diff --git a/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml b/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
new file mode 100644
index 0000000..4c1b161
--- /dev/null
+++ b/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="someGroup">
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="expected_to_be_registered"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_incorrect_id">
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml b/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml
new file mode 100644
index 0000000..89d1508
--- /dev/null
+++ b/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="mixed_policy_group">
+        <policyGroup id="basic_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <defaultPolicy state="On" id="policy_id_other_untouched"/>
+        </policyGroup>
+        <policyGroup id="no_default_policy_group">
+            <noDefaultPolicy state="WaitForVHAL"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+        <policy id="policy_id_other_off">
+            <otherComponents behavior="off"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_DISPLAY">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_untouched">
+            <otherComponents behavior="untouched"/>
+            <component id="POWER_COMPONENT_AUDIO">on</component>
+            <component id="POWER_COMPONENT_DISPLAY">on</component>
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">on</component>
+        </policy>
+        <policy id="policy_id_other_on">
+            <otherComponents behavior="on"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_none">
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_no_user_interaction">
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl
index 4e0ace2..a26b93f 100644
--- a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl
@@ -37,5 +37,9 @@
   POWER_CYCLE_SHUTDOWN_PREPARE = 0,
   POWER_CYCLE_SHUTDOWN_ENTER = 1,
   POWER_CYCLE_RESUME = 2,
+  /**
+   * @deprecated Value of enum no longer reflects the true amount of power cycles. Enum should not be used.
+   */
   NUM_POWER_CYLES = 3,
+  POWER_CYCLE_SUSPEND_EXIT = 4,
 }
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
index a23fa4e..a2e53c2 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
@@ -38,6 +38,14 @@
 
   /**
    * Number of available power cycles.
+   *
+   * @deprecated Value of enum no longer reflects the true amount of power cycles.
+   *             Enum should not be used.
    */
   NUM_POWER_CYLES,
+
+  /**
+   * The system wakes up from deep sleep or hibernation.
+   */
+  POWER_CYCLE_SUSPEND_EXIT,
 }
diff --git a/cpp/watchdog/sepolicy/public/carwatchdog.te b/cpp/watchdog/sepolicy/public/carwatchdog.te
index fd7ab3b..fa40f68 100644
--- a/cpp/watchdog/sepolicy/public/carwatchdog.te
+++ b/cpp/watchdog/sepolicy/public/carwatchdog.te
@@ -7,3 +7,5 @@
 # Configuration for system_server.
 allow system_server carwatchdogd_service:service_manager find;
 binder_call(carwatchdogd, system_server)
+
+allow carwatchdogd servicemanager:service_manager list;
diff --git a/cpp/watchdog/server/carwatchdogd.rc b/cpp/watchdog/server/carwatchdogd.rc
index 1fd121b..6184541 100644
--- a/cpp/watchdog/server/carwatchdogd.rc
+++ b/cpp/watchdog/server/carwatchdogd.rc
@@ -28,6 +28,7 @@
     # Below durations are in seconds
     setprop ro.carwatchdog.post_system_event_duration 30
     setprop ro.carwatchdog.user_switch_timeout 30
+    setprop ro.carwatchdog.wake_up_event_duration 30
 
 on early-init && property:ro.build.type=eng
     # Below intervals are in seconds
@@ -38,6 +39,7 @@
     # Below durations are in seconds
     setprop ro.carwatchdog.post_system_event_duration 30
     setprop ro.carwatchdog.user_switch_timeout 30
+    setprop ro.carwatchdog.wake_up_event_duration 30
 
 on early-init && property:ro.build.type=user
     # Below intervals are in seconds
@@ -48,6 +50,7 @@
     # Below durations are in seconds
     setprop ro.carwatchdog.post_system_event_duration 30
     setprop ro.carwatchdog.user_switch_timeout 30
+    setprop ro.carwatchdog.wake_up_event_duration 30
 
 on init
     # Number of top stats per category
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.h b/cpp/watchdog/server/src/IoOveruseMonitor.h
index 3a858a8..71fd002 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.h
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.h
@@ -113,6 +113,12 @@
     // Below methods implement DataProcessorInterface.
     std::string name() const override { return "IoOveruseMonitor"; }
     friend std::ostream& operator<<(std::ostream& os, const IoOveruseMonitor& monitor);
+
+    android::base::Result<void> onSystemStartup() {
+        // No tracking of boot-time and wake-up events in I/O overuse monitoring.
+        return {};
+    }
+
     android::base::Result<void> onBoottimeCollection(
             [[maybe_unused]] time_t time,
             [[maybe_unused]] const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
@@ -122,6 +128,15 @@
         return {};
     }
 
+    android::base::Result<void> onWakeUpCollection(
+            [[maybe_unused]] time_t time,
+            [[maybe_unused]] const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+            [[maybe_unused]] const android::wp<ProcStatCollectorInterface>& procStatCollector)
+            override {
+        // No I/O overuse monitoring during wake up.
+        return {};
+    }
+
     android::base::Result<void> onUserSwitchCollection(
             [[maybe_unused]] time_t time, [[maybe_unused]] userid_t from,
             [[maybe_unused]] userid_t to,
diff --git a/cpp/watchdog/server/src/IoPerfCollection.cpp b/cpp/watchdog/server/src/IoPerfCollection.cpp
index a7e26ca..ee333e7 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.cpp
+++ b/cpp/watchdog/server/src/IoPerfCollection.cpp
@@ -53,6 +53,7 @@
 constexpr const char kUserSwitchCollectionTitle[] =
         "%s\nUser-switch events performance report:\n%s\n";
 constexpr const char kUserSwitchCollectionSubtitle[] = "Number of user switch events: %zu\n";
+constexpr const char kWakeUpCollectionTitle[] = "%s\nWake-up performance report:\n%s\n";
 constexpr const char kCustomCollectionTitle[] = "%s\nCustom performance data report:\n%s\n";
 constexpr const char kUserSwitchEventTitle[] = "\nEvent %zu: From: %d To: %d\n%s\n";
 constexpr const char kCollectionTitle[] =
@@ -368,6 +369,10 @@
             .maxCacheSize = periodicCollectionBufferSize,
             .records = {},
     };
+    mWakeUpCollection = {
+            .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+            .records = {},
+    };
     mCustomCollection = {
             .maxCacheSize = std::numeric_limits<std::size_t>::max(),
             .records = {},
@@ -400,6 +405,12 @@
         !WriteStringToFd(mBoottimeCollection.toString(), fd)) {
         return Error(FAILED_TRANSACTION) << "Failed to dump the boot-time collection report.";
     }
+    if (!WriteStringToFd(StringPrintf(kWakeUpCollectionTitle, std::string(75, '-').c_str(),
+                                      std::string(27, '=').c_str()),
+                         fd) ||
+        !WriteStringToFd(mWakeUpCollection.toString(), fd)) {
+        return Error(FAILED_TRANSACTION) << "Failed to dump the wake-up collection report.";
+    }
     if (const auto& result = onUserSwitchCollectionDump(fd); !result.ok()) {
         return result.error();
     }
@@ -433,6 +444,13 @@
     return {};
 }
 
+Result<void> IoPerfCollection::onSystemStartup() {
+    Mutex::Autolock lock(mMutex);
+    mBoottimeCollection.records.clear();
+    mWakeUpCollection.records.clear();
+    return {};
+}
+
 Result<void> IoPerfCollection::onBoottimeCollection(
         time_t time, const wp<UidStatsCollectorInterface>& uidStatsCollector,
         const wp<ProcStatCollectorInterface>& procStatCollector) {
@@ -492,6 +510,20 @@
                          procStatCollectorSp, &mUserSwitchCollections.back());
 }
 
+Result<void> IoPerfCollection::onWakeUpCollection(
+        time_t time, const wp<UidStatsCollectorInterface>& uidStatsCollector,
+        const wp<ProcStatCollectorInterface>& procStatCollector) {
+    const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
+    const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
+    auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
+    if (!result.ok()) {
+        return result;
+    }
+    Mutex::Autolock lock(mMutex);
+    return processLocked(time, std::unordered_set<std::string>(), uidStatsCollectorSp,
+                         procStatCollectorSp, &mWakeUpCollection);
+}
+
 Result<void> IoPerfCollection::onCustomCollection(
         time_t time, [[maybe_unused]] SystemState systemState,
         const std::unordered_set<std::string>& filterPackages,
diff --git a/cpp/watchdog/server/src/IoPerfCollection.h b/cpp/watchdog/server/src/IoPerfCollection.h
index 498413a..2ea8de4 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.h
+++ b/cpp/watchdog/server/src/IoPerfCollection.h
@@ -142,6 +142,7 @@
           mBoottimeCollection({}),
           mPeriodicCollection({}),
           mUserSwitchCollections({}),
+          mWakeUpCollection({}),
           mCustomCollection({}),
           mLastMajorFaults(0) {}
 
@@ -150,10 +151,16 @@
     std::string name() const override { return "IoPerfCollection"; }
 
     // Implements DataProcessorInterface.
+    android::base::Result<void> onSystemStartup() override;
+
     android::base::Result<void> onBoottimeCollection(
             time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
             const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
 
+    android::base::Result<void> onWakeUpCollection(
+            time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+            const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
+
     android::base::Result<void> onPeriodicCollection(
             time_t time, SystemState systemState,
             const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
@@ -221,7 +228,8 @@
     // Makes sure only one collection is running at any given time.
     mutable Mutex mMutex;
 
-    // Info for the boot-time collection event. The cache is persisted until system shutdown/reboot.
+    // Info for the boot-time collection event. The cache is persisted until system shutdown/reboot
+    // or a wake-up collection occurs.
     CollectionInfo mBoottimeCollection GUARDED_BY(mMutex);
 
     // Info for the periodic collection event. The cache size is limited by
@@ -231,6 +239,9 @@
     // Cache for user switch collection events. Events are cached from oldest to newest.
     std::vector<UserSwitchCollectionInfo> mUserSwitchCollections GUARDED_BY(mMutex);
 
+    // Info for the wake-up collection event. Only the latest wake-up collection is cached.
+    CollectionInfo mWakeUpCollection GUARDED_BY(mMutex);
+
     // Info for the custom collection event. The info is cleared at the end of every custom
     // collection.
     CollectionInfo mCustomCollection GUARDED_BY(mMutex);
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 9427322..3c3f2cb 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -170,10 +170,6 @@
     switch (type) {
         case aawi::StateType::POWER_CYCLE: {
             PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
-            if (powerCycle >= PowerCycle::NUM_POWER_CYLES) {
-                return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         StringPrintf("Invalid power cycle %d", powerCycle));
-            }
             return handlePowerCycleChange(powerCycle);
         }
         case aawi::StateType::GARAGE_MODE: {
@@ -212,6 +208,11 @@
         case PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER:
             ALOGI("Received SHUTDOWN_ENTER power cycle");
             mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
+            mWatchdogPerfService->onShutdownEnter();
+            break;
+        case PowerCycle::POWER_CYCLE_SUSPEND_EXIT:
+            ALOGI("Received SUSPEND_EXIT power cycle");
+            mWatchdogPerfService->onSuspendExit();
             break;
         case PowerCycle::POWER_CYCLE_RESUME:
             ALOGI("Received RESUME power cycle");
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.cpp b/cpp/watchdog/server/src/WatchdogPerfService.cpp
index a45dab2..40ed86a 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.cpp
+++ b/cpp/watchdog/server/src/WatchdogPerfService.cpp
@@ -75,7 +75,7 @@
         "behavior is to list the results for the top N packages.\n"
         "%s: Stops custom performance data collection and generates a dump of "
         "the collection report.\n\n"
-        "When no options are specified, the carwatchdog report contains the performance data "
+        "When no options are specified, the car watchdog report contains the performance data "
         "collected during boot-time and over the last few minutes before the report generation.\n";
 
 Result<std::chrono::seconds> parseSecondsFlag(const Vector<String16>& args, size_t pos) {
@@ -104,6 +104,8 @@
                         return "PERIODIC_COLLECTION";
                     case EventType::USER_SWITCH_COLLECTION:
                         return "USER_SWITCH_COLLECTION";
+                    case EventType::WAKE_UP_COLLECTION:
+                        return "WAKE_UP_COLLECTION";
                     case EventType::CUSTOM_COLLECTION:
                         return "CUSTOM_COLLECTION";
                     case EventType::PERIODIC_MONITOR:
@@ -112,6 +114,10 @@
                         return "LAST_EVENT";
                     case SwitchMessage::END_BOOTTIME_COLLECTION:
                         return "END_BOOTTIME_COLLECTION";
+                    case SwitchMessage::END_USER_SWITCH_COLLECTION:
+                        return "END_USER_SWITCH_COLLECTION";
+                    case SwitchMessage::END_WAKE_UP_COLLECTION:
+                        return "END_WAKE_UP_COLLECTION";
                     case SwitchMessage::END_CUSTOM_COLLECTION:
                         return "END_CUSTOM_COLLECTION";
                     default:
@@ -195,6 +201,11 @@
                 .interval = systemEventCollectionInterval,
                 .lastUptime = 0,
         }};
+        mWakeUpCollection = {
+                .eventType = EventType::WAKE_UP_COLLECTION,
+                .interval = systemEventCollectionInterval,
+                .lastUptime = 0,
+        };
         mPeriodicMonitor = {
                 .eventType = EventType::PERIODIC_MONITOR,
                 .interval = periodicMonitorInterval,
@@ -219,6 +230,7 @@
                       toString(mCurrCollectionEvent), toString(expected));
                 return;
             }
+            notifySystemStartUpLocked();
             mCurrCollectionEvent = EventType::BOOT_TIME_COLLECTION;
             mBoottimeCollection.lastUptime = mHandlerLooper->now();
             mHandlerLooper->setLooper(Looper::prepare(/*opts=*/0));
@@ -253,7 +265,7 @@
             ALOGE("%s was terminated already", kServiceName);
             return;
         }
-        ALOGE("Terminating %s as carwatchdog is terminating", kServiceName);
+        ALOGE("Terminating %s as car watchdog is terminating", kServiceName);
         if (mCurrCollectionEvent != EventType::INIT) {
             /*
              * Looper runs only after EventType::INIT has completed so remove looper messages
@@ -309,7 +321,10 @@
 
 Result<void> WatchdogPerfService::onUserStateChange(userid_t userId, const UserState& userState) {
     Mutex::Autolock lock(mMutex);
-    if (mCurrCollectionEvent == EventType::BOOT_TIME_COLLECTION) {
+    if (mCurrCollectionEvent == EventType::BOOT_TIME_COLLECTION ||
+        mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
+        // Ignoring the user switch events because the boot-time and custom collections take
+        // precedence over other collections.
         return {};
     }
     switch (static_cast<int>(userState)) {
@@ -389,6 +404,44 @@
     return {};
 }
 
+Result<void> WatchdogPerfService::onSuspendExit() {
+    Mutex::Autolock lock(mMutex);
+    if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
+        // Ignoring the suspend exit event because the custom collection takes
+        // precedence over other collections.
+        ALOGE("Unable to start %s. Current performance data collection event: %s",
+              toString(EventType::WAKE_UP_COLLECTION), toString(mCurrCollectionEvent));
+        return {};
+    }
+    if (mCurrCollectionEvent == EventType::WAKE_UP_COLLECTION) {
+        ALOGE("The current performance data collection event is already %s",
+              toString(EventType::WAKE_UP_COLLECTION));
+        return {};
+    }
+    notifySystemStartUpLocked();
+    auto thiz = sp<WatchdogPerfService>::fromExisting(this);
+    mHandlerLooper->removeMessages(thiz);
+    mWakeUpCollection.lastUptime = mHandlerLooper->now();
+    nsecs_t uptime = mHandlerLooper->now() + mWakeUpDurationNs.count();
+    mHandlerLooper->sendMessageAtTime(uptime, thiz, SwitchMessage::END_WAKE_UP_COLLECTION);
+    mCurrCollectionEvent = EventType::WAKE_UP_COLLECTION;
+    mHandlerLooper->sendMessage(thiz, EventType::WAKE_UP_COLLECTION);
+    ALOGI("Switching to %s", toString(mCurrCollectionEvent));
+    return {};
+}
+
+Result<void> WatchdogPerfService::onShutdownEnter() {
+    Mutex::Autolock lock(mMutex);
+    if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
+        ALOGI("Unable to switch to %s during shutdown enter. Current performance data collection "
+              "event: %s",
+              toString(EventType::PERIODIC_COLLECTION), toString(mCurrCollectionEvent));
+        return {};
+    }
+    switchToPeriodicLocked(/*startNow=*/true);
+    return {};
+}
+
 Result<void> WatchdogPerfService::onCustomCollection(int fd, const Vector<String16>& args) {
     if (args.empty()) {
         return Error(BAD_VALUE) << "No custom collection dump arguments";
@@ -483,6 +536,10 @@
                                       kDumpMajorDelimiter.c_str(), std::string(33, '=').c_str()),
                          fd) ||
         !WriteStringToFd(mBoottimeCollection.toString(), fd) ||
+        !WriteStringToFd(StringPrintf("\nWake-up collection information:\n%s\n",
+                                      std::string(31, '=').c_str()),
+                         fd) ||
+        !WriteStringToFd(mWakeUpCollection.toString(), fd) ||
         !WriteStringToFd(StringPrintf("\nUser-switch collection information:\n%s\n",
                                       std::string(35, '=').c_str()),
                          fd) ||
@@ -603,28 +660,33 @@
     return {};
 }
 
+void WatchdogPerfService::switchToPeriodicLocked(bool startNow) {
+    if (mCurrCollectionEvent == EventType::PERIODIC_COLLECTION) {
+        ALOGW("The current performance data collection event is already %s",
+              toString(mCurrCollectionEvent));
+        return;
+    }
+    auto thiz = sp<WatchdogPerfService>::fromExisting(this);
+    mHandlerLooper->removeMessages(thiz);
+    mCurrCollectionEvent = EventType::PERIODIC_COLLECTION;
+    mPeriodicCollection.lastUptime = mHandlerLooper->now();
+    if (startNow) {
+        mHandlerLooper->sendMessage(thiz, EventType::PERIODIC_COLLECTION);
+    } else {
+        mPeriodicCollection.lastUptime += mPeriodicCollection.interval.count();
+        mHandlerLooper->sendMessageAtTime(mPeriodicCollection.lastUptime, thiz,
+                                          EventType::PERIODIC_COLLECTION);
+    }
+    mPeriodicMonitor.lastUptime = mHandlerLooper->now() + mPeriodicMonitor.interval.count();
+    mHandlerLooper->sendMessageAtTime(mPeriodicMonitor.lastUptime, thiz,
+                                      EventType::PERIODIC_MONITOR);
+    ALOGI("Switching to %s and %s", toString(mCurrCollectionEvent),
+          toString(EventType::PERIODIC_MONITOR));
+}
+
 void WatchdogPerfService::handleMessage(const Message& message) {
     Result<void> result;
 
-    auto switchToPeriodicLocked = [&](bool startNow) {
-        auto thiz = sp<WatchdogPerfService>::fromExisting(this);
-        mHandlerLooper->removeMessages(thiz);
-        mCurrCollectionEvent = EventType::PERIODIC_COLLECTION;
-        mPeriodicCollection.lastUptime = mHandlerLooper->now();
-        if (startNow) {
-            mHandlerLooper->sendMessage(thiz, EventType::PERIODIC_COLLECTION);
-        } else {
-            mPeriodicCollection.lastUptime += mPeriodicCollection.interval.count();
-            mHandlerLooper->sendMessageAtTime(mPeriodicCollection.lastUptime, thiz,
-                                              EventType::PERIODIC_COLLECTION);
-        }
-        mPeriodicMonitor.lastUptime = mHandlerLooper->now() + mPeriodicMonitor.interval.count();
-        mHandlerLooper->sendMessageAtTime(mPeriodicMonitor.lastUptime, thiz,
-                                          EventType::PERIODIC_MONITOR);
-        ALOGI("Switching to %s and %s", toString(mCurrCollectionEvent),
-              toString(EventType::PERIODIC_MONITOR));
-    };
-
     switch (message.what) {
         case static_cast<int>(EventType::BOOT_TIME_COLLECTION):
             result = processCollectionEvent(&mBoottimeCollection);
@@ -642,13 +704,22 @@
         case static_cast<int>(EventType::USER_SWITCH_COLLECTION):
             result = processCollectionEvent(&mUserSwitchCollection);
             break;
+        case static_cast<int>(EventType::WAKE_UP_COLLECTION):
+            result = processCollectionEvent(&mWakeUpCollection);
+            break;
         case static_cast<int>(SwitchMessage::END_USER_SWITCH_COLLECTION):
+        case static_cast<int>(SwitchMessage::END_WAKE_UP_COLLECTION): {
             mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
-            if (result = processCollectionEvent(&mUserSwitchCollection); result.ok()) {
+            EventMetadata* eventMetadata =
+                    message.what == static_cast<int>(SwitchMessage::END_USER_SWITCH_COLLECTION)
+                    ? &mUserSwitchCollection
+                    : &mWakeUpCollection;
+            if (result = processCollectionEvent(eventMetadata); result.ok()) {
                 Mutex::Autolock lock(mMutex);
                 switchToPeriodicLocked(/*startNow=*/false);
             }
             break;
+        }
         case static_cast<int>(EventType::CUSTOM_COLLECTION):
             result = processCollectionEvent(&mCustomCollection);
             break;
@@ -764,6 +835,9 @@
                                                            mUidStatsCollector, mProcStatCollector);
                 break;
             }
+            case EventType::WAKE_UP_COLLECTION:
+                result = processor->onWakeUpCollection(now, mUidStatsCollector, mProcStatCollector);
+                break;
             case EventType::CUSTOM_COLLECTION:
                 result = processor->onCustomCollection(now, mSystemState, metadata->filterPackages,
                                                        mUidStatsCollector, mProcStatCollector);
@@ -846,6 +920,16 @@
     return {};
 }
 
+Result<void> WatchdogPerfService::notifySystemStartUpLocked() {
+    for (const auto& processor : mDataProcessors) {
+        if (const auto result = processor->onSystemStartup(); !result.ok()) {
+            ALOGE("%s failed to process system startup event", processor->name().c_str());
+            return Error() << processor->name() << " failed to process system startup event";
+        }
+    }
+    return {};
+}
+
 WatchdogPerfService::EventMetadata* WatchdogPerfService::currCollectionMetadataLocked() {
     switch (mCurrCollectionEvent) {
         case EventType::BOOT_TIME_COLLECTION:
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.h b/cpp/watchdog/server/src/WatchdogPerfService.h
index 3f412f8..9302611 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.h
+++ b/cpp/watchdog/server/src/WatchdogPerfService.h
@@ -55,6 +55,7 @@
 }  // namespace internal
 
 constexpr std::chrono::seconds kDefaultPostSystemEventDurationSec = 30s;
+constexpr std::chrono::seconds kDefaultWakeUpEventDurationSec = 30s;
 constexpr std::chrono::seconds kDefaultUserSwitchTimeoutSec = 30s;
 constexpr const char* kStartCustomCollectionFlag = "--start_perf";
 constexpr const char* kEndCustomCollectionFlag = "--stop_perf";
@@ -81,10 +82,17 @@
     virtual android::base::Result<void> init() = 0;
     // Callback to terminate the data processor.
     virtual void terminate() = 0;
+    // Callback to perform actions (such as clearing stats from previous system startup events)
+    // before starting boot-time or wake-up collections.
+    virtual android::base::Result<void> onSystemStartup() = 0;
     // Callback to process the data collected during boot-time.
     virtual android::base::Result<void> onBoottimeCollection(
             time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
             const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
+    // Callback to process the data collected during a wake-up event.
+    virtual android::base::Result<void> onWakeUpCollection(
+            time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+            const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
     // Callback to process the data collected periodically post boot complete.
     virtual android::base::Result<void> onPeriodicCollection(
             time_t time, SystemState systemState,
@@ -95,6 +103,7 @@
             time_t time, userid_t from, userid_t to,
             const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
             const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
+
     /**
      * Callback to process the data collected on custom collection and filter the results only to
      * the specified |filterPackages|.
@@ -128,6 +137,7 @@
     BOOT_TIME_COLLECTION,
     PERIODIC_COLLECTION,
     USER_SWITCH_COLLECTION,
+    WAKE_UP_COLLECTION,
     CUSTOM_COLLECTION,
 
     // Monitor event.
@@ -150,6 +160,12 @@
     END_USER_SWITCH_COLLECTION,
 
     /**
+     * On receiving this message, collect the last wake up record and start periodic collection and
+     * monitor.
+     */
+    END_WAKE_UP_COLLECTION,
+
+    /**
      * On receiving this message, ends custom collection, discard collected data and start periodic
      * collection and monitor.
      */
@@ -157,9 +173,9 @@
 };
 
 /**
- * WatchdogPerfServiceInterface collects performance data during boot-time and periodically post
- * boot complete. It exposes APIs that the main thread and binder service can call to start a
- * collection, switch the collection type, and generate collection dumps.
+ * WatchdogPerfServiceInterface collects performance data during boot-time, user switch, system wake
+ * up and periodically post system events. It exposes APIs that the main thread and binder service
+ * can call to start a collection, switch the collection type, and generate collection dumps.
  */
 class WatchdogPerfServiceInterface : public MessageHandler {
 public:
@@ -182,6 +198,10 @@
     virtual android::base::Result<void> onUserStateChange(
             userid_t userId,
             const android::automotive::watchdog::internal::UserState& userState) = 0;
+    // Starts wake-up collection. Any running collection is stopped, except for custom collections.
+    virtual android::base::Result<void> onSuspendExit() = 0;
+    // Called on shutdown enter, suspend enter and hibernation enter.
+    virtual android::base::Result<void> onShutdownEnter() = 0;
 
     /**
      * Depending on the arguments, it either:
@@ -203,6 +223,9 @@
           mPostSystemEventDurationNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
                   std::chrono::seconds(sysprop::postSystemEventDuration().value_or(
                           kDefaultPostSystemEventDurationSec.count())))),
+          mWakeUpDurationNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
+                  std::chrono::seconds(sysprop::wakeUpEventDuration().value_or(
+                          kDefaultWakeUpEventDurationSec.count())))),
           mUserSwitchTimeoutNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
                   std::chrono::seconds(sysprop::userSwitchTimeout().value_or(
                           kDefaultUserSwitchTimeoutSec.count())))),
@@ -234,6 +257,10 @@
             userid_t userId,
             const android::automotive::watchdog::internal::UserState& userState) override;
 
+    android::base::Result<void> onSuspendExit() override;
+
+    android::base::Result<void> onShutdownEnter() override;
+
     android::base::Result<void> onCustomCollection(int fd,
                                                    const Vector<android::String16>& args) override;
 
@@ -290,6 +317,9 @@
     // Start a user switch collection.
     android::base::Result<void> startUserSwitchCollection();
 
+    // Switch to periodic collection and periodic monitor.
+    void switchToPeriodicLocked(bool startNow);
+
     // Handles the messages received by the lopper.
     void handleMessage(const Message& message) override;
 
@@ -302,6 +332,11 @@
     // Processes the monitor events received by |handleMessage|.
     android::base::Result<void> processMonitorEvent(EventMetadata* metadata);
 
+    // Notifies all registered data processors that either boot-time or wake-up collection will
+    // start. Individual implementations of data processors may clear stats collected during
+    // previous system startup events.
+    android::base::Result<void> notifySystemStartUpLocked();
+
     /**
      * Returns the metadata for the current collection based on |mCurrCollectionEvent|. Returns
      * nullptr on invalid collection event.
@@ -311,6 +346,9 @@
     // Duration to extend a system event collection after the final signal is received.
     std::chrono::nanoseconds mPostSystemEventDurationNs;
 
+    // Duration of the wake-up collection event.
+    std::chrono::nanoseconds mWakeUpDurationNs;
+
     // Timeout duration for user switch collection in case final signal isn't received.
     std::chrono::nanoseconds mUserSwitchTimeoutNs;
 
@@ -335,6 +373,9 @@
     // Info for the |EventType::USER_SWITCH_COLLECTION| collection event.
     UserSwitchEventMetadata mUserSwitchCollection GUARDED_BY(mMutex);
 
+    // Info for the |EventType::WAKE_UP_COLLECTION| collection event.
+    EventMetadata mWakeUpCollection GUARDED_BY(mMutex);
+
     // Info for the |EventType::CUSTOM_COLLECTION| collection event. The info is cleared at the end
     // of every custom collection.
     EventMetadata mCustomCollection GUARDED_BY(mMutex);
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp
index 9c785b4..28e77a9 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.cpp
+++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp
@@ -34,6 +34,7 @@
 #include <android/automotive/watchdog/internal/BnCarWatchdogServiceForSystem.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 #include <hidl/HidlTransportSupport.h>
 #include <utils/SystemClock.h>
 
@@ -90,6 +91,7 @@
 // TimeoutLength::TIMEOUT_NORMAL.
 const int32_t MSG_VHAL_WATCHDOG_ALIVE = static_cast<int>(TimeoutLength::TIMEOUT_NORMAL) + 1;
 const int32_t MSG_VHAL_HEALTH_CHECK = MSG_VHAL_WATCHDOG_ALIVE + 1;
+const int32_t MSG_CACHE_VHAL_PROCESS_IDENTIFIER = MSG_VHAL_HEALTH_CHECK + 1;
 
 // VHAL is supposed to send heart beat every 3s. Car watchdog checks if there is the latest heart
 // beat from VHAL within 3s, allowing 1s marginal time.
@@ -103,7 +105,9 @@
 constexpr const char kPropertyVhalCheckInterval[] = "ro.carwatchdog.vhal_healthcheck.interval";
 constexpr const char kPropertyClientCheckInterval[] = "ro.carwatchdog.client_healthcheck.interval";
 constexpr const char kServiceName[] = "WatchdogProcessService";
-constexpr const char kVhalInterfaceName[] = "android.hardware.automotive.vehicle@2.0::IVehicle";
+constexpr const char kHidlVhalInterfaceName[] = "android.hardware.automotive.vehicle@2.0::IVehicle";
+constexpr const char kAidlVhalInterfaceName[] =
+        "android.hardware.automotive.vehicle.IVehicle/default";
 
 std::string toPidString(const std::vector<ProcessIdentifier>& processIdentifiers) {
     size_t size = processIdentifiers.size();
@@ -133,6 +137,42 @@
     return pidStat->startTimeMillis;
 }
 
+Result<pid_t> queryHidlServiceManagerForVhalPid() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    pid_t pid = -1;
+    Return<void> ret = IServiceManager::getService()->debugDump([&](auto& hals) {
+        for (const auto& info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+            if (info.interfaceName == kHidlVhalInterfaceName) {
+                pid = info.pid;
+                return;
+            }
+        }
+    });
+
+    if (!ret.isOk()) {
+        return Error() << "Failed to get VHAL process id from HIDL service manager";
+    }
+    if (pid == -1) {
+        return Error() << "No VHAL service registered to HIDL service manager";
+    }
+    return pid;
+}
+
+Result<pid_t> queryAidlServiceManagerForVhalPid() {
+    using ServiceDebugInfo = android::IServiceManager::ServiceDebugInfo;
+    std::vector<ServiceDebugInfo> serviceDebugInfos =
+            defaultServiceManager()->getServiceDebugInfo();
+    for (const auto& serviceDebugInfo : serviceDebugInfos) {
+        if (serviceDebugInfo.name == kAidlVhalInterfaceName) {
+            return serviceDebugInfo.pid;
+        }
+    }
+    return Error() << "No VHAL service registered to AIDL service manager";
+}
+
 }  // namespace
 
 WatchdogProcessService::WatchdogProcessService(const sp<Looper>& handlerLooper) :
@@ -312,7 +352,7 @@
         status = tellClientAliveLocked(BnCarWatchdogServiceForSystem::asBinder(service), sessionId);
     }
     if (status.isOk()) {
-        dumpAndKillAllProcesses(clientsNotResponding, true);
+        dumpAndKillAllProcesses(clientsNotResponding, /*reportToVhal=*/true);
     }
     return status;
 }
@@ -403,6 +443,13 @@
     WriteStringToFd(StringPrintf("%sVHAL health check interval: %lldms\n", indent,
                                  mVhalHealthCheckWindowMs.count()),
                     fd);
+    if (mVhalProcessIdentifier.has_value()) {
+        WriteStringToFd(StringPrintf("%sVHAL process identifier (PID = %d, Start time millis = "
+                                     "%" PRIi64 ")",
+                                     indent, mVhalProcessIdentifier->pid,
+                                     mVhalProcessIdentifier->startTimeMillis),
+                        fd);
+    }
     return {};
 }
 
@@ -658,7 +705,7 @@
     for (const ClientInfo*& clientInfo : clientsToNotify) {
         clientInfo->prepareProcessTermination();
     }
-    return dumpAndKillAllProcesses(processIdentifiers, true);
+    return dumpAndKillAllProcesses(processIdentifiers, /*reportToVhal=*/true);
 }
 
 Result<void> WatchdogProcessService::dumpAndKillAllProcesses(
@@ -868,6 +915,36 @@
     std::chrono::nanoseconds intervalNs = mVhalHealthCheckWindowMs + kHealthCheckDelayMs;
     mHandlerLooper->sendMessageDelayed(intervalNs.count(), mMessageHandler,
                                        Message(MSG_VHAL_HEALTH_CHECK));
+    // VHAL process identifier is required only when termiating the VHAL process. VHAL process is
+    // terminated only when the VHAL is unhealthy. However, caching the process identifier as soon
+    // as connecting to VHAL guarantees the correct PID is cached. Because the VHAL pid is queried
+    // from the service manager, the caching should be performed outside the class level lock. So,
+    // handle the caching in the handler thread after successfully subscribing to the VHAL_HEARTBEAT
+    // property.
+    mHandlerLooper->sendMessage(mMessageHandler, Message(MSG_CACHE_VHAL_PROCESS_IDENTIFIER));
+    return;
+}
+
+bool WatchdogProcessService::cacheVhalProcessIdentifier() {
+    pid_t pid = -1;
+    if (Result<pid_t> hidlResult = queryHidlServiceManagerForVhalPid(); hidlResult.ok()) {
+        pid = *hidlResult;
+        ALOGI("Fetched HIDL VHAL PID %d", pid);
+    } else if (Result<pid_t> aidlResult = queryAidlServiceManagerForVhalPid(); aidlResult.ok()) {
+        pid = *aidlResult;
+        ALOGI("Fetched AIDL VHAL PID %d", pid);
+    } else {
+        ALOGE("Failed to fetch VHAL pid:\n\t%s\n\t%s", hidlResult.error().message().c_str(),
+              aidlResult.error().message().c_str());
+        return false;
+    }
+    ProcessIdentifier processIdentifier;
+    processIdentifier.pid = pid;
+    processIdentifier.startTimeMillis = mGetStartTimeForPidFunc(pid);
+
+    Mutex::Autolock lock(mMutex);
+    mVhalProcessIdentifier = processIdentifier;
+    return true;
 }
 
 int32_t WatchdogProcessService::getNewSessionId() {
@@ -916,34 +993,25 @@
 }
 
 void WatchdogProcessService::terminateVhal() {
-    using android::hidl::manager::V1_0::IServiceManager;
-
-    std::vector<ProcessIdentifier> processIdentifiers;
-    sp<IServiceManager> manager = IServiceManager::getService();
-    Return<void> ret = manager->debugDump([&](auto& hals) {
-        for (const auto& info : hals) {
-            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
-                continue;
-            }
-            // TODO(b/216735836): terminate AIDL VHAL.
-            if (info.interfaceName == kVhalInterfaceName) {
-                ProcessIdentifier processIdentifier;
-                processIdentifier.pid = info.pid;
-                processIdentifier.startTimeMillis = mGetStartTimeForPidFunc(info.pid);
-                processIdentifiers.push_back(processIdentifier);
-                break;
-            }
+    auto maybeDumpAndKillVhalProcess = [&]() -> bool {
+        std::optional<ProcessIdentifier> processIdentifier;
+        {
+            Mutex::Autolock lock(mMutex);
+            processIdentifier = mVhalProcessIdentifier;
         }
-    });
-
-    if (!ret.isOk()) {
-        ALOGE("Failed to terminate VHAL: could not get VHAL process id");
-        return;
-    } else if (processIdentifiers.empty()) {
-        ALOGE("Failed to terminate VHAL: VHAL is not running");
+        if (!processIdentifier.has_value()) {
+            return false;
+        }
+        dumpAndKillAllProcesses(std::vector<ProcessIdentifier>(1, *processIdentifier),
+                                /*reportToVhal=*/false);
+        return true;
+    };
+    if (maybeDumpAndKillVhalProcess()) {
         return;
     }
-    dumpAndKillAllProcesses(processIdentifiers, false);
+    if (!cacheVhalProcessIdentifier() || !maybeDumpAndKillVhalProcess()) {
+        ALOGE("Failed to termitate VHAL: failed to fetch VHAL PID");
+    }
 }
 
 std::chrono::nanoseconds WatchdogProcessService::getTimeoutDurationNs(
@@ -1066,6 +1134,9 @@
         case MSG_VHAL_HEALTH_CHECK:
             mService->checkVhalHealth();
             break;
+        case MSG_CACHE_VHAL_PROCESS_IDENTIFIER:
+            mService->cacheVhalProcessIdentifier();
+            break;
         default:
             ALOGW("Unknown message: %d", message.what);
     }
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.h b/cpp/watchdog/server/src/WatchdogProcessService.h
index 1bb8efe..c0bf3bf 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.h
+++ b/cpp/watchdog/server/src/WatchdogProcessService.h
@@ -37,6 +37,7 @@
 #include <IVhalClient.h>
 #include <VehicleHalTypes.h>
 
+#include <optional>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
@@ -249,6 +250,7 @@
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
     android::base::Result<void> connectToVhalLocked();
     void subscribeToVhalHeartBeatLocked();
+    bool cacheVhalProcessIdentifier();
     void reportWatchdogAliveToVhal();
     void reportTerminatedProcessToVhal(
             const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&
@@ -296,6 +298,8 @@
     bool mIsEnabled GUARDED_BY(mMutex);
     std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient> mVhalService
             GUARDED_BY(mMutex);
+    std::optional<android::automotive::watchdog::internal::ProcessIdentifier> mVhalProcessIdentifier
+            GUARDED_BY(mMutex);
     HeartBeat mVhalHeartBeat GUARDED_BY(mMutex);
     android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper GUARDED_BY(mMutex);
     android::sp<BinderDeathRecipient> mBinderDeathRecipient GUARDED_BY(mMutex);
diff --git a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
index 20f3b14..db67e79 100644
--- a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
+++ b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
@@ -42,6 +42,15 @@
     prop_name: "ro.carwatchdog.post_system_event_duration"
 }
 
+# Duration in seconds of data collection for a system wake up event.
+prop {
+    api_name: "wakeUpEventDuration"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.carwatchdog.wake_up_event_duration"
+}
+
 # Maximum number of periodically collected records to be cached in memory.
 prop {
     api_name: "periodicCollectionBufferSize"
diff --git a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
index da8cfe1..e93849c 100644
--- a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
+++ b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
@@ -19,6 +19,12 @@
     prop_name: "ro.carwatchdog.post_system_event_duration"
   }
   prop {
+    api_name: "wakeUpEventDuration"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.wake_up_event_duration"
+  }
+  prop {
     api_name: "periodicCollectionBufferSize"
     type: Integer
     scope: Internal
diff --git a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp b/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
index 2bbd11f..f7b4f24 100644
--- a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
+++ b/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
@@ -458,6 +458,11 @@
         return mCollector->mUserSwitchCollections;
     }
 
+    const CollectionInfo& getWakeUpCollectionInfo() {
+        Mutex::Autolock lock(mCollector->mMutex);
+        return mCollector->mWakeUpCollection;
+    }
+
     const CollectionInfo& getCustomCollectionInfo() {
         Mutex::Autolock lock(mCollector->mMutex);
         return mCollector->mCustomCollection;
@@ -548,8 +553,69 @@
             << expected.toString() << "\nActual:\n"
             << actual.toString();
 
-    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
-            << "Periodic and user-switch collections shouldn't be reported";
+    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+            << "Periodic, wake-up and user-switch collections shouldn't be reported";
+}
+
+TEST_F(IoPerfCollectionTest, TestOnWakeUpCollection) {
+    const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+    const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+    EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(uidStats));
+    EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(procStatInfo));
+
+    time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    ASSERT_RESULT_OK(
+            mCollector->onWakeUpCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+
+    const auto actual = mCollectorPeer->getWakeUpCollectionInfo();
+
+    const CollectionInfo expected{
+            .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+            .records = {{
+                    .systemSummaryStats = systemSummaryStats,
+                    .userPackageSummaryStats = userPackageSummaryStats,
+            }},
+    };
+
+    EXPECT_THAT(actual, CollectionInfoEq(expected))
+            << "Wake-up collection info doesn't match.\nExpected:\n"
+            << expected.toString() << "\nActual:\n"
+            << actual.toString();
+
+    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+            << "Boot-time, periodic, and user-switch collections shouldn't be reported";
+}
+
+TEST_F(IoPerfCollectionTest, TestOnSystemStartup) {
+    const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+    const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+    EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(uidStats));
+    EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillRepeatedly(Return(procStatInfo));
+
+    time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    ASSERT_RESULT_OK(
+            mCollector->onBoottimeCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+    ASSERT_RESULT_OK(
+            mCollector->onWakeUpCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+
+    auto actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
+    auto actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
+
+    EXPECT_THAT(actualBoottimeCollection.records.size(), 1)
+            << "Boot-time collection records is empty.";
+    EXPECT_THAT(actualWakeUpCollection.records.size(), 1) << "Wake-up collection records is empty.";
+
+    ASSERT_RESULT_OK(mCollector->onSystemStartup());
+
+    actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
+    actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
+
+    EXPECT_THAT(actualBoottimeCollection.records.size(), 0)
+            << "Boot-time collection records is not empty.";
+    EXPECT_THAT(actualWakeUpCollection.records.size(), 0)
+            << "Wake-up collection records is not empty.";
 }
 
 TEST_F(IoPerfCollectionTest, TestOnUserSwitchCollection) {
@@ -652,8 +718,8 @@
             << expected.toString() << "\nActual:\n"
             << actual.toString();
 
-    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
-            << "Boottime and Periodic collections shouldn't be reported";
+    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+            << "Boot-time, wake-up and periodic collections shouldn't be reported";
 }
 
 TEST_F(IoPerfCollectionTest, TestUserSwitchCollectionsMaxCacheSize) {
@@ -750,8 +816,8 @@
             << expected.toString() << "\nActual:\n"
             << actual.toString();
 
-    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
-            << "Boot-time and user-switch collections shouldn't be reported";
+    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+            << "Boot-time, wake-up and user-switch collections shouldn't be reported";
 }
 
 TEST_F(IoPerfCollectionTest, TestOnCustomCollectionWithoutPackageFilter) {
@@ -914,8 +980,8 @@
             << expected.toString() << "\nActual:\n"
             << actual.toString();
 
-    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
-            << "Boot-time and user-switch collections shouldn't be reported";
+    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+            << "Boot-time, wake-up and user-switch collections shouldn't be reported";
 }
 
 TEST_F(IoPerfCollectionTest, TestConsecutiveOnPeriodicCollection) {
@@ -962,8 +1028,8 @@
             << expected.toString() << "\nActual:\n"
             << actual.toString();
 
-    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
-            << "Boot-time and user-switch collection shouldn't be reported";
+    ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+            << "Boot-time, wake-up and user-switch collection shouldn't be reported";
 }
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/tests/MockDataProcessor.h b/cpp/watchdog/server/tests/MockDataProcessor.h
index 8abc753..01224db 100644
--- a/cpp/watchdog/server/tests/MockDataProcessor.h
+++ b/cpp/watchdog/server/tests/MockDataProcessor.h
@@ -33,10 +33,15 @@
     MOCK_METHOD(std::string, name, (), (const, override));
     MOCK_METHOD(android::base::Result<void>, init, (), (override));
     MOCK_METHOD(void, terminate, (), (override));
+    MOCK_METHOD(android::base::Result<void>, onSystemStartup, (), (override));
     MOCK_METHOD(android::base::Result<void>, onBoottimeCollection,
                 (time_t, const wp<UidStatsCollectorInterface>&,
                  const wp<ProcStatCollectorInterface>&),
                 (override));
+    MOCK_METHOD(android::base::Result<void>, onWakeUpCollection,
+                (time_t, const wp<UidStatsCollectorInterface>&,
+                 const wp<ProcStatCollectorInterface>&),
+                (override));
     MOCK_METHOD(android::base::Result<void>, onPeriodicCollection,
                 (time_t, SystemState, const wp<UidStatsCollectorInterface>&,
                  const wp<ProcStatCollectorInterface>&),
diff --git a/cpp/watchdog/server/tests/MockWatchdogPerfService.h b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
index 9aebb2f..13f78d5 100644
--- a/cpp/watchdog/server/tests/MockWatchdogPerfService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
@@ -43,6 +43,8 @@
                 (userid_t userId,
                  const android::automotive::watchdog::internal::UserState& userState),
                 (override));
+    MOCK_METHOD(android::base::Result<void>, onSuspendExit, (), (override));
+    MOCK_METHOD(android::base::Result<void>, onShutdownEnter, (), (override));
     MOCK_METHOD(android::base::Result<void>, onCustomCollection,
                 (int fd, const Vector<android::String16>& args), (override));
     MOCK_METHOD(android::base::Result<void>, onDump, (int fd), (const, override));
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index cf72613..3329691 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -378,6 +378,8 @@
 TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToShutdownEnter) {
     setSystemCallingUid();
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/false)).Times(1);
+    EXPECT_CALL(*mMockWatchdogPerfService, onShutdownEnter()).Times(1);
+
     Status status =
             mWatchdogInternalHandler
                     ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
@@ -398,6 +400,20 @@
     ASSERT_TRUE(status.isOk()) << status;
 }
 
+TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToSuspendExit) {
+    setSystemCallingUid();
+
+    EXPECT_CALL(*mMockWatchdogPerfService, onSuspendExit()).Times(1);
+
+    auto status = mWatchdogInternalHandler
+                          ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
+                                                    static_cast<int32_t>(
+                                                            PowerCycle::POWER_CYCLE_SUSPEND_EXIT),
+                                                    -1);
+
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnNotifyPowerCycleChangeWithInvalidArgs) {
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(_)).Times(0);
     EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(_)).Times(0);
diff --git a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
index 679e57e..46594de 100644
--- a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
@@ -62,6 +62,7 @@
 constexpr std::chrono::seconds kTestCustomCollectionDuration = 11s;
 constexpr std::chrono::seconds kTestPeriodicMonitorInterval = 2s;
 constexpr std::chrono::seconds kTestUserSwitchTimeout = 15s;
+constexpr std::chrono::seconds kTestWakeUpDuration = 20s;
 
 namespace internal {
 
@@ -89,6 +90,7 @@
         mService->mUserSwitchCollection.interval = kTestSystemEventCollectionInterval;
         mService->mPeriodicMonitor.interval = kTestPeriodicMonitorInterval;
         mService->mUserSwitchTimeoutNs = kTestUserSwitchTimeout;
+        mService->mWakeUpDurationNs = kTestWakeUpDuration;
     }
 
     void clearPostSystemEventDuration() {
@@ -149,6 +151,7 @@
                            mMockProcDiskStatsCollector);
 
         EXPECT_CALL(*mMockDataProcessor, init()).Times(1);
+        EXPECT_CALL(*mMockDataProcessor, onSystemStartup()).Times(1);
 
         ASSERT_RESULT_OK(mService->registerDataProcessor(mMockDataProcessor));
 
@@ -222,6 +225,7 @@
                        mMockProcDiskStatsCollector);
 
     EXPECT_CALL(*mMockDataProcessor, init()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor, onSystemStartup()).Times(1);
 
     ASSERT_RESULT_OK(mService->registerDataProcessor(mMockDataProcessor));
 
@@ -233,6 +237,19 @@
 
     ASSERT_TRUE(mService->mCollectionThread.joinable()) << "Collection thread not created";
 
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor,
+                onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+            .Times(1);
+
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+            << "Boot-time collection didn't start immediately";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
+            << "Invalid collection event";
+
     ASSERT_FALSE(mService->start().ok())
             << "No error returned when WatchdogPerfService was started more than once";
 
@@ -1059,6 +1076,108 @@
     ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
 }
 
+TEST_F(WatchdogPerfServiceTest, TestWakeUpCollection) {
+    ASSERT_NO_FATAL_FAILURE(startService());
+
+    ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+    // #1 Wake up collection
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor, onSystemStartup()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor,
+                onWakeUpCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+            .Times(1);
+
+    ASSERT_RESULT_OK(mService->onSuspendExit());
+
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0) << "Wake up collection didn't start immediately";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::WAKE_UP_COLLECTION)
+            << "Invalid collection event";
+    ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+    // #2 Wake up collections before duration expires
+    int maxIterations = static_cast<int>(kTestWakeUpDuration.count() /
+                                         kTestSystemEventCollectionInterval.count());
+
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+    EXPECT_CALL(*mMockDataProcessor,
+                onWakeUpCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+            .Times(maxIterations);
+
+    // Poll all remaining wake up collections except last
+    for (int i = 0; i < maxIterations - 1; ++i) {
+        ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+        ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+                << "Subsequent wake up collection didn't happen at "
+                << kTestSystemEventCollectionInterval.count() << " seconds interval";
+        ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::WAKE_UP_COLLECTION)
+                << "Invalid collection event";
+    }
+
+    // Suspend exit signal should be ignored since already running wake up collection.
+    ASSERT_RESULT_OK(mService->onSuspendExit());
+
+    // Poll the last wake up collection
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+            << "Last wake up collection didn't happen immediately after sending "
+            << "END_WAKE_UP_COLLECTION message";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+            << "Invalid collection event";
+    ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestWakeUpCollectionDuringCustomCollection) {
+    ASSERT_NO_FATAL_FAILURE(startService());
+
+    ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+    // Start custom collection
+    Vector<String16> args;
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16(kIntervalFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
+    args.push_back(String16(kMaxDurationFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+
+    ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(2);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(2);
+    EXPECT_CALL(*mMockDataProcessor,
+                onCustomCollection(_, SystemState::NORMAL_MODE, _, Eq(mMockUidStatsCollector),
+                                   Eq(mMockProcStatCollector)))
+            .Times(2);
+    EXPECT_CALL(*mMockDataProcessor,
+                onWakeUpCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+            .Times(0);
+
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0) << "Custom collection didn't start immediately";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+            << "Invalid collection event";
+
+    // Custom collection while suspend exit signal is received
+    ASSERT_RESULT_OK(mService->onSuspendExit());
+
+    // Continued custom collection
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestCustomCollectionInterval.count())
+            << "Subsequent custom collection didn't happen at "
+            << kTestCustomCollectionInterval.count() << " seconds interval";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+            << "Invalid collection event";
+    ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
 TEST_F(WatchdogPerfServiceTest, TestPeriodicMonitorRequestsCollection) {
     ASSERT_NO_FATAL_FAILURE(startService());
 
@@ -1096,6 +1215,93 @@
     EXPECT_CALL(*mMockDataProcessor, terminate()).Times(1);
 }
 
+TEST_F(WatchdogPerfServiceTest, TestShutdownEnter) {
+    ASSERT_NO_FATAL_FAILURE(startService());
+
+    // Start boot-time collection
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor,
+                onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+            .Times(1);
+
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+            << "Boot-time collection didn't start immediately";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
+            << "Invalid collection event";
+    ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+    ASSERT_RESULT_OK(mService->onShutdownEnter());
+
+    // Switch to periodic collection
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor,
+                onPeriodicCollection(_, SystemState::NORMAL_MODE, Eq(mMockUidStatsCollector),
+                                     Eq(mMockProcStatCollector)))
+            .Times(1);
+
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+            << "Periodic collection didn't start immediately after receiving shutdown enter signal";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+            << "Invalid collection event";
+    ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestShutdownEnterWithCustomCollection) {
+    ASSERT_NO_FATAL_FAILURE(startService());
+
+    ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+    // Start custom collection
+    Vector<String16> args;
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16(kIntervalFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
+    args.push_back(String16(kMaxDurationFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+
+    ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor,
+                onCustomCollection(_, SystemState::NORMAL_MODE, _, Eq(mMockUidStatsCollector),
+                                   Eq(mMockProcStatCollector)))
+            .Times(1);
+
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0) << "Custom collection didn't start immediately";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+            << "Invalid collection event";
+    ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+    // Suspend in middle of custom collection
+    ASSERT_RESULT_OK(mService->onShutdownEnter());
+
+    // Custom collection
+    EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+    EXPECT_CALL(*mMockDataProcessor,
+                onCustomCollection(_, SystemState::NORMAL_MODE, _, Eq(mMockUidStatsCollector),
+                                   Eq(mMockProcStatCollector)))
+            .Times(1);
+
+    ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+    ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestCustomCollectionInterval.count())
+            << "Subsequent custom collection didn't happen at "
+            << kTestCustomCollectionInterval.count() << " seconds interval";
+    ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+            << "Invalid collection event";
+    ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
 TEST_F(WatchdogPerfServiceTest, TestSystemStateSwitch) {
     ASSERT_NO_FATAL_FAILURE(startService());
 
diff --git a/data/etc/android.car.cluster.xml b/data/etc/android.car.cluster.xml
index 191ded5..3cc4aae 100644
--- a/data/etc/android.car.cluster.xml
+++ b/data/etc/android.car.cluster.xml
@@ -22,6 +22,7 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
         <permission name="android.car.permission.CAR_ENGINE_DETAILED"/>
         <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+        <permission name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
     </privapp-permissions>
 </permissions>
diff --git a/packages/CarDeveloperOptions/AndroidManifest.xml b/packages/CarDeveloperOptions/AndroidManifest.xml
index 8a98780..5850d3e 100644
--- a/packages/CarDeveloperOptions/AndroidManifest.xml
+++ b/packages/CarDeveloperOptions/AndroidManifest.xml
@@ -22,8 +22,9 @@
           android:sharedUserId="android.uid.system">
 
     <application android:label="@string/development_settings_title"
+                 android:theme="@style/Theme.CDOBaseTheme"
                  tools:node="merge"
-                 tools:replace="android:label">
+                 tools:replace="android:label,android:theme">
 
         <activity
             android:name=".CarDevelopmentSettingsDashboardActivity"
diff --git a/packages/CarDeveloperOptions/res/values/themes.xml b/packages/CarDeveloperOptions/res/values/themes.xml
index 43887b3..1eea0e7 100644
--- a/packages/CarDeveloperOptions/res/values/themes.xml
+++ b/packages/CarDeveloperOptions/res/values/themes.xml
@@ -39,6 +39,13 @@
         <item name="buttonBarButtonStyle">@*android:style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
     </style>
 
+    <!-- Base settings application theme with minor modifications for visibility -->
+    <style name="Theme.CDOBaseTheme" parent="@style/Theme.Settings">
+        <item name="android:textAppearanceListItem">@style/CDOTitleTextAppearance</item>
+        <item name="android:textColor">@*android:color/car_body1</item>
+        <item name="android:textColorSecondary">@*android:color/car_body1</item>
+    </style>
+
     <style name="Theme.SubSettings" parent="@android:style/Theme.DeviceDefault.NoActionBar">
         <item name="alertDialogTheme">@style/Theme.AlertDialog</item>
         <item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
@@ -57,15 +64,20 @@
     <style name="Theme.CarDeveloperOptions" parent="@style/Theme.CarUi.WithToolbar">
         <item name="alertDialogTheme">@style/Theme.AlertDialog</item>
         <item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
-        <item name="preferenceTheme">@style/CarDeveloperOptionsPreferenceTheme</item>
+        <item name="preferenceTheme">@style/CDOPreferenceTheme</item>
     </style>
 
-    <style name="CarDeveloperOptionsPreferenceTheme" parent="@style/CarUiPreferenceTheme">
-        <item name="preferenceFragmentCompatStyle">@style/CarDeveloperOptionsPreferenceFragment</item>
-        <item name="preferenceFragmentStyle">@style/CarDeveloperOptionsPreferenceFragment</item>
+    <style name="CDOPreferenceTheme" parent="@style/CarUiPreferenceTheme">
+        <item name="preferenceFragmentCompatStyle">@style/CDOPreferenceFragment</item>
+        <item name="preferenceFragmentStyle">@style/CDOPreferenceFragment</item>
     </style>
 
-    <style name="CarDeveloperOptionsPreferenceFragment" parent="@style/PreferenceFragment.CarUi">
+    <style name="CDOPreferenceFragment" parent="@style/PreferenceFragment.CarUi">
         <item name="android:layout">@layout/preference_list_fragment</item>
     </style>
-</resources>
\ No newline at end of file
+
+    <style name="CDOTitleTextAppearance" parent="@android:style/TextAppearance.DeviceDefault">
+        <item name="android:textSize">@*android:dimen/car_body2_size</item>
+        <item name="android:textColor">@*android:color/car_body1</item>
+    </style>
+</resources>
diff --git a/packages/ScriptExecutor/Android.bp b/packages/ScriptExecutor/Android.bp
index 7258589..c126c7f 100644
--- a/packages/ScriptExecutor/Android.bp
+++ b/packages/ScriptExecutor/Android.bp
@@ -78,6 +78,10 @@
         enabled: false,
     },
 
+    libs: [
+        "android.car",
+    ],
+
     jni_libs: [
         "libscriptexecutorjni",
     ],
@@ -99,5 +103,9 @@
         "src/**/*.java",
     ],
 
+    libs: [
+        "android.car",
+    ],
+
     sdk_version: "test_current",
 }
diff --git a/packages/ScriptExecutor/src/BundleWrapper.cpp b/packages/ScriptExecutor/src/BundleWrapper.cpp
index 88403b0..799f37c 100644
--- a/packages/ScriptExecutor/src/BundleWrapper.cpp
+++ b/packages/ScriptExecutor/src/BundleWrapper.cpp
@@ -17,6 +17,7 @@
 #include "BundleWrapper.h"
 
 #include "JniUtils.h"
+#include "jni.h"
 #include "nativehelper/scoped_local_ref.h"
 
 namespace com {
@@ -106,6 +107,37 @@
     return {};  // ok result
 }
 
+Result<void> BundleWrapper::putBooleanArray(const char* key,
+                                            const std::vector<unsigned char>& value) {
+    ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
+    if (keyStringRef == nullptr) {
+        return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
+    }
+
+    jmethodID putBooleanArrayMethod =
+            mJNIEnv->GetMethodID(mBundleClass, "putBooleanArray", "(Ljava/lang/String;[Z)V");
+
+    ScopedLocalRef<jbooleanArray> arrayRef(mJNIEnv, mJNIEnv->NewBooleanArray(value.size()));
+    mJNIEnv->SetBooleanArrayRegion(arrayRef.get(), 0, value.size(), &value.at(0));
+    mJNIEnv->CallVoidMethod(mBundle, putBooleanArrayMethod, keyStringRef.get(), arrayRef.get());
+    return {};  // ok result
+}
+
+Result<void> BundleWrapper::putDoubleArray(const char* key, const std::vector<double>& value) {
+    ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
+    if (keyStringRef == nullptr) {
+        return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
+    }
+
+    jmethodID putDoubleArrayMethod =
+            mJNIEnv->GetMethodID(mBundleClass, "putDoubleArray", "(Ljava/lang/String;[D)V");
+
+    ScopedLocalRef<jdoubleArray> arrayRef(mJNIEnv, mJNIEnv->NewDoubleArray(value.size()));
+    mJNIEnv->SetDoubleArrayRegion(arrayRef.get(), 0, value.size(), &value[0]);
+    mJNIEnv->CallVoidMethod(mBundle, putDoubleArrayMethod, keyStringRef.get(), arrayRef.get());
+    return {};  // ok result
+}
+
 Result<void> BundleWrapper::putLongArray(const char* key, const std::vector<int64_t>& value) {
     ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
     if (keyStringRef == nullptr) {
@@ -148,7 +180,20 @@
     return {};  // ok result
 }
 
-jobject BundleWrapper::getBundle() {
+Result<void> BundleWrapper::putPersistableBundle(const char* key, const BundleWrapper& value) {
+    jmethodID putPersistableBundleMethod =
+            mJNIEnv->GetMethodID(mBundleClass, "putPersistableBundle",
+                                 "(Ljava/lang/String;Landroid/os/PersistableBundle;)V");
+    ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
+    if (keyStringRef == nullptr) {
+        return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
+    }
+    mJNIEnv->CallVoidMethod(mBundle, putPersistableBundleMethod, keyStringRef.get(),
+                            value.getBundle());
+    return {};  // ok result
+}
+
+jobject BundleWrapper::getBundle() const {
     return mBundle;
 }
 
diff --git a/packages/ScriptExecutor/src/BundleWrapper.h b/packages/ScriptExecutor/src/BundleWrapper.h
index a949108..e7473d8 100644
--- a/packages/ScriptExecutor/src/BundleWrapper.h
+++ b/packages/ScriptExecutor/src/BundleWrapper.h
@@ -45,11 +45,15 @@
     ::android::base::Result<void> putLong(const char* key, int64_t value);
     ::android::base::Result<void> putDouble(const char* key, double value);
     ::android::base::Result<void> putString(const char* key, const char* value);
+    ::android::base::Result<void> putBooleanArray(const char* key,
+                                                  const std::vector<unsigned char>& value);
+    ::android::base::Result<void> putDoubleArray(const char* key, const std::vector<double>& value);
     ::android::base::Result<void> putLongArray(const char* key, const std::vector<int64_t>& value);
     ::android::base::Result<void> putStringArray(const char* key,
                                                  const std::vector<std::string>& value);
+    ::android::base::Result<void> putPersistableBundle(const char* key, const BundleWrapper& value);
 
-    jobject getBundle();
+    jobject getBundle() const;
 
 private:
     // The class asks Java to create PersistableBundle object and stores the reference.
diff --git a/packages/ScriptExecutor/src/JniUtils.cpp b/packages/ScriptExecutor/src/JniUtils.cpp
index 62467f5..119debd 100644
--- a/packages/ScriptExecutor/src/JniUtils.cpp
+++ b/packages/ScriptExecutor/src/JniUtils.cpp
@@ -23,6 +23,9 @@
 namespace car {
 namespace scriptexecutor {
 
+// TODO(b/199415783): Revisit the topic of limits to potentially move it to standalone file.
+constexpr int MAX_ARRAY_SIZE = 1000;
+
 void pushBundleToLuaTable(JNIEnv* env, lua_State* lua, jobject bundle) {
     lua_newtable(lua);
     // null bundle object is allowed. We will treat it as an empty table.
@@ -52,12 +55,11 @@
     ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long"));
     ScopedLocalRef<jclass> numberClass(env, env->FindClass("java/lang/Number"));
     ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
+    ScopedLocalRef<jclass> booleanArrayClass(env, env->FindClass("[Z"));
     ScopedLocalRef<jclass> intArrayClass(env, env->FindClass("[I"));
     ScopedLocalRef<jclass> longArrayClass(env, env->FindClass("[J"));
     ScopedLocalRef<jclass> doubleArrayClass(env, env->FindClass("[D"));
     ScopedLocalRef<jclass> stringArrayClass(env, env->FindClass("[Ljava/lang/String;"));
-    // TODO(b/188816922): Handle more types such as float and integer arrays,
-    // and perhaps nested Bundles.
 
     jmethodID getMethod = env->GetMethodID(persistableBundleClass.get(), "get",
                                            "(Ljava/lang/String;)Ljava/lang/Object;");
@@ -97,6 +99,23 @@
                     env->GetStringUTFChars(static_cast<jstring>(value.get()), nullptr);
             lua_pushstring(lua, rawStringValue);
             env->ReleaseStringUTFChars(static_cast<jstring>(value.get()), rawStringValue);
+        } else if (env->IsInstanceOf(value.get(), booleanArrayClass.get())) {
+            jbooleanArray booleanArray = static_cast<jbooleanArray>(value.get());
+            const auto kLength = env->GetArrayLength(booleanArray);
+            // Arrays are represented as a table of sequential elements in Lua.
+            // We are creating a nested table to represent this array. We specify number of elements
+            // in the Java array to preallocate memory accordingly.
+            lua_createtable(lua, kLength, 0);
+            jboolean* rawBooleanArray = env->GetBooleanArrayElements(booleanArray, nullptr);
+            // Fills in the table at stack idx -2 with key value pairs, where key is a
+            // Lua index and value is an integer from the long array at that index
+            for (int i = 0; i < kLength; i++) {
+                lua_pushboolean(lua, rawBooleanArray[i]);
+                lua_rawseti(lua, /* idx= */ -2,
+                            i + 1);  // lua index starts from 1
+            }
+            // JNI_ABORT is used because we do not need to copy back elements.
+            env->ReleaseBooleanArrayElements(booleanArray, rawBooleanArray, JNI_ABORT);
         } else if (env->IsInstanceOf(value.get(), intArrayClass.get())) {
             jintArray intArray = static_cast<jintArray>(value.get());
             const auto kLength = env->GetArrayLength(intArray);
@@ -167,6 +186,11 @@
                 // lua index starts from 1
                 lua_rawseti(lua, /* idx= */ -2, i + 1);
             }
+        } else if (env->IsInstanceOf(value.get(), persistableBundleClass.get())) {
+            jobject bundle = static_cast<jobject>(value.get());
+            // After this call, the lua stack will have 1 new item at the top of the stack: a table
+            // representing the PersistableBundle
+            pushBundleToLuaTable(env, lua, bundle);
         } else {
             // Other types are not implemented yet, skipping.
             continue;
@@ -180,6 +204,178 @@
     }
 }
 
+void pushBundleListToLuaTable(JNIEnv* env, lua_State* lua, jobject bundleList) {
+    // Creates a new table as the encompassing array to contain the converted bundles.
+    // Pushed to top of stack.
+    lua_newtable(lua);
+
+    ScopedLocalRef<jclass> listClass(env, env->FindClass("java/util/List"));
+    jmethodID sizeMethod = env->GetMethodID(listClass.get(), "size", "()I");
+    jmethodID getMethod = env->GetMethodID(listClass.get(), "get", "(I)Ljava/lang/Object;");
+
+    const auto listSize = env->CallIntMethod(bundleList, sizeMethod);
+    // For each bundle in the bundleList set a converted Lua table into the table array.
+    for (int i = 0; i < listSize; i++) {
+        // Push to stack the index at which the next Lua table will be at. Lua index start at 1.
+        lua_pushnumber(lua, i + 1);
+        // Convert the bundle at i into Lua table and push to top of stack.
+        pushBundleToLuaTable(env, lua, env->CallObjectMethod(bundleList, getMethod, i));
+        // table[k] = v, table should be at the given index (-3), and expects v the value to be
+        // at the top of the stack, and k the key to be just below the top.
+        lua_settable(lua, /* idx= */ -3);
+    }
+}
+
+Result<void> convertLuaTableToBundle(JNIEnv* env, lua_State* lua, BundleWrapper* bundleWrapper) {
+    // Iterate over Lua table which is expected to be at the top of Lua stack.
+    // lua_next call pops the key from the top of the stack and finds the next
+    // key-value pair. It returns 0 if the next pair was not found.
+    // More on lua_next in: https://www.lua.org/manual/5.3/manual.html#lua_next
+    lua_pushnil(lua);  // First key is a null value, at index -1
+    while (lua_next(lua, /* table index = */ -2) != 0) {
+        //  'key' is at index -2 and 'value' is at index -1
+        // -1 index is the top of the stack.
+        // remove 'value' and keep 'key' for next iteration
+        // Process each key-value depending on a type and push it to Java PersistableBundle.
+        // TODO(b/199531928): Consider putting limits on key sizes as well.
+        const char* key = lua_tostring(lua, /* index = */ -2);
+        Result<void> bundleInsertionResult;
+        if (lua_isboolean(lua, /* index = */ -1)) {
+            bundleInsertionResult =
+                    bundleWrapper->putBoolean(key,
+                                              static_cast<bool>(
+                                                      lua_toboolean(lua, /* index = */ -1)));
+        } else if (lua_isinteger(lua, /* index = */ -1)) {
+            bundleInsertionResult =
+                    bundleWrapper->putLong(key,
+                                           static_cast<int64_t>(
+                                                   lua_tointeger(lua, /* index = */ -1)));
+        } else if (lua_isnumber(lua, /* index = */ -1)) {
+            bundleInsertionResult =
+                    bundleWrapper->putDouble(key,
+                                             static_cast<double>(
+                                                     lua_tonumber(lua, /* index = */ -1)));
+        } else if (lua_isstring(lua, /* index = */ -1)) {
+            // TODO(b/199415783): We need to have a limit on how long these strings could be.
+            bundleInsertionResult =
+                    bundleWrapper->putString(key, lua_tostring(lua, /* index = */ -1));
+        } else if (lua_istable(lua, /* index =*/-1) && lua_rawlen(lua, -1) > 0) {
+            // Lua uses tables to represent arrays and PersistableBundles.
+            // If lua_rawlen is greater than 0, this table is a sequence, which means it is an
+            // array.
+
+            // TODO(b/199438375): Document to users that we expect tables to be either only indexed
+            // or keyed but not both. If the table contains consecutively indexed values starting
+            // from 1, we will treat it as an array. lua_rawlen call returns the size of the indexed
+            // part. We copy this part into an array, but any keyed values in this table are
+            // ignored. There is a test that documents this current behavior. If a user wants a
+            // nested table to be represented by a PersistableBundle object, they must make sure
+            // that the nested table does not contain indexed data, including no key=1.
+            const auto kTableLength = lua_rawlen(lua, -1);
+            if (kTableLength > MAX_ARRAY_SIZE) {
+                return Error()
+                        << "Returned table " << key << " exceeds maximum allowed size of "
+                        << MAX_ARRAY_SIZE
+                        << " elements. This key-value cannot be unpacked successfully. This error "
+                           "is unrecoverable.";
+            }
+
+            std::vector<unsigned char> boolArray;
+            std::vector<double> doubleArray;
+            std::vector<int64_t> longArray;
+            std::vector<std::string> stringArray;
+            int originalLuaType = LUA_TNIL;
+            for (int i = 0; i < kTableLength; i++) {
+                lua_rawgeti(lua, -1, i + 1);
+                // Lua allows arrays to have values of varying type. We need to force all Lua
+                // arrays to stick to single type within the same array. We use the first value
+                // in the array to determine the type of all values in the array that follow
+                // after. If the second, third, etc element of the array does not match the type
+                // of the first element we stop the extraction and return an error via a
+                // callback.
+                if (i == 0) {
+                    originalLuaType = lua_type(lua, /* index = */ -1);
+                }
+                int currentType = lua_type(lua, /* index= */ -1);
+                if (currentType != originalLuaType) {
+                    return Error()
+                            << "Returned Lua arrays must have elements of the same type. Returned "
+                               "table with key="
+                            << key << " has the first element of type=" << originalLuaType
+                            << ", but the element at index=" << i + 1 << " has type=" << currentType
+                            << ". Integer type codes are defined in lua.h file. This error is "
+                               "unrecoverable.";
+                }
+                switch (currentType) {
+                    case LUA_TBOOLEAN:
+                        boolArray.push_back(
+                                static_cast<unsigned char>(lua_toboolean(lua, /* index = */ -1)));
+                        break;
+                    case LUA_TNUMBER:
+                        if (lua_isinteger(lua, /* index = */ -1)) {
+                            longArray.push_back(lua_tointeger(lua, /* index = */ -1));
+                        } else {
+                            doubleArray.push_back(lua_tonumber(lua, /* index = */ -1));
+                        }
+                        break;
+                    case LUA_TSTRING:
+                        // TODO(b/200833728): Investigate optimizations to minimize string
+                        // copying. For example, populate JNI object array one element at a
+                        // time, as we go.
+                        stringArray.push_back(lua_tostring(lua, /* index = */ -1));
+                        break;
+                    default:
+                        return Error() << "Returned value for key=" << key
+                                       << " is an array with values of type="
+                                       << lua_typename(lua, lua_type(lua, /* index = */ -1))
+                                       << ", which is not supported yet.";
+                }
+                lua_pop(lua, 1);
+            }
+            switch (originalLuaType) {
+                case LUA_TBOOLEAN:
+                    bundleInsertionResult = bundleWrapper->putBooleanArray(key, boolArray);
+                    break;
+                case LUA_TNUMBER:
+                    if (longArray.size() > 0) {
+                        bundleInsertionResult = bundleWrapper->putLongArray(key, longArray);
+                    } else {
+                        bundleInsertionResult = bundleWrapper->putDoubleArray(key, doubleArray);
+                    }
+                    break;
+                case LUA_TSTRING:
+                    bundleInsertionResult = bundleWrapper->putStringArray(key, stringArray);
+                    break;
+            }
+        } else if (lua_istable(lua, /* index =*/-1)) {
+            // If the Lua table is not a sequence, i.e., it is a table with string keys, then it is
+            // a PersistableBundle
+            BundleWrapper nestedBundleWrapper(env);
+            // After this line, the Lua stack is unchanged, so the top of the stack is still a
+            // table, but the nestedBundleWrapper will be populated
+            const auto status = convertLuaTableToBundle(env, lua, &nestedBundleWrapper);
+            if (!status.ok()) {
+                return Error() << "Failed to parse nested tables into nested PersistableBundles";
+            }
+            bundleInsertionResult = bundleWrapper->putPersistableBundle(key, nestedBundleWrapper);
+        } else {
+            return Error() << "key=" << key << " has a Lua type="
+                           << lua_typename(lua, lua_type(lua, /* index = */ -1))
+                           << ", which is not supported yet.";
+        }
+        // Pop value from the stack, keep the key for the next iteration.
+        lua_pop(lua, 1);
+        // The key is at index -1, the table is at index -2 now.
+
+        // Check if insertion of the current key-value into the bundle was successful. If not,
+        // fail-fast out of this extraction routine.
+        if (!bundleInsertionResult.ok()) {
+            return bundleInsertionResult;
+        }
+    }
+    return {};  // ok result
+}
+
 }  // namespace scriptexecutor
 }  // namespace car
 }  // namespace android
diff --git a/packages/ScriptExecutor/src/JniUtils.h b/packages/ScriptExecutor/src/JniUtils.h
index 542a91a..2a08217 100644
--- a/packages/ScriptExecutor/src/JniUtils.h
+++ b/packages/ScriptExecutor/src/JniUtils.h
@@ -22,6 +22,8 @@
 #include "lua.h"
 }
 
+#include "BundleWrapper.h"
+
 #include <android-base/result.h>
 
 namespace com {
@@ -29,6 +31,9 @@
 namespace car {
 namespace scriptexecutor {
 
+using ::android::base::Error;
+using ::android::base::Result;
+
 // Helper function which takes android.os.Bundle object in "bundle" argument
 // and converts it to Lua table on top of Lua stack. All key-value pairs are
 // converted to the corresponding key-value pairs of the Lua table as long as
@@ -36,6 +41,28 @@
 // integer, double and String types in Java.
 void pushBundleToLuaTable(JNIEnv* env, lua_State* lua, jobject bundle);
 
+// Helper function that takes list of android.os.Bundle object in "bundleList"
+// argument and converts it to Lua table on top of the Lua stack. The Lua table
+// will be an array of converted android.os.Bundle objects in Lua table form,
+// each having the key-value pairs as converted by pushBundleToLuaTable.
+void pushBundleListToLuaTable(JNIEnv* env, lua_State* lua, jobject bundleList);
+
+// Helper function that goes over Lua table fields one by one and populates PersistableBundle
+// object wrapped in BundleWrapper.
+// It is assumed that Lua table is located on top of the Lua stack. There could be other
+// items in the stack, this function will not touch them.
+//
+// Returns false if the conversion encountered unrecoverable error.
+// Otherwise, returns true for success.
+//
+// If the function succeeds, the stack should be unchanged.
+// In case of an error, there is no need to pop elements or clean the stack. When Lua calls C,
+// the stack used to pass data between Lua and C is private for each call. According to
+// https://www.lua.org/pil/26.1.html, after C function returns back to Lua, Lua
+// removes everything that is in the stack below the returned results.
+// TODO(b/200849134): Refactor this function.
+Result<void> convertLuaTableToBundle(JNIEnv* env, lua_State* lua, BundleWrapper* bundleWrapper);
+
 }  // namespace scriptexecutor
 }  // namespace car
 }  // namespace android
diff --git a/packages/ScriptExecutor/src/LuaEngine.cpp b/packages/ScriptExecutor/src/LuaEngine.cpp
index 3a5daf4..e7cf654 100644
--- a/packages/ScriptExecutor/src/LuaEngine.cpp
+++ b/packages/ScriptExecutor/src/LuaEngine.cpp
@@ -17,6 +17,8 @@
 #include "LuaEngine.h"
 
 #include "BundleWrapper.h"
+#include "JniUtils.h"
+#include "jni.h"
 
 #include <android-base/logging.h>
 
@@ -36,9 +38,6 @@
 namespace car {
 namespace scriptexecutor {
 
-using ::android::base::Error;
-using ::android::base::Result;
-
 namespace {
 
 enum LuaNumReturnedResults {
@@ -48,156 +47,6 @@
 // Prefix for logging messages coming from lua script.
 const char kLuaLogTag[] = "LUA: ";
 
-// TODO(b/199415783): Revisit the topic of limits to potentially move it to standalone file.
-constexpr int MAX_ARRAY_SIZE = 1000;
-
-// Helper method that goes over Lua table fields one by one and populates PersistableBundle
-// object wrapped in BundleWrapper.
-// It is assumed that Lua table is located on top of the Lua stack. There could be other
-// items in the stack, this function will not touch them.
-//
-// Returns false if the conversion encountered unrecoverable error.
-// Otherwise, returns true for success.
-//
-// If the function succeeds, the stack should be unchanged.
-// In case of an error, there is no need to pop elements or clean the stack. When Lua calls C,
-// the stack used to pass data between Lua and C is private for each call. According to
-// https://www.lua.org/pil/26.1.html, after C function returns back to Lua, Lua
-// removes everything that is in the stack below the returned results.
-// TODO(b/200849134): Refactor this function.
-Result<void> convertLuaTableToBundle(lua_State* lua, BundleWrapper* bundleWrapper) {
-    // Iterate over Lua table which is expected to be at the top of Lua stack.
-    // lua_next call pops the key from the top of the stack and finds the next
-    // key-value pair. It returns 0 if the next pair was not found.
-    // More on lua_next in: https://www.lua.org/manual/5.3/manual.html#lua_next
-    lua_pushnil(lua);  // First key is a null value, at index -1
-    while (lua_next(lua, /* table index = */ -2) != 0) {
-        //  'key' is at index -2 and 'value' is at index -1
-        // -1 index is the top of the stack.
-        // remove 'value' and keep 'key' for next iteration
-        // Process each key-value depending on a type and push it to Java PersistableBundle.
-        // TODO(b/199531928): Consider putting limits on key sizes as well.
-        const char* key = lua_tostring(lua, /* index = */ -2);
-        Result<void> bundleInsertionResult;
-        if (lua_isboolean(lua, /* index = */ -1)) {
-            bundleInsertionResult =
-                    bundleWrapper->putBoolean(key,
-                                              static_cast<bool>(
-                                                      lua_toboolean(lua, /* index = */ -1)));
-        } else if (lua_isinteger(lua, /* index = */ -1)) {
-            bundleInsertionResult =
-                    bundleWrapper->putLong(key,
-                                           static_cast<int64_t>(
-                                                   lua_tointeger(lua, /* index = */ -1)));
-        } else if (lua_isnumber(lua, /* index = */ -1)) {
-            bundleInsertionResult =
-                    bundleWrapper->putDouble(key,
-                                             static_cast<double>(
-                                                     lua_tonumber(lua, /* index = */ -1)));
-        } else if (lua_isstring(lua, /* index = */ -1)) {
-            // TODO(b/199415783): We need to have a limit on how long these strings could be.
-            bundleInsertionResult =
-                    bundleWrapper->putString(key, lua_tostring(lua, /* index = */ -1));
-        } else if (lua_istable(lua, /* index =*/-1)) {
-            // Lua uses tables to represent an array.
-
-            // TODO(b/199438375): Document to users that we expect tables to be either only indexed
-            // or keyed but not both. If the table contains consecutively indexed values starting
-            // from 1, we will treat it as an array. lua_rawlen call returns the size of the indexed
-            // part. We copy this part into an array, but any keyed values in this table are
-            // ignored. There is a test that documents this current behavior. If a user wants a
-            // nested table to be represented by a PersistableBundle object, they must make sure
-            // that the nested table does not contain indexed data, including no key=1.
-            const auto kTableLength = lua_rawlen(lua, -1);
-            if (kTableLength > MAX_ARRAY_SIZE) {
-                return Error()
-                        << "Returned table " << key << " exceeds maximum allowed size of "
-                        << MAX_ARRAY_SIZE
-                        << " elements. This key-value cannot be unpacked successfully. This error "
-                           "is unrecoverable.";
-            }
-            if (kTableLength <= 0) {
-                return Error() << "A value with key=" << key
-                               << " appears to be a nested table that does not represent an array "
-                                  "of data. "
-                                  "Such nested tables are not supported yet. This script error is "
-                                  "unrecoverable.";
-            }
-
-            std::vector<int64_t> longArray;
-            std::vector<std::string> stringArray;
-            int originalLuaType = LUA_TNIL;
-            for (int i = 0; i < kTableLength; i++) {
-                lua_rawgeti(lua, -1, i + 1);
-                // Lua allows arrays to have values of varying type. We need to force all Lua
-                // arrays to stick to single type within the same array. We use the first value
-                // in the array to determine the type of all values in the array that follow
-                // after. If the second, third, etc element of the array does not match the type
-                // of the first element we stop the extraction and return an error via a
-                // callback.
-                if (i == 0) {
-                    originalLuaType = lua_type(lua, /* index = */ -1);
-                }
-                int currentType = lua_type(lua, /* index= */ -1);
-                if (currentType != originalLuaType) {
-                    return Error()
-                            << "Returned Lua arrays must have elements of the same type. Returned "
-                               "table with key="
-                            << key << " has the first element of type=" << originalLuaType
-                            << ", but the element at index=" << i + 1 << " has type=" << currentType
-                            << ". Integer type codes are defined in lua.h file. This error is "
-                               "unrecoverable.";
-                }
-                switch (currentType) {
-                    case LUA_TNUMBER:
-                        if (!lua_isinteger(lua, /* index = */ -1)) {
-                            return Error() << "Returned value for key=" << key
-                                           << " contains a floating number array, which is not "
-                                              "supported yet.";
-                        } else {
-                            longArray.push_back(lua_tointeger(lua, /* index = */ -1));
-                        }
-                        break;
-                    case LUA_TSTRING:
-                        // TODO(b/200833728): Investigate optimizations to minimize string
-                        // copying. For example, populate JNI object array one element at a
-                        // time, as we go.
-                        stringArray.push_back(lua_tostring(lua, /* index = */ -1));
-                        break;
-                    default:
-                        return Error() << "Returned value for key=" << key
-                                       << " is an array with values of type="
-                                       << lua_typename(lua, lua_type(lua, /* index = */ -1))
-                                       << ", which is not supported yet.";
-                }
-                lua_pop(lua, 1);
-            }
-            switch (originalLuaType) {
-                case LUA_TNUMBER:
-                    bundleInsertionResult = bundleWrapper->putLongArray(key, longArray);
-                    break;
-                case LUA_TSTRING:
-                    bundleInsertionResult = bundleWrapper->putStringArray(key, stringArray);
-                    break;
-            }
-        } else {
-            return Error() << "key=" << key << " has a Lua type="
-                           << lua_typename(lua, lua_type(lua, /* index = */ -1))
-                           << ", which is not supported yet.";
-        }
-        // Pop value from the stack, keep the key for the next iteration.
-        lua_pop(lua, 1);
-        // The key is at index -1, the table is at index -2 now.
-
-        // Check if insertion of the current key-value into the bundle was successful. If not,
-        // fail-fast out of this extraction routine.
-        if (!bundleInsertionResult.ok()) {
-            return bundleInsertionResult;
-        }
-    }
-    return {};  // ok result
-}
-
 }  // namespace
 
 ScriptExecutorListener* LuaEngine::sListener = nullptr;
@@ -313,7 +162,7 @@
 
     // Helper object to create and populate Java PersistableBundle object.
     BundleWrapper bundleWrapper(sListener->getCurrentJNIEnv());
-    const auto status = convertLuaTableToBundle(lua, &bundleWrapper);
+    const auto status = convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &bundleWrapper);
     if (!status.ok()) {
         sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, status.error().message().c_str(), "");
         // We explicitly must tell Lua how many results we return, which is 0 in this case.
@@ -341,7 +190,7 @@
 
     // Helper object to create and populate Java PersistableBundle object.
     BundleWrapper bundleWrapper(sListener->getCurrentJNIEnv());
-    const auto status = convertLuaTableToBundle(lua, &bundleWrapper);
+    const auto status = convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &bundleWrapper);
     if (!status.ok()) {
         sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, status.error().message().c_str(), "");
         // We explicitly must tell Lua how many results we return, which is 0 in this case.
@@ -390,7 +239,8 @@
     // object.
     BundleWrapper topBundleWrapper(sListener->getCurrentJNIEnv());
     // If the helper function succeeds, it should not change the stack
-    const auto status = convertLuaTableToBundle(lua, &topBundleWrapper);
+    const auto status =
+            convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &topBundleWrapper);
     if (!status.ok()) {
         sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, status.error().message().c_str(), "");
         // We explicitly must tell Lua how many results we return, which is 0 in this case.
@@ -420,7 +270,8 @@
 
     // process the report
     BundleWrapper bottomBundleWrapper(sListener->getCurrentJNIEnv());
-    const auto statusBottom = convertLuaTableToBundle(lua, &bottomBundleWrapper);
+    const auto statusBottom =
+            convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &bottomBundleWrapper);
     if (!statusBottom.ok()) {
         sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, statusBottom.error().message().c_str(), "");
         // We explicitly must tell Lua how many results we return, which is 0 in this case.
diff --git a/packages/ScriptExecutor/src/ScriptExecutorJni.cpp b/packages/ScriptExecutor/src/ScriptExecutorJni.cpp
index d8ddd55..7a38ab8 100644
--- a/packages/ScriptExecutor/src/ScriptExecutorJni.cpp
+++ b/packages/ScriptExecutor/src/ScriptExecutorJni.cpp
@@ -67,7 +67,7 @@
 // Step 6: Attempt to run the provided function.
 JNIEXPORT void JNICALL Java_com_android_car_scriptexecutor_ScriptExecutor_nativeInvokeScript(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jstring scriptBody, jstring functionName,
-        jobject publishedData, jobject savedState, jobject listener) {
+        jobject publishedData, jobject bundleList, jobject savedState, jobject listener) {
     if (!luaEnginePtr) {
         env->FatalError("luaEnginePtr parameter cannot be nil");
     }
@@ -106,8 +106,13 @@
         return;
     }
 
-    // Unpack bundle in publishedData, convert to Lua table and push it to Lua stack.
-    pushBundleToLuaTable(env, engine->getLuaState(), publishedData);
+    if (bundleList != nullptr) {
+        // Unpack bundle in bundleList, convert to Lua array of tables and push it to Lua stack.
+        pushBundleListToLuaTable(env, engine->getLuaState(), bundleList);
+    } else {
+        // Unpack bundle in publishedData, convert to Lua table and push it to Lua stack.
+        pushBundleToLuaTable(env, engine->getLuaState(), publishedData);
+    }
 
     // Unpack bundle in savedState, convert to Lua table and push it to Lua
     // stack.
diff --git a/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java b/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java
index 362005e..aea6f3f 100644
--- a/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java
+++ b/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java
@@ -29,11 +29,14 @@
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.car.internal.LargeParcelable;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 
 /**
  * Executes Lua code in an isolated process with provided source code
@@ -59,7 +62,7 @@
             ensureCallerIsSystem();
             mNativeHandler.post(() ->
                     nativeInvokeScript(mLuaEnginePtr, scriptBody, functionName, publishedData,
-                            savedState, listener));
+                            null, savedState, listener));
         }
 
         @Override
@@ -87,9 +90,22 @@
                 }
 
                 nativeInvokeScript(mLuaEnginePtr, scriptBody, functionName, publishedData,
-                        savedState, listener);
+                        null, savedState, listener);
             });
         }
+
+        @Override
+        public void invokeScriptForBundleList(String scriptBody, String functionName,
+                BundleList bundleList, PersistableBundle savedState,
+                IScriptExecutorListener listener) throws SecurityException {
+            ensureCallerIsSystem();
+            BundleList reconstBundles =
+                    (BundleList) LargeParcelable.reconstructStableAIDLParcelable(
+                            bundleList, /*keepSharedMemory=*/false);
+            mNativeHandler.post(() ->
+                    nativeInvokeScript(mLuaEnginePtr, scriptBody, functionName, null,
+                            reconstBundles.bundles, savedState, listener));
+        }
     }
 
     private IScriptExecutorImpl mScriptExecutorBinder;
@@ -147,12 +163,14 @@
      *                      invoked.
      * @param functionName  the name of the function to execute.
      * @param publishedData input data provided by the source which the function handles.
+     * @param bundleList    input data list provided by the source which the function handles.
      * @param savedState    key-value pairs preserved from the previous invocation of the function.
-     * @param listener      callback for the sandboxed environent to report back script execution
+     * @param listener      callback for the sandboxed environment to report back script execution
      *                      results
      *                      and errors.
      */
     private native void nativeInvokeScript(long luaEnginePtr, String scriptBody,
-            String functionName, PersistableBundle publishedData, PersistableBundle savedState,
+            String functionName, PersistableBundle publishedData,
+            List<PersistableBundle> bundleList, PersistableBundle savedState,
             IScriptExecutorListener listener);
 }
diff --git a/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java b/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
index 68bc2b1..8ae1f27 100644
--- a/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
+++ b/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
@@ -164,21 +164,51 @@
     }
 
     @Test
-    public void invokeScript_skipsUnsupportedNestedTables()
+    public void invokeScript_supportsNestedTables()
             throws RemoteException, InterruptedException {
         String script =
                 "function nested(data, state)\n"
                         + "    result = {string=\"hello\", boolean=true, integer=1, number=1.1}\n"
-                        + "    result.nested_table = {x=0, y=0}\n"
+                        + "    result.nested_table = {x=10, y=30}\n"
                         + "    on_success(result)\n"
                         + "end\n";
 
         runScriptAndWaitForResponse(script, "nested", mEmptyPublishedData, mEmptyIterimResult);
 
         // Verify that expected error is received.
-        assertThat(mListener.mErrorType)
-                .isEqualTo(IScriptExecutorListener.ERROR_TYPE_LUA_SCRIPT_ERROR);
-        assertThat(mListener.mMessage).contains("nested tables are not supported");
+        assertThat(mListener.mInterimResult.size()).isEqualTo(5);
+        PersistableBundle nestedBundle = mListener.mInterimResult.getPersistableBundle(
+                "nested_table");
+        assertThat(nestedBundle).isNotNull();
+        assertThat(nestedBundle.getLong("x")).isEqualTo(10);
+        assertThat(nestedBundle.getLong("y")).isEqualTo(30);
+    }
+
+    @Test
+    public void invokeScript_supportsDeeplyNestedTables()
+            throws RemoteException, InterruptedException {
+        String script =
+                "function nested(data, state)\n"
+                        + "    local result = {}\n"
+                        + "    result.nested_table = {x=10, y=30}\n"
+                        + "    result.nested_table.second_nested_table = {z=100}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+        runScriptAndWaitForResponse(script, "nested", mEmptyPublishedData, mEmptyIterimResult);
+
+        // Verify that expected error is received.
+        assertThat(mListener.mInterimResult.size()).isEqualTo(1);
+        PersistableBundle nestedBundle = mListener.mInterimResult.getPersistableBundle(
+                "nested_table");
+        assertThat(nestedBundle).isNotNull();
+        assertThat(nestedBundle.size()).isEqualTo(3);
+        assertThat(nestedBundle.getLong("x")).isEqualTo(10);
+        assertThat(nestedBundle.getLong("y")).isEqualTo(30);
+        PersistableBundle secondNestedBundle = nestedBundle.getPersistableBundle(
+                "second_nested_table");
+        assertThat(secondNestedBundle.size()).isEqualTo(1);
+        assertThat(secondNestedBundle.getLong("z")).isEqualTo(100);
     }
 
     @Test
@@ -254,16 +284,22 @@
         String script =
                 "function arrays(data, state)\n"
                         + "    result = {}\n"
+                        + "    result.boolean_array = state.boolean_array\n"
+                        + "    result.double_array = state.double_array\n"
                         + "    result.int_array = state.int_array\n"
                         + "    result.long_array = state.long_array\n"
                         + "    result.string_array = state.string_array\n"
                         + "    on_success(result)\n"
                         + "end\n";
         PersistableBundle previousState = new PersistableBundle();
+        boolean[] boolean_array = new boolean[] {true, true, false};
+        double[] double_array = new double[] {1.5, 2.222};
         int[] int_array = new int[] {1, 2};
         long[] int_array_in_long = new long[] {1, 2};
         long[] long_array = new long[] {1, 2, 3};
         String[] string_array = new String[] {"one", "two", "three"};
+        previousState.putBooleanArray("boolean_array", boolean_array);
+        previousState.putDoubleArray("double_array", double_array);
         previousState.putIntArray("int_array", int_array);
         previousState.putLongArray("long_array", long_array);
         previousState.putStringArray("string_array", string_array);
@@ -271,9 +307,12 @@
         runScriptAndWaitForResponse(script, "arrays", mEmptyPublishedData, previousState);
 
         // Verify that keys are preserved but the values are modified as expected.
-        assertThat(mListener.mInterimResult.size()).isEqualTo(3);
+        assertThat(mListener.mInterimResult.size()).isEqualTo(5);
         // Lua has only one lua_Integer. Here Java long is used to represent it when data is
         // transferred from Lua to CarTelemetryService.
+        assertThat(mListener.mInterimResult.getBooleanArray("boolean_array"))
+                .isEqualTo(boolean_array);
+        assertThat(mListener.mInterimResult.getDoubleArray("double_array")).isEqualTo(double_array);
         assertThat(mListener.mInterimResult.getLongArray("int_array")).isEqualTo(int_array_in_long);
         assertThat(mListener.mInterimResult.getLongArray("long_array")).isEqualTo(long_array);
         assertThat(mListener.mInterimResult.getStringArray("string_array")).isEqualTo(string_array);
@@ -856,52 +895,6 @@
     }
 
     @Test
-    public void invokeScript_returnedFloatingArraysNotSupported()
-            throws RemoteException, InterruptedException {
-        // Verifies that we do not support return values that contain floating number arrays.
-        String script =
-                "function floating_point_arrays(data, state)\n"
-                        + "    array = {}\n"
-                        + "    array[0] = 1.1\n"
-                        + "    array[1] = 1.2\n"
-                        + "    result = {data = array}\n"
-                        + "    on_success(result)\n"
-                        + "end\n";
-
-        runScriptAndWaitForResponse(
-                script, "floating_point_arrays", mEmptyPublishedData, mEmptyIterimResult);
-
-        // Verify that the expected error is received.
-        assertThat(mListener.mErrorType)
-                .isEqualTo(IScriptExecutorListener.ERROR_TYPE_LUA_SCRIPT_ERROR);
-        assertThat(mListener.mMessage)
-                .contains("a floating number array, which is not supported yet");
-    }
-
-    @Test
-    public void invokeScript_returnedBooleanArraysNotSupported()
-            throws RemoteException, InterruptedException {
-        // Verifies that we do not yet support return values that contain boolean arrays.
-        String script =
-                "function array_of_booleans(data, state)\n"
-                        + "    array = {}\n"
-                        + "    array[0] = false\n"
-                        + "    array[1] = true\n"
-                        + "    result = {data = array}\n"
-                        + "    on_success(result)\n"
-                        + "end\n";
-
-        runScriptAndWaitForResponse(
-                script, "array_of_booleans", mEmptyPublishedData, mEmptyIterimResult);
-
-        // Verify that the expected error is received.
-        assertThat(mListener.mErrorType)
-                .isEqualTo(IScriptExecutorListener.ERROR_TYPE_LUA_SCRIPT_ERROR);
-        assertThat(mListener.mMessage)
-                .contains("is an array with values of type=boolean, which is not supported yet");
-    }
-
-    @Test
     public void invokeScript_onMetricsReport_returnsReport() throws Exception {
         String returnFinalResultScript =
                 "function script_completes(data, state)\n"
diff --git a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
index 7a7404f..3e4f33e 100644
--- a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
+++ b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
@@ -26,6 +26,9 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(JUnit4.class)
 public final class JniUtilsTest {
 
@@ -35,17 +38,22 @@
     private static final String INT_KEY = "int_key";
     private static final String STRING_KEY = "string_key";
     private static final String NUMBER_KEY = "number_key";
+    private static final String BOOLEAN_ARRAY_KEY = "boolean_array_key";
     private static final String INT_ARRAY_KEY = "int_array_key";
     private static final String LONG_ARRAY_KEY = "long_array_key";
     private static final String DOUBLE_ARRAY_KEY = "double_array_key";
+    private static final String PERSISTABLE_BUNDLE_KEY = "persistable_bundle_key";
 
     private static final boolean BOOLEAN_VALUE = true;
     private static final double NUMBER_VALUE = 0.1;
     private static final int INT_VALUE = 10;
+    private static final int INT_VALUE_2 = 20;
     private static final String STRING_VALUE = "test";
+    private static final boolean[] BOOLEAN_ARRAY_VALUE = new boolean[]{true, false, true};
     private static final int[] INT_ARRAY_VALUE = new int[]{1, 2, 3};
     private static final long[] LONG_ARRAY_VALUE = new long[]{1, 2, 3, 4};
     private static final double[] DOUBLE_ARRAY_VALUE = new double[]{1.1d, 2.2d, 3.3d, 4.4d};
+    private static final PersistableBundle PERSISTABLE_BUNDLE_VALUE = new PersistableBundle();
 
     // Pointer to Lua Engine instantiated in native space.
     private long mLuaEnginePtr = 0;
@@ -68,6 +76,10 @@
     private native void nativePushBundleToLuaTableCaller(
             long luaEnginePtr, PersistableBundle bundle);
 
+    // Invokes pushBundleListToLuaTable native method.
+    private native void nativePushBundleListToLuaTableCaller(
+            long luaEnginePtr, List<PersistableBundle> bundleList);
+
     // Creates an instance of LuaEngine on the heap and returns the pointer.
     private native long nativeCreateLuaEngine();
 
@@ -87,6 +99,9 @@
 
     private native boolean nativeHasIntValue(long luaEnginePtr, String key, int value);
 
+    private native boolean nativeHasBooleanArrayValue(
+            long luaEnginePtr, String key, boolean[] value);
+
     private native boolean nativeHasDoubleValue(long luaEnginePtr, String key, double value);
 
     private native boolean nativeHasIntArrayValue(long luaEnginePtr, String key, int[] value);
@@ -95,6 +110,18 @@
 
     private native boolean nativeHasDoubleArrayValue(long luaEnginePtr, String key, double[] value);
 
+    /*
+     * Checks if the key maps to a Lua table/PersistableBundle, and checks if the PersistableBundle
+     * has the string representation equal to the parameter {@code expected}.
+     */
+    private native boolean nativeHasPersistableBundleOfStringValue(
+            long luaEnginePtr, String key, String expected);
+
+    private native boolean nativeHasNumberOfTables(long luaEnginePtr, int num);
+
+    private native boolean nativeHasTableAtIndexWithIntValue(
+            long luaEnginePtr, int index, String key, int value);
+
     @Test
     public void pushBundleToLuaTable_nullBundleMakesEmptyLuaTable() {
         nativePushBundleToLuaTableCaller(mLuaEnginePtr, null);
@@ -110,6 +137,7 @@
         bundle.putInt(INT_KEY, INT_VALUE);
         bundle.putDouble(NUMBER_KEY, NUMBER_VALUE);
         bundle.putString(STRING_KEY, STRING_VALUE);
+        bundle.putPersistableBundle(PERSISTABLE_BUNDLE_KEY, PERSISTABLE_BUNDLE_VALUE);
 
         // Invokes the corresponding helper method to convert the bundle
         // to Lua table on Lua stack.
@@ -120,6 +148,8 @@
         assertThat(nativeHasIntValue(mLuaEnginePtr, INT_KEY, INT_VALUE)).isTrue();
         assertThat(nativeHasDoubleValue(mLuaEnginePtr, NUMBER_KEY, NUMBER_VALUE)).isTrue();
         assertThat(nativeHasStringValue(mLuaEnginePtr, STRING_KEY, STRING_VALUE)).isTrue();
+        assertThat(nativeHasPersistableBundleOfStringValue(mLuaEnginePtr, PERSISTABLE_BUNDLE_KEY,
+                PERSISTABLE_BUNDLE_VALUE.toString())).isTrue();
     }
 
     @Test
@@ -138,6 +168,7 @@
     @Test
     public void pushBundleToLuaTable_arrays() {
         PersistableBundle bundle = new PersistableBundle();
+        bundle.putBooleanArray(BOOLEAN_ARRAY_KEY, BOOLEAN_ARRAY_VALUE);
         bundle.putIntArray(INT_ARRAY_KEY, INT_ARRAY_VALUE);
         bundle.putLongArray(LONG_ARRAY_KEY, LONG_ARRAY_VALUE);
         bundle.putDoubleArray(DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE);
@@ -149,11 +180,50 @@
         // Check contents of Lua table.
         // Java int and long arrays both end up being arrays of Lua's Integer type,
         // which is interpreted as a 8-byte int type.
+        assertThat(nativeHasBooleanArrayValue(
+                mLuaEnginePtr, BOOLEAN_ARRAY_KEY, BOOLEAN_ARRAY_VALUE)).isTrue();
         assertThat(nativeHasIntArrayValue(mLuaEnginePtr, INT_ARRAY_KEY, INT_ARRAY_VALUE)).isTrue();
-        assertThat(
-                nativeHasLongArrayValue(mLuaEnginePtr, LONG_ARRAY_KEY, LONG_ARRAY_VALUE)).isTrue();
-        assertThat(
-                nativeHasDoubleArrayValue(mLuaEnginePtr, DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE))
+        assertThat(nativeHasLongArrayValue(mLuaEnginePtr, LONG_ARRAY_KEY, LONG_ARRAY_VALUE))
                 .isTrue();
+        assertThat(nativeHasDoubleArrayValue(mLuaEnginePtr, DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE))
+                .isTrue();
+    }
+
+    @Test
+    public void pushBundleListToLuaTable_makesArrayOfTables() {
+        PersistableBundle bundle1 = new PersistableBundle();
+        PersistableBundle bundle2 = new PersistableBundle();
+        bundle1.putInt(INT_KEY, INT_VALUE);
+        bundle2.putInt(INT_KEY, INT_VALUE_2);
+        List<PersistableBundle> bundleList = new ArrayList<>();
+        bundleList.add(bundle1);
+        bundleList.add(bundle2);
+
+        nativePushBundleListToLuaTableCaller(mLuaEnginePtr, bundleList);
+
+        assertThat(nativeHasNumberOfTables(mLuaEnginePtr, 2)).isTrue();
+        assertThat(nativeHasTableAtIndexWithIntValue(mLuaEnginePtr, 1, INT_KEY, INT_VALUE))
+                .isTrue();
+        assertThat(nativeHasTableAtIndexWithIntValue(mLuaEnginePtr, 2, INT_KEY, INT_VALUE_2))
+                .isTrue();
+    }
+
+    @Test
+    public void pushBundleToLuaTable_nestedBundle() {
+        PersistableBundle bundle = new PersistableBundle();
+        PersistableBundle nestedBundle = new PersistableBundle();
+        nestedBundle.putInt(INT_KEY, INT_VALUE);
+        nestedBundle.putDouble(NUMBER_KEY, NUMBER_VALUE);
+        nestedBundle.putString(STRING_KEY, STRING_VALUE);
+        nestedBundle.putPersistableBundle(PERSISTABLE_BUNDLE_KEY, PERSISTABLE_BUNDLE_VALUE);
+        bundle.putPersistableBundle(PERSISTABLE_BUNDLE_KEY, nestedBundle);
+
+        // Invokes the corresponding helper method to convert the bundle
+        // to Lua table on Lua stack.
+        nativePushBundleToLuaTableCaller(mLuaEnginePtr, bundle);
+
+        // Check contents of Lua table/PersistableBundle.
+        assertThat(nativeHasPersistableBundleOfStringValue(
+                mLuaEnginePtr, PERSISTABLE_BUNDLE_KEY, nestedBundle.toString())).isTrue();
     }
 }
diff --git a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
index 11ae637..5597e50 100644
--- a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
+++ b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#include "BundleWrapper.h"
 #include "JniUtils.h"
 #include "LuaEngine.h"
 #include "jni.h"
+#include "nativehelper/scoped_local_ref.h"
 
 #include <cstdint>
 #include <cstring>
@@ -70,6 +72,44 @@
     return result;
 }
 
+template <typename T>
+bool hasValidBooleanArray(JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key,
+                          T rawInputArray, const int arrayLength) {
+    const char* rawKey = env->GetStringUTFChars(key, nullptr);
+    scriptexecutor::LuaEngine* engine =
+            reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+    // Assumes the table is on top of the stack.
+    auto* luaState = engine->getLuaState();
+    lua_pushstring(luaState, rawKey);
+    env->ReleaseStringUTFChars(key, rawKey);
+    lua_gettable(luaState, -2);
+    bool result = false;
+    if (!lua_istable(luaState, -1)) {
+        result = false;
+    } else {
+        // First, compare the input and Lua array sizes.
+        const auto kActualLength = lua_rawlen(luaState, -1);
+        if (arrayLength != kActualLength) {
+            // No need to compare further if number of elements in the two arrays are not equal.
+            result = false;
+        } else {
+            // Do element by element comparison.
+            bool is_equal = true;
+            for (int i = 0; i < arrayLength; ++i) {
+                lua_rawgeti(luaState, -1, i + 1);
+                is_equal = lua_isboolean(luaState, /* idx = */ -1) &&
+                        lua_toboolean(luaState, /* idx = */ -1) ==
+                                static_cast<bool>(rawInputArray[i]);
+                lua_pop(luaState, 1);
+                if (!is_equal) break;
+            }
+            result = is_equal;
+        }
+    }
+    lua_pop(luaState, 1);
+    return result;
+}
+
 extern "C" {
 
 #include "lua.h"
@@ -95,6 +135,14 @@
     scriptexecutor::pushBundleToLuaTable(env, engine->getLuaState(), bundle);
 }
 
+JNIEXPORT void JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativePushBundleListToLuaTableCaller(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jobject bundleList) {
+    scriptexecutor::LuaEngine* engine =
+            reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+    scriptexecutor::pushBundleListToLuaTable(env, engine->getLuaState(), bundleList);
+}
+
 JNIEXPORT jint JNICALL
 Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeGetObjectSize(JNIEnv* env,
                                                                               jobject object,
@@ -188,6 +236,16 @@
 }
 
 JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasBooleanArrayValue(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jbooleanArray value) {
+    jboolean* rawInputArray = env->GetBooleanArrayElements(value, nullptr);
+    const auto kInputLength = env->GetArrayLength(value);
+    bool result = hasValidBooleanArray(env, object, luaEnginePtr, key, rawInputArray, kInputLength);
+    env->ReleaseBooleanArrayElements(value, rawInputArray, JNI_ABORT);
+    return result;
+}
+
+JNIEXPORT bool JNICALL
 Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasIntArrayValue(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jintArray value) {
     jint* rawInputArray = env->GetIntArrayElements(value, nullptr);
@@ -220,6 +278,85 @@
     return result;
 }
 
+JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasNumberOfTables(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jint num) {
+    scriptexecutor::LuaEngine* engine =
+            reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+    auto* luaState = engine->getLuaState();
+    bool result = true;
+    for (int i = 1; i <= num; i++) {
+        lua_pushinteger(luaState, i);
+        lua_gettable(luaState, -2);
+        if (!lua_istable(luaState, -1)) {
+            result = false;
+        }
+        lua_pop(luaState, 1);
+    }
+    return result;
+}
+
+JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasTableAtIndexWithIntValue(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jint index, jstring key, jint value) {
+    const char* rawKey = env->GetStringUTFChars(key, nullptr);
+    scriptexecutor::LuaEngine* engine =
+            reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+    // Assumes the table is on top of the stack.
+    auto* luaState = engine->getLuaState();
+    lua_pushinteger(luaState, index);
+    lua_gettable(luaState, -2);
+    lua_pushstring(luaState, rawKey);
+    env->ReleaseStringUTFChars(key, rawKey);
+    lua_gettable(luaState, -2);
+    bool result = false;
+    if (!lua_isinteger(luaState, -1))
+        result = false;
+    else
+        result = lua_tointeger(luaState, -1) == static_cast<int>(value);
+    lua_pop(luaState, 2);
+    return result;
+}
+
+JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasPersistableBundleOfStringValue(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jstring expected) {
+    const char* rawKey = env->GetStringUTFChars(key, nullptr);
+    scriptexecutor::LuaEngine* engine =
+            reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+    // Assumes the table is on top of the stack.
+    auto* luaState = engine->getLuaState();
+    lua_pushstring(luaState, rawKey);
+    lua_gettable(luaState, -2);
+    // check if the key maps to a value of type table
+    if (!lua_istable(luaState, -1)) {
+        return false;
+    }
+    // convert value (a table) into a PersistableBundle
+    scriptexecutor::BundleWrapper bundleWrapper(env);
+    scriptexecutor::convertLuaTableToBundle(env, luaState, &bundleWrapper);
+    // call PersistableBundle#toString() to compare the string representation with the expected
+    // representation
+    ScopedLocalRef<jclass> persistableBundleClass(env,
+                                                  env->FindClass("android/os/PersistableBundle"));
+    jmethodID toStringMethod =
+            env->GetMethodID(persistableBundleClass.get(), "toString", "()Ljava/lang/String;");
+    ScopedLocalRef<jstring> actual(env,
+                                   (jstring)env->CallObjectMethod(bundleWrapper.getBundle(),
+                                                                  toStringMethod));
+    // convert jstring into c string
+    const char* nativeActualString = env->GetStringUTFChars(actual.get(), nullptr);
+    const char* nativeExpectedString = env->GetStringUTFChars(expected, nullptr);
+
+    // compare actual vs expected
+    int res = strncmp(nativeActualString, nativeExpectedString, strlen(nativeActualString));
+
+    env->ReleaseStringUTFChars(key, rawKey);
+    env->ReleaseStringUTFChars(actual.get(), nativeActualString);
+    env->ReleaseStringUTFChars(expected, nativeExpectedString);
+    return res == 0;
+}
+
 }  //  extern "C"
 
 }  // namespace
diff --git a/service-builtin/res/values/strings.xml b/service-builtin/res/values/strings.xml
index e15b970..4ac5e18 100644
--- a/service-builtin/res/values/strings.xml
+++ b/service-builtin/res/values/strings.xml
@@ -80,17 +80,11 @@
     <!-- Title of notification shown when an app overuses system resources [CHAR LIMIT=100] -->
     <string name="resource_overuse_notification_title"><xliff:g name="app_name" example="Maps">^1</xliff:g> is affecting your system performance</string>
     <!-- Message of notification shown when an app overuses system resources [CHAR LIMIT=NONE] -->
-    <string name="resource_overuse_notification_text_disable_app">Disable app to improve system performance. You can enable the app once again in Settings.</string>
-    <!-- Message of notification shown when an app overuses system resources [CHAR LIMIT=NONE] -->
-    <string name="resource_overuse_notification_text_prioritize_app">Prioritize app to keep using app.</string>
-    <!-- Message of notification shown when an app overuses system resources [CHAR LIMIT=NONE] -->
-    <string name="resource_overuse_notification_text_uninstall_app">Uninstall app to improve system performance.</string>
+    <string name="resource_overuse_notification_text_disabled_app">This app has been prevented from running in the background. Prioritize app to continue background usage.</string>
     <!-- Label for button that will disable the app now [CHAR LIMIT=30] -->
-    <string name="resource_overuse_notification_button_disable_app">Disable app</string>
+    <string name="resource_overuse_notification_button_close_app">Close</string>
     <!-- Label for button that will redirect user to prioritize app setting [CHAR LIMIT=30] -->
     <string name="resource_overuse_notification_button_prioritize_app">Prioritize app</string>
-    <!-- Label for button that will redirect user to uninstall app setting [CHAR LIMIT=30] -->
-    <string name="resource_overuse_notification_button_uninstall_app">Uninstall app</string>
     <!-- Text of the toast shown when the app is disabled [CHAR_LIMIT=100]-->
     <string name="resource_overuse_toast_disable_app_now"><xliff:g name="app_name" example="Maps">^1</xliff:g> has been disabled. You can enable it again in Settings.</string>
 </resources>
diff --git a/service-builtin/src/com/android/car/CarService.java b/service-builtin/src/com/android/car/CarService.java
index 30f57b9..42c3636 100644
--- a/service-builtin/src/com/android/car/CarService.java
+++ b/service-builtin/src/com/android/car/CarService.java
@@ -18,10 +18,19 @@
 
 import android.content.Intent;
 
+import com.android.internal.os.BinderInternal;
+
 /** Proxy service for CarServciceImpl */
 public class CarService extends ServiceProxy {
+
+    // Binder threads are set to 31. system_server is also using 31.
+    // check sMaxBinderThreads in SystemServer.java
+    private  static final int MAX_BINDER_THREADS = 31;
+
     public CarService() {
         super(UpdatablePackageDependency.CAR_SERVICE_IMPL_CLASS);
+        // Increase the number of binder threads in car service
+        BinderInternal.setMaxThreads(MAX_BINDER_THREADS);
     }
 
     @Override
diff --git a/service-builtin/src/com/android/car/admin/NotificationHelper.java b/service-builtin/src/com/android/car/admin/NotificationHelper.java
index 9521cad..54a802b 100644
--- a/service-builtin/src/com/android/car/admin/NotificationHelper.java
+++ b/service-builtin/src/com/android/car/admin/NotificationHelper.java
@@ -59,8 +59,6 @@
             "com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION";
     public static final String CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS =
             "com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS";
-    public static final String CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP =
-            "com.android.car.watchdog.ACTION_RESOURCE_OVERUSE_DISABLE_APP";
     public static final String CAR_SERVICE_PACKAGE_NAME = "com.android.car";
     @VisibleForTesting
     public static final String CHANNEL_ID_DEFAULT = "channel_id_default";
@@ -229,20 +227,12 @@
                 context.getSystemService(NotificationManager.class);
 
         CharSequence titleTemplate = context.getText(R.string.resource_overuse_notification_title);
-        String textPrioritizeApp =
-                context.getString(R.string.resource_overuse_notification_text_prioritize_app);
-        String textDisableApp =
-                context.getString(R.string.resource_overuse_notification_text_disable_app) + " "
-                        + textPrioritizeApp;
-        String textUninstallApp =
-                context.getString(R.string.resource_overuse_notification_text_uninstall_app) + " "
-                        + textPrioritizeApp;
+        String textDisabledApp =
+                context.getString(R.string.resource_overuse_notification_text_disabled_app);
         String actionTitlePrioritizeApp =
                 context.getString(R.string.resource_overuse_notification_button_prioritize_app);
-        String actionTitleDisableApp =
-                context.getString(R.string.resource_overuse_notification_button_disable_app);
-        String actionTitleUninstallApp =
-                context.getString(R.string.resource_overuse_notification_button_uninstall_app);
+        String actionTitleCloseNotification =
+                context.getString(R.string.resource_overuse_notification_button_close_app);
 
         for (int i = 0; i < packagesByImportance.size(); i++) {
             int importance = packagesByImportance.keyAt(i);
@@ -250,46 +240,32 @@
             for (int pkgIdx = 0; pkgIdx < packagesById.size(); pkgIdx++) {
                 int notificationId = packagesById.keyAt(pkgIdx);
                 String packageName = packagesById.valueAt(pkgIdx);
-                String text = textUninstallApp;
-                String negativeActionText = actionTitleUninstallApp;
 
                 CharSequence appName;
-                PendingIntent positiveActionPendingIntent;
-                PendingIntent negativeActionPendingIntent;
                 try {
                     ApplicationInfo info = packageManager.getApplicationInfoAsUser(packageName,
                             /* flags= */ 0, user);
                     appName = info.loadLabel(packageManager);
-                    negativeActionPendingIntent = positiveActionPendingIntent =
-                            getPendingIntent(context, CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS, user,
-                                    packageName, notificationId);
-                    // Apps with SYSTEM flag are considered bundled apps by car settings and
-                    // bundled apps have disable button rather than uninstall button.
-                    if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        text = textDisableApp;
-                        negativeActionText = actionTitleDisableApp;
-                        negativeActionPendingIntent = getPendingIntent(context,
-                                CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP, user, packageName,
-                                notificationId);
-                    }
                 } catch (PackageManager.NameNotFoundException e) {
                     Slogf.e(TAG, e, "Package '%s' not found for user %s", packageName, user);
                     continue;
                 }
-                PendingIntent deletePendingIntent = getPendingIntent(context,
+                PendingIntent negativeActionPendingIntent = getPendingIntent(context,
                         CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION, user,
                         packageName, notificationId);
+                PendingIntent positiveActionPendingIntent = getPendingIntent(context,
+                        CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS, user, packageName, notificationId);
                 Notification notification = NotificationHelper
                         .newNotificationBuilder(context, importance)
                         .setSmallIcon(R.drawable.car_ic_warning)
                         .setContentTitle(TextUtils.expandTemplate(titleTemplate, appName))
-                        .setContentText(text)
+                        .setContentText(textDisabledApp)
                         .setCategory(Notification.CATEGORY_CAR_WARNING)
                         .addAction(new Notification.Action.Builder(/* icon= */ null,
-                                actionTitlePrioritizeApp, positiveActionPendingIntent).build())
+                                actionTitleCloseNotification, negativeActionPendingIntent).build())
                         .addAction(new Notification.Action.Builder(/* icon= */ null,
-                                negativeActionText, negativeActionPendingIntent).build())
-                        .setDeleteIntent(deletePendingIntent)
+                                actionTitlePrioritizeApp, positiveActionPendingIntent).build())
+                        .setDeleteIntent(negativeActionPendingIntent)
                         .build();
 
                 notificationManager.notifyAsUser(TAG, notificationId, notification, user);
@@ -300,8 +276,8 @@
                                     + "user %s.\nNotification { App name: %s, Importance: %d, "
                                     + "Description: %s, Positive button text: %s, Negative button "
                                     + "text: %s }",
-                            notificationId, user, appName, importance, text,
-                            actionTitlePrioritizeApp, negativeActionText);
+                            notificationId, user, appName, importance, textDisabledApp,
+                            actionTitleCloseNotification, actionTitlePrioritizeApp);
                 }
             }
         }
diff --git a/service/Android.bp b/service/Android.bp
index c84c874..23a82a3 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -195,6 +195,7 @@
 filegroup {
     name: "iscriptexecutor_aidl",
     srcs: [
+        "src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl",
         "src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl",
         "src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutorListener.aidl",
     ],
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 1752eab..f763860 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -50,6 +50,14 @@
                 android:label="@string/car_permission_label_control_car_energy"
                 android:description="@string/car_permission_desc_control_car_energy"/>
 
+    <!-- Allows CarService to connect to OEM CarService.
+         <p>Protection level: signature|privileged
+    -->
+    <permission android:name="android.car.permission.BIND_OEM_CAR_SERVICE"
+                android:protectionLevel="signature|privileged"
+                android:label="@string/car_permission_label_bind_oem_car_service"
+                android:description="@string/car_permission_desc_bind_oem_car_service"/>
+
     <!-- Allows an application to adjust the vehicle's range remaining information.
          <p>Protection level: signature|privileged
     -->
diff --git a/service/jni/evs/EvsServiceContext.cpp b/service/jni/evs/EvsServiceContext.cpp
index e3d7220..ff6f7ae 100644
--- a/service/jni/evs/EvsServiceContext.cpp
+++ b/service/jni/evs/EvsServiceContext.cpp
@@ -179,7 +179,8 @@
             mCarEvsServiceObj = env->NewGlobalRef(thiz);
         }
 
-        // Reset a EvsDisplay handle
+        // Reset a stored camera id and a display handle
+        mCameraIdInUse.clear();
         mDisplay = nullptr;
     }
 
@@ -273,6 +274,10 @@
             LOG(WARNING) << "Failed to close a current camera device.";
         }
     }
+
+    // Reset a camera reference and id in use.
+    mCamera.reset();
+    mCameraIdInUse.clear();
 }
 
 bool EvsServiceContext::startVideoStream() {
@@ -429,6 +434,7 @@
             mService = nullptr;
             mStreamHandler = nullptr;
             mBufferRecords.clear();
+            mCameraIdInUse.clear();
         }
 
         LOG(ERROR) << "The native EVS service has died.";
diff --git a/service/jni/evs/EvsServiceContext.h b/service/jni/evs/EvsServiceContext.h
index 87966d1..38e1b5e 100644
--- a/service/jni/evs/EvsServiceContext.h
+++ b/service/jni/evs/EvsServiceContext.h
@@ -160,7 +160,7 @@
     std::set<int> mBufferRecords GUARDED_BY(mLock);
 
     // A name of the camera device currently in use.
-    std::string_view mCameraIdInUse;
+    std::string mCameraIdInUse;
 
     // List of available camera devices
     std::vector<::aidl::android::hardware::automotive::evs::CameraDesc> mCameraList;
diff --git a/service/proto/android/car/telemetry/atoms.proto b/service/proto/android/car/telemetry/atoms.proto
index 4aad716..cd504f1 100644
--- a/service/proto/android/car/telemetry/atoms.proto
+++ b/service/proto/android/car/telemetry/atoms.proto
@@ -37,6 +37,7 @@
   oneof pulled {
     ProcessMemoryState process_memory_state = 10013;
     ProcessCpuTime process_cpu_time = 10035;
+    ProcessMemorySnapshot process_memory_snapshot = 10064;
   }
 }
 
@@ -167,6 +168,19 @@
   optional ErrorSource error_source = 5;
 }
 
+message ProcessMemorySnapshot {
+  optional int32 uid = 1;
+  optional string process_name = 2;
+  optional int32 pid = 3;
+  optional int32 oom_score_adj = 4;
+  optional int32 rss_in_kilobytes = 5;
+  optional int32 anon_rss_in_kilobytes = 6;
+  optional int32 swap_in_kilobytes = 7;
+  optional int32 anon_rss_and_swap_in_kilobytes = 8;
+  optional int32 gpu_memory_kb = 9;
+  optional bool has_foreground_services = 10;
+}
+
 message CarPowerStateChanged {
   enum State {
     WAIT_FOR_VHAL = 0;
diff --git a/service/res/values-af/strings.xml b/service/res/values-af/strings.xml
index 5bd0506..f2fe643 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Lewer template."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"beheer die oopmaak van programme"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Beheer die oopmaak van programme."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"bestuur draadprioriteit"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Bestuur draadprioriteit."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus het misluk"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus reageer nie. Ontprop hoofeenheidkas, prop dit weer in, en herbegin die motor"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Toestel"</string>
diff --git a/service/res/values-am/strings.xml b/service/res/values-am/strings.xml
index 39ad921..e7c95ca 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"የቅንብር ደንቦችን ምስል ሥራ።"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"መተግበሪያዎችን ማስጀመር መቆጣጠር"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"መተግበሪያዎችን ማስጀመር መቆጣጠር።"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"የተከታታይ ቅድሚያን ያስተዳድሩ"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"የተከታታይ ቅድሚያን ያስተዳድሩ።"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN አውቶብስ አልተሳካም"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN አውቶብስ ምላሽ አይሰጥም። የጭንቅላት አሃድ መያዣ ሳጥኑን ይሰኩ እና ይንቀሉ በመቀጠል መኪናውን ዳግም ያስጀምሩ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"የእኔ መሣሪያ"</string>
diff --git a/service/res/values-ar/strings.xml b/service/res/values-ar/strings.xml
index b742435..a1a5c22 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -62,11 +62,11 @@
     <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"الانتباه إلى تغييرات حالة التنقل على شاشة مجموعة العدادات"</string>
     <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"ضبط قيود تجربة المستخدم"</string>
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ضبط قيود تجربة المُستخدِم"</string>
-    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"الإذن بالاطّلاع على معرّف الشاشة الخاص"</string>
+    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"إذن الوصول لقراءة معرّف الشاشة الخاص"</string>
     <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"يتيح إذن الوصول هذا قراءة معرّف الشاشة الخاص."</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"التواصل مع جهاز USB في وضع AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"يتيح للتطبيق التواصل مع جهاز في وضع AOAP."</string>
-    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"الإذن بالاطّلاع على Occupant Awareness System"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"الوصول لقراءة Occupant Awareness System"</string>
     <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"السماح بقراءة حالة Occupant Awareness System وبيانات التعرف عليه"</string>
     <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"التحكّم في الرسم البياني لنظام Occupant Awareness System"</string>
     <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"السماح بالتحكّم في بدء وإيقاف الرسم البياني للتعرف على Occupant Awareness System"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"عرض النماذج"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"التحكم في تشغيل التطبيقات"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"التحكم في تشغيل التطبيقات"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"إدارة أولوية سلسلة المحادثات"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"يمكنك إدارة أولوية سلسلة المحادثات."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"حدث خطأ في موصّل CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"لا استجابة من موصّل CAN. يمكنك فصل صندوق وحدة الرأس وإعادة تشغيل السيارة."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"جهازي"</string>
diff --git a/service/res/values-as/strings.xml b/service/res/values-as/strings.xml
index b8b0f47..f567a47 100644
--- a/service/res/values-as/strings.xml
+++ b/service/res/values-as/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"টেমপ্লে’ট প্ৰদান কৰক।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"এপ্লিকেশ্বন লঞ্চ হোৱাটো নিয়ন্ত্ৰণ কৰে"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"এপ্লিকেশ্বন লঞ্চ হোৱাটো নিয়ন্ত্ৰণ কৰে।"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"থ্ৰেডৰ অগ্ৰাধিকাৰ পৰিচালনা কৰক"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"থ্ৰেডৰ অগ্ৰাধিকাৰ পৰিচালনা কৰক।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাছ বিফল হৈছে"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN বাছে সঁহাৰি দিয়া নাই। হে’ড ইউনিট বাকচটো আঁতৰাই পুনৰ লগাওক"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"মোৰ ডিভাইচ"</string>
diff --git a/service/res/values-az/strings.xml b/service/res/values-az/strings.xml
index 0252fab..f872fb3 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Şablonları vizualizasiya edin."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"tətbiqlərin başladılmasına nəzarət"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Tətbiqlərin başladılmasına nəzarət."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mövzu prioritetini idarə edin"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mövzu prioritetini idarə edin."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN idarəetmə mexanizmi uğursuz oldu"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN mexanizmi cavab vermir. Əsas cihaz panelini ayırın və yenidən qoşun, sonra avtomobili yenidən işə salın"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
diff --git a/service/res/values-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index d4b970c..b2969e9 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Prikazivanje šablona."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrola pokretanja aplikacija"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontroliše pokretanje aplikacija."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN magistrale"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN magistrala ne reaguje. Isključite i ponovo uključite glavnu jedinicu i ponovo pokrenite automobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-be/strings.xml b/service/res/values-be/strings.xml
index c964195..2e6f2ad 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Візуалізацыя шаблонаў."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"кіраванне запускам праграм"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Кіраванне запускам праграм."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"кіраваць прыярытэтам патокаў"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Кіраваць прыярытэтам патокаў."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-шына парушана"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-шына не адказвае. Перападключыце канектар, а затым выключыце запальванне і паўторна завядзіце аўтамабіль"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мая прылада"</string>
diff --git a/service/res/values-bg/strings.xml b/service/res/values-bg/strings.xml
index 5726b7c..15031e5 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Рендериране на шаблони."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"управление на приложенията, които се стартират"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Управление на приложенията, които се стартират."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управление на приоритета на нишката"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управление на приоритета на нишката."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка в CAN шината"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN шината не реагира. Изключете и включете отново захранването на основното устройство и рестартирайте автомобила"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Моето устройство"</string>
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index bd477db..6b3413c 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"টেম্পলেট রেন্ডার করুন।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"অ্যাপ্লিকেশন চালু করা প্রক্রিয়া নিয়ন্ত্রণ করুন"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"অ্যাপ্লিকেশন চালু করা প্রক্রিয়া নিয়ন্ত্রণ করুন।"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"থ্রেডের অগ্রাধিকার ম্যানেজ করুন"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"থ্রেডের অগ্রাধিকার ম্যানেজ করুন।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাস কাজ করছে না"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN বাস কাজ করছে না। হেডইউনিট বক্স খুলে নিয়ে আবার লাগান ও গাড়ি রিস্টার্ট করুন"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"আমার ডিভাইস"</string>
diff --git a/service/res/values-bs/strings.xml b/service/res/values-bs/strings.xml
index b9bf4cf..ef200fb 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Iscrtavanje šablona."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"upravljanje pokretanjem aplikacija"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Upravljanje pokretanjem aplikacija."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN busa"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ne reagira. Isključite i ponovo uključite glavnu jedinicu i ponovo pokrenite automobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-ca/strings.xml b/service/res/values-ca/strings.xml
index 6ed24e3..535dc5d 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderitzar plantilles."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla l\'inici de les aplicacions"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla l\'inici de les aplicacions."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestiona la prioritat de les converses"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestiona la prioritat de les converses."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Ha fallat el bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"El bus CAN no respon. Desendolla i torna a endollar el capçal i torna a engegar el cotxe."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"El meu dispositiu"</string>
diff --git a/service/res/values-cs/strings.xml b/service/res/values-cs/strings.xml
index 42c5f7a..5bb1d08 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vykreslování šablon."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ovládání spouštěných aplikací"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ovládání spouštěných aplikací."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"správa priority vlákna"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Správa priority vlákna."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Sběrnice CAN selhala"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Sběrnice CAN neodpovídá. Odpojte a opět zapojte autorádio a znovu nastartujte auto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje zařízení"</string>
diff --git a/service/res/values-da/strings.xml b/service/res/values-da/strings.xml
index edd9fb0..3752122 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Gengive skabeloner."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"styre startapps"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Styre startapps."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrer trådprioritet"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administrer trådprioritet."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus (Controller Area Network) mislykkedes"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus (Controller Area Network) svarer ikke. Afbryd forbindelsen til bilens hovedenhed, tilslut den igen, og genstart bilen"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Min enhed"</string>
diff --git a/service/res/values-de/strings.xml b/service/res/values-de/strings.xml
index ec03139..0f0d4d7 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_permission_label" msgid="2215078736675564541">"Fahrzeug­­informationen"</string>
+    <string name="car_permission_label" msgid="2215078736675564541">"Fahrzeug­informationen"</string>
     <string name="car_permission_desc" msgid="3584369074931334964">"Zugriff auf Informationen deines Autos"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"auf die Autokamera zuzugreifen"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Auf Autokamera(s) zugreifen."</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vorlagen werden gerendert."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"Der Start von Anwendungen wird gesteuert"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Der Start von Anwendungen wird gesteuert."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"Thread-Priorität verwalten"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Thread-Priorität verwalten."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-Bus ausgefallen"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-Bus reagiert nicht. Trenne die Haupteinheit vom Stromnetz, schließe sie wieder an und starte das Auto."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mein Gerät"</string>
diff --git a/service/res/values-el/strings.xml b/service/res/values-el/strings.xml
index 617fe62..84f8a50 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Να αποδίδει πρότυπα."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"έλεγχος εφαρμογών εκκίνησης"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Έλεγχος εφαρμογών εκκίνησης."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"διαχείριση προτεραιότητας νημάτων"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Διαχείριση προτεραιότητας νημάτων."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Αποτυχία διαύλου CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Ο δίαυλος CAN δεν αποκρίνεται. Αποσυνδέστε και συνδέστε ξανά το πλαίσιο μονάδας κεφαλής και έπειτα επανεκκινήστε το αυτοκίνητο"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Η συσκευή μου"</string>
diff --git a/service/res/values-en-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index 3dff490..ef982fb 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index 39fa611..ef982fb 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -27,7 +27,7 @@
     <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"adjust car’s range remaining"</string>
     <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Adjust car’s range remaining value."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"access car’s hvac"</string>
-    <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s hvac."</string>
+    <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s HVAC."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"access car’s mileage information"</string>
     <string name="car_permission_desc_mileage" msgid="7179735693278681090">"Access your car’s mileage information."</string>
     <string name="car_permission_label_speed" msgid="1149027717860529745">"read car’s speed"</string>
@@ -52,7 +52,7 @@
     <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Control your car’s audio settings."</string>
     <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Application blocking"</string>
     <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Control application blocking while driving."</string>
-    <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Navigation Manager"</string>
+    <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Navigation manager"</string>
     <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Report navigation data to instrument cluster"</string>
     <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Direct rendering to instrument cluster"</string>
     <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Allow an application to declare activities to be displayed in the instrument cluster"</string>
@@ -60,16 +60,16 @@
     <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
     <string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
     <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
-    <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX Restrictions Configuration"</string>
-    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX Restrictions"</string>
-    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display id"</string>
-    <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Allows read access to private display id"</string>
+    <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX restrictions configuration"</string>
+    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
+    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display ID"</string>
+    <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Allows read access to private display ID"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communicate with USB device in AOAP mode"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Allows an app to communicate with a device in AOAP mode"</string>
-    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System Read Access"</string>
-    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for Occupant Awareness System"</string>
-    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control Occupant Awareness System Graph"</string>
-    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stopping of the Occupant Awareness System detection graph"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant awareness system read access"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
     <string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
     <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
     <string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -81,15 +81,15 @@
     <string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
     <string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
-    <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to Driving state changes."</string>
-    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Use Car Telemetry Service"</string>
+    <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to driving state changes."</string>
+    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Use car telemetry service"</string>
     <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Collect car system health data."</string>
-    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Use Car EVS Service"</string>
+    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Use car EVS service"</string>
     <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Subscribe to EVS video streams"</string>
     <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Request the EVS preview activity"</string>
     <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Request the system to launch the EVS preview activity"</string>
     <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Control the EVS preview activity"</string>
-    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Control the EVS preview activity of the sytsem"</string>
+    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Control the EVS preview activity of the system"</string>
     <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Use the EVS camera"</string>
     <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Subscribe to EVS camera streams"</string>
     <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitor the status of the EVS service"</string>
@@ -131,7 +131,7 @@
     <string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"read car’s exterior temperature"</string>
     <string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Access car’s exterior temperature."</string>
     <string name="car_permission_label_car_tires" msgid="4379255261197836840">"access car’s tires information"</string>
-    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Access car’s tire information."</string>
+    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Access car’s tyre information."</string>
     <string name="car_permission_label_car_steering" msgid="7779530447441232479">"read car’s steering angle information"</string>
     <string name="car_permission_desc_car_steering" msgid="1357331844530708138">"Access car’s steering angle information."</string>
     <string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"read car display units"</string>
@@ -142,7 +142,7 @@
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Access car’s powertrain information."</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"read car’s power state"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"Access car’s power state."</string>
-    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Enroll Trusted Device"</string>
+    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Enrol Trusted Device"</string>
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Allow Trusted Device Enrollment"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Control car’s test mode"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Control car’s test mode"</string>
@@ -164,10 +164,8 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
-    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back headunit box and restart the car"</string>
+    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Guest"</string>
 </resources>
diff --git a/service/res/values-en-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index 3dff490..ef982fb 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index 3dff490..ef982fb 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
index 1dd1a7d..7be1b4c 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎Render templates.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎control launching applications‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎Control launching applications.‎‏‎‎‏‎"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎manage thread priority‎‏‎‎‏‎"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎Manage thread priority.‎‏‎‎‏‎"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎CAN bus failed‎‏‎‎‏‎"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎CAN bus does not respond. Unplug and plug back headunit box and restart the car‎‏‎‎‏‎"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎My Device‎‏‎‎‏‎"</string>
diff --git a/service/res/values-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index 7092d40..234fc95 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar plantillas"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla el inicio de las aplicaciones"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla el inicio de las aplicaciones."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrar prioridad de subprocesos"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administra la prioridad de subprocesos."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Error de bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus no responde. Desconecta y vuelve a conectar la caja de la unidad central y enciende nuevamente el auto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
diff --git a/service/res/values-es/strings.xml b/service/res/values-es/strings.xml
index 2956a34..4f84835 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_permission_label" msgid="2215078736675564541">"Información sobre el coche"</string>
+    <string name="car_permission_label" msgid="2215078736675564541">"información sobre el coche"</string>
     <string name="car_permission_desc" msgid="3584369074931334964">"acceder a los datos de tu coche"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"acceder a la cámara del coche"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Acceder a las cámaras del coche."</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar plantillas."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla las aplicaciones abiertas"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla las aplicaciones abiertas."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestionar la prioridad de las conversaciones"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestionar la prioridad de las conversaciones."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Fallo de bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"El bus CAN no responde. Desconecta el cabezal, conéctalo de nuevo y reinicia el coche"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
diff --git a/service/res/values-et/strings.xml b/service/res/values-et/strings.xml
index 0fc4de5..13e4a8c 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mallide renderdamine."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"rakenduste käivitamise juhtimine"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Rakenduste käivitamise juhtimine."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"saavad hallata ohu prioriteeti"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Ohu prioriteedi haldamine."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-siin ebaõnnestus"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-siin ei reageeri. Eemaldage autoraadio üksus ja pange see tagasi ning taaskäivitage auto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Minu seade"</string>
diff --git a/service/res/values-eu/strings.xml b/service/res/values-eu/strings.xml
index 6f4c9b6..e1c2346 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -38,10 +38,10 @@
     <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Atzitu auto-saltzailearen kanala autoari buruzko informazio zehatza trukatzeko."</string>
     <string name="car_permission_label_radio" msgid="6009465291685935112">"kudeatu autoaren irratia"</string>
     <string name="car_permission_desc_radio" msgid="3385999027478186964">"Atzitu autoaren irratia."</string>
-    <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoaren pantailan"</string>
-    <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoaren pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
+    <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoko pantailan"</string>
+    <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoko pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
     <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"atzitu proiekzio-egoera"</string>
-    <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoaren pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
+    <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoko pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
     <string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolatu autoaren audioaren bolumena"</string>
     <string name="car_permission_label_audio_settings" msgid="6524703796944023977">"kudeatu autoaren audio-ezarpenak"</string>
     <string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulatu autoaren hardware-abstrakzioaren geruza (HAL)"</string>
@@ -118,8 +118,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Atzitu autoaren saltzailearen baimenari buruzko informazioa"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"irakurri autoaren kanpoaldeko argien egoera"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Atzitu autoaren kanpoaldeko argien egoera."</string>
-    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"atzitu autoaren erreferentziazko denbora tartearen ordua"</string>
-    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Atzitu autoaren erreferentziazko denbora tartearen ordua."</string>
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"atzitu autoaren epoch ordua"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Atzitu autoaren epoch ordua."</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"atzitu autoaren enkriptazioa lotzeko hazia"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Atzitu autoaren enkriptazioa lotzeko hazia."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"irakurri autoaren kanpoaldeko argiak"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Errendatu txantiloiak."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrolatu abiarazteko aplikazioak"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrolatu abiarazteko aplikazioak."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"kudeatu elkarrizketa-harien lehentasuna"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Kudeatu elkarrizketa-harien lehentasuna."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN autobusak huts egin du"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus-ak ez du erantzuten. Desentxufatu eta entxufatu berriro gailu nagusia eta berrabiarazi autoa."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Nire gailua"</string>
diff --git a/service/res/values-fa/strings.xml b/service/res/values-fa/strings.xml
index e3d3fb0..3ab9659 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"پرداز زدن الگوها."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"کنترل راه‌اندازی برنامه‌ها"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"کنترل راه‌اندازی برنامه‌ها."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"مدیریت اولویت رشته"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"مدیریت اولویت رشته."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"گذرگاه CAN ناموفق بود"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"گذرگاه CAN پاسخ نمی‌دهد. محفظه ضبط‌وپخش را جدا و سپس وصل کنید و خودرو را دوباره روشن کنید"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"دستگاه من"</string>
diff --git a/service/res/values-fi/strings.xml b/service/res/values-fi/strings.xml
index f971a7d..6a12e4a 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderöi mallit."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"hallita sovellusten käynnistymistä"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"hallita sovellusten käynnistymistä."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"hallitsee ketjujen priorisointia"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Hallitsee ketjujen priorisointia."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-väylä hylättiin"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-väylä ei vastaa. Irrota pääyksikkö ja liitä se takaisin. Käynnistä auto sitten uudelleen."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Oma laite"</string>
diff --git a/service/res/values-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index 32aeca5..3e65de2 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Effectuer un rendu des modèles."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"contrôler le lancement d\'applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Contrôler le lancement d\'applications."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gérer la priorité du fil d\'exécution"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gérer la priorité du fil d\'exécution."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Défaillance du bus de données CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Le bus de données CAN ne répond pas. Débranchez et rebranchez le boîtier de l\'unité centrale, puis redémarrez la voiture"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index a29ef28..e2979c9 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Afficher les modèles."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"contrôler le lancement d\'applications."</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Contrôler le lancement d\'applications."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gérer la priorité des threads"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gérer la priorité des threads."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Échec du bus de données CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Le bus de données CAN ne répond pas. Débranchez et rebranchez le boîtier de l\'unité principale, puis redémarrez la voiture"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
diff --git a/service/res/values-gl/strings.xml b/service/res/values-gl/strings.xml
index 8ebfe66..25b2a3f 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -118,8 +118,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acceder á información sobre os permisos do vendedor do coche."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ler o estado das luces exteriores do dispositivo"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder ao estado das luces exteriores do coche."</string>
-    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao inicio do rexistro de tempo do coche"</string>
-    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao inicio do rexistro de tempo do coche."</string>
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao tempo epoch do coche"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao tempo epoch do coche."</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"acceder á semente de vinculación de encriptación do coche"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Acceder á semente de vinculación de encriptación do coche."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler as luces exteriores do coche"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Xerar modelos."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controlar o inicio de aplicacións"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlar o inicio de aplicacións."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"xestionar prioridade das conversas"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Xestionar prioridade das conversas."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Produciuse un erro no bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O bus CAN non responde. Desconecta a caixa da unidade principal, conéctaa de novo e reinicia o coche"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 9aaaacd..a41b9fc 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"નમૂના જનરેટ કરો."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"લૉન્ચિંગ ઍપ્લિકેશનો નિયંત્રિત કરો"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"લૉન્ચિંગ ઍપ્લિકેશનો નિયંત્રિત કરો."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"થ્રેડની પ્રાધાન્યતા મેનેજ કરો"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"થ્રેડની પ્રાધાન્યતા મેનેજ કરો."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN બસ નિષ્ફળ રહી"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN બસ પ્રતિસાદ આપતી નથી. હેડયુનિટ બોક્સને અનપ્લગ કરી ફરી પ્લગ કરો અને કારને ફરી શરૂ કરો"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"મારું ડિવાઇસ"</string>
diff --git a/service/res/values-hi/strings.xml b/service/res/values-hi/strings.xml
index 5c38a70..e457d73 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेंप्लेट बनाएं."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"लॉन्च किए जाने वाले ऐप्लिकेशन कंट्रोल करता है"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"लॉन्च किए जाने वाले ऐप्लिकेशन कंट्रोल करता है."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेड की प्राथमिकता मैनेज करने की अनुमति दें"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेड की प्राथमिकता मैनेज करने की अनुमति दें."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"\'CAN बस\' काम नहीं कर पा रहा है"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"\'CAN बस\' जवाब नहीं दे रहा है. हेडयूनिट बॉक्स का प्लग निकालकर वापस लगाएं और कार को रीस्टार्ट करें"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"मेरा डिवाइस"</string>
diff --git a/service/res/values-hr/strings.xml b/service/res/values-hr/strings.xml
index 780dc07..77b4a88 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Generirati predloške."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"upravljajte pokretanjem aplikacija"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Upravljajte pokretanjem aplikacija."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Pogreška CAN busa"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ne odgovara. Iskopčajte i ponovo ukopčajte glavnu jedinicu i ponovo pokrenite automobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-hu/strings.xml b/service/res/values-hu/strings.xml
index e5e462b..3285cfc 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Sablonok renderelése."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"alkalmazásindítás vezérlése"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Alkalmazásindítás vezérlése."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"témaszál-prioritás kezelése"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Témaszál-prioritás kezelése."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"A CAN-busz hibát észlelt"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"A CAN-busz nem válaszol. Csatlakoztassa újra a fejegységet, és indítsa újra az autót."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Saját eszköz"</string>
diff --git a/service/res/values-hy/strings.xml b/service/res/values-hy/strings.xml
index c93caf7..71839fd 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Ձևանմուշների արտապատկերում։"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"վերահսկել հավելվածների գործարկումը"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Վերահսկել հավելվածների գործարկումը"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"կառավարել Тhread-ի առաջնահերթությունը"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Կառավարել Тhread-ի առաջնահերթությունը։"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN անվադողի սխալ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN անվադողը չի պատասխանում: Անջատեք և նորից միացրեք միակցիչը, ապա անջատեք վառոցքը և վերագործարկեք մեքենան:"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Իմ սարքը"</string>
diff --git a/service/res/values-in/strings.xml b/service/res/values-in/strings.xml
index 0ace097..f527b85 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Merender template."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"mengontrol aplikasi yang diluncurkan"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrol aplikasi yang diluncurkan."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mengelola prioritas thread"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mengelola prioritas thread."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus gagal"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus tidak merespons. Cabut dan colokkan kembali boks headunit, lalu nyalakan ulang mobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Perangkat Saya"</string>
diff --git a/service/res/values-is/strings.xml b/service/res/values-is/strings.xml
index 91116e4..4995bb8 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Teikna sniðmát."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"stjórna ræsingu forrita"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Stjórna ræsingu forrita."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"stjórna forgangi þráða"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Stjórna forgangi þráða."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Bilun í CAN-gagnabraut"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-gagnabraut svarar ekki. Taktu stjórneiningarboxið úr sambandi, settu það aftur í samband og gangsettu bílinn aftur."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Tækið mitt"</string>
diff --git a/service/res/values-it/strings.xml b/service/res/values-it/strings.xml
index 113d4b7..958d15b 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Consente di visualizzare i modelli."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controllo avvio delle applicazioni"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controllo avvio delle applicazioni."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestione della priorità dei thread"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestione della priorità dei thread."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Comunicazione tramite bus CAN non riuscita"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Il bus CAN non risponde. Scollega e ricollega l\'unità principale e riaccendi il motore."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mio dispositivo"</string>
diff --git a/service/res/values-iw/strings.xml b/service/res/values-iw/strings.xml
index e8ddd2a..84ba79a 100644
--- a/service/res/values-iw/strings.xml
+++ b/service/res/values-iw/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"עיבוד תבניות."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"שליטה בהפעלת אפליקציות"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"יש שליטה בהפעלת אפליקציות."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ניהול העדיפות של השרשורים"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ניהול העדיפות של השרשורים."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"פרוטוקול CAN bus נכשל"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"פרוטוקול CAN bus לא מגיב. יש לנתק ולחבר שוב את מערכת הסטריאו ולהתניע מחדש את הרכב"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"המכשיר שלי"</string>
diff --git a/service/res/values-ja/strings.xml b/service/res/values-ja/strings.xml
index a741cfb..49cc734 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"テンプレートの表示。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"起動アプリの管理"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"起動アプリの管理。"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"スレッドの優先度の管理"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"スレッドの優先度の管理"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN バスでエラーが発生しました"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN バスが応答しません。ヘッドユニット ボックスのプラグを抜いて接続し直し、車を再始動してください"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"自分のデバイス"</string>
diff --git a/service/res/values-ka/strings.xml b/service/res/values-ka/strings.xml
index 96977f6..548f5dc 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"შაბლონების ჩვენება."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"აპლიკაციების გაშვების კონტროლი"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"აპლიკაციების გაშვების კონტროლი."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"თემატური გზავნილების პრიორიტეტულობის მართვა"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"თემატური გზავნილების პრიორიტეტულობის მართვა."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"წარმოიშვა CAN-სალტის შეცდომა"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-სალტე არ რეაგირებს. გამოაერთეთ და ხელახლა მიაერთეთ საინფორმაციო-გასართობი მოწყობილობა, შემდეგ კი ხელახლა დაქოქეთ მანქანა"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ჩემი მოწყობილობა"</string>
diff --git a/service/res/values-kk/strings.xml b/service/res/values-kk/strings.xml
index 1be18a5..620c0c9 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Рендеринг үлгілері"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"қолданбалардың іске қосылуын басқару"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Қолданбалардың іске қосылуын басқара аласыз."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"тізбек басымдығын басқару"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Тізбек басымдығын басқарыңыз."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN шинасы істен шықты"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN шинасы жауап бермейді. Негізгі модульді ажыратып, қайта жалғаңыз және көлікті қайта оталдырыңыз"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Құрылғым"</string>
diff --git a/service/res/values-km/strings.xml b/service/res/values-km/strings.xml
index 12d2339..621b072 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"បំប្លែង​ទម្រង់គំរូ។"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"គ្រប់គ្រង​ការចាប់ផ្ដើម​កម្មវិធី"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"គ្រប់គ្រង​ការចាប់ផ្ដើម​កម្មវិធី។"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"គ្រប់គ្រង​អាទិភាព​កម្រងសារ"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"គ្រប់គ្រង​អាទិភាព​កម្រងសារ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"មិនអាច​ដំណើរការ CAN bus បានទេ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus មិនឆ្លើយតបទេ។ សូមផ្ដាច់ រួចភ្ជាប់​ប្រអប់​ឧបករណ៍ចាក់តន្ត្រី​ម្តងទៀត បន្ទាប់មក​បញ្ឆេះ​រថយន្ត​ឡើងវិញ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ឧបករណ៍របស់ខ្ញុំ"</string>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index 9134516..3fec736 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -40,7 +40,7 @@
     <string name="car_permission_desc_radio" msgid="3385999027478186964">"ಕಾರಿನ ರೇಡಿಯೋವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="car_permission_label_projection" msgid="9107156380287576787">"ಕಾರಿನ ಡಿಸ್‌ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್‌ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಿ"</string>
     <string name="car_permission_desc_projection" msgid="2352178999656292944">"ಕಾರಿನ ಡಿಸ್‌ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್‌ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
-    <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರೊಜೆಕ್ಷನ್ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರಕ್ಷೇಪಣೆ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
     <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ಕಾರಿನ ಡಿಸ್‌ಪ್ಲೇಗೆ ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡುವ ಇತರ ಆ್ಯಪ್‌ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪಡೆಯಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="car_permission_label_audio_volume" msgid="310587969373137690">"ಕಾರಿನ ಆಡಿಯೋ ವಾಲ್ಯೂಮ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ಕಾರಿನ ಆಡಿಯೋ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ಟೆಂಪ್ಲೇಟ್‌ಗಳನ್ನು ರೆಂಡರ್ ಮಾಡಿ."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ಪ್ರಾರಂಭಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ಪ್ರಾರಂಭಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ಥ್ರೆಡ್ ಆದ್ಯತೆಯನ್ನು ನಿರ್ವಹಿಸಿ"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ಥ್ರೆಡ್ ಆದ್ಯತೆಯನ್ನು ನಿರ್ವಹಿಸಿ."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"ಸಿಎಎನ್ ಬಸ್ ಕೆಟ್ಟಿದೆ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ಬಸ್ ಸ್ಪಂದಿಸುತ್ತಿಲ್ಲ. ಹೆಡ್ ಯುನಿಟ್ ಪೆಟ್ಟಿಗೆಯನ್ನು ಅನ್‌ಪ್ಲಗ್ ಮಾಡಿ ಮತ್ತೆ ಪ್ಲಗ್ ಮಾಡಿ ಕಾರನ್ನು ಪುನರಾರಂಭಿಸಿ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ನನ್ನ ಸಾಧನ"</string>
diff --git a/service/res/values-ko/strings.xml b/service/res/values-ko/strings.xml
index 3d5a3a8..fd40bf9 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"템플릿 렌더링"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"애플리케이션 실행을 제어합니다."</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"애플리케이션 실행을 제어합니다."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"대화목록 우선순위 관리"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"대화목록 우선순위를 관리합니다."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 버스 실패"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN 버스가 응답하지 않습니다. 헤드유닛 박스를 분리한 후 다시 연결한 다음 시동을 다시 걸어 보세요."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"내 기기"</string>
diff --git a/service/res/values-ky/strings.xml b/service/res/values-ky/strings.xml
index d468a7f..8d808d9 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -20,8 +20,8 @@
     <string name="car_permission_desc" msgid="3584369074931334964">"унааңыз тууралуу маалымат алынат"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"унаадагы камерага мүмкүнчүлүк алуу"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Унааңыздын камераларын колдонуу."</string>
-    <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалымат алуу"</string>
-    <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалымат алуу."</string>
+    <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалыматты көрүү"</string>
+    <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалыматты көрүү."</string>
     <string name="car_permission_label_control_car_energy" msgid="2788215385574313796">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөө"</string>
     <string name="car_permission_desc_control_car_energy" msgid="8765015897869031807">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөңүз."</string>
     <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"унаа дагы канча аралыкты басып өтөрүн тууралоо"</string>
@@ -131,7 +131,7 @@
     <string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"унаанын сыртындагы температураны окуу"</string>
     <string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Унаанын сыртындагы температураны көрүү."</string>
     <string name="car_permission_label_car_tires" msgid="4379255261197836840">"унаа дөңгөлөктөрү тууралуу маалыматты окуу"</string>
-    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалымат алуу."</string>
+    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалыматты көрүү."</string>
     <string name="car_permission_label_car_steering" msgid="7779530447441232479">"унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү"</string>
     <string name="car_permission_desc_car_steering" msgid="1357331844530708138">"Унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү."</string>
     <string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"унаанын дисплей бөлүмдөрүн окуу"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Үлгүлөрдү түзүү."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"иштетилген колдонмолорду көзөмөлдөө"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Иштетилген колдонмолорду көзөмөлдөңүз."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"маектин маанилүүлүгүн башкаруу"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Маектин маанилүүлүгүн башкаруу."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN иштебей калды"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN жооп бербей жатат. Башкы шайман блогун сууруп, кайра сайгандан кийин унааны кайра жүргүзүңүз"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Түзмөгүм"</string>
diff --git a/service/res/values-lo/strings.xml b/service/res/values-lo/strings.xml
index 26aa899..d07bf73 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ສະແດງແມ່ແບບ."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ຄວບຄຸມການເປີດໃຊ້ແອັບພລິເຄຊັນ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ຄວບຄຸມການເປີດໃຊ້ແອັບພລິເຄຊັນ."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ຈັດການຄວາມສຳຄັນຂອງຫົວຂໍ້"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ຈັດການຄວາມສຳຄັນຂອງຫົວຂໍ້."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus ບໍ່ສຳເລັດ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ບໍ່ຕອບສະໜອງ. ຖອດປລັກກ່ອງເຄື່ອງຫຼິ້ນວິທະຍຸ (Headunit) ແລ້ວສຽບເຂົ້າຄືນໃໝ່ ແລະ ຣິສະຕາດລົດ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ອຸປະກອນຂອງຂ້ອຍ"</string>
diff --git a/service/res/values-lt/strings.xml b/service/res/values-lt/strings.xml
index 6d9f0df..38ebbc1 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Pateikti šablonus."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"Valdyti paleidžiamas programas"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Valdyti paleidžiamas programas."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"tvarkyti instrukcijų sekos prioritetą"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Tvarkyti instrukcijų sekos prioritetą."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN BUS klaida"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN BUS nereaguoja. Atjunkite ir vėl prijunkite pagrindinio įtaiso dėžutę."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mano įrenginys"</string>
diff --git a/service/res/values-lv/strings.xml b/service/res/values-lv/strings.xml
index adb0907..c3a2a13 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Atveidot veidnes."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"lietojumprogrammu palaišanas kontrole"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Lietojumprogrammu palaišanas kontrole."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"pārvaldīt pavediena prioritāti"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Pārvaldīt pavediena prioritāti."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Radās atteice datu maģistrālē"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Datu maģistrāle nereaģē. Atvienojiet un atkal pievienojiet stereosistēmas paneļa kabeli un atkārtoti iedarbiniet automašīnu"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mana ierīce"</string>
diff --git a/service/res/values-mk/strings.xml b/service/res/values-mk/strings.xml
index 5936bf5..42b0c73 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"податоци за автомобилот"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"може да пристапуваат до податоците за автомобилот"</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"пристапува до податоците за автомобилот"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"пристапува до камерата на автомобилот"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Пристапува до камерите на автомобилот."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"пристапува до информациите за енергијата на автомобилот"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Прикажување шаблони."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"да го контролира стартувањето апликации"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"да го контролира стартувањето апликации"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"да управуваат со приоритетот на thread"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"да управуваат со приоритетот на thread"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-магистралата не успеа"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-магистралата не реагира. Откачете ја и повторно прикачете ја кутијата на главната единица и рестартирајте го автомобилот"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мојот уред"</string>
diff --git a/service/res/values-ml/strings.xml b/service/res/values-ml/strings.xml
index 2061442..8487ac5 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ടെം‍പ്ലേറ്റുകൾ റെൻഡർ ചെയ്യുക."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ലോഞ്ച് ചെയ്യുന്ന ആപ്പുകൾ നിയന്ത്രിക്കാം"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ലോഞ്ച് ചെയ്യുന്ന ആപ്പുകൾ നിയന്ത്രിക്കാം."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ത്രെഡ് മുൻഗണന മാനേജ് ചെയ്യുക"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ത്രെഡ് മുൻഗണന മാനേജ് ചെയ്യുക."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ബസ് പരാജയപ്പെട്ടു"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ബസ് പ്രതികരിക്കുന്നില്ല. ഹെഡ്‌യൂണിറ്റ് ബോക്‌സ്, അൺപ്ലഗ് ചെയ്‌ത്, വീണ്ടും പ്ലഗ് ചെയ്‌ത്, കാർ റീസ്‌റ്റാർട്ട് ചെയ്യുക"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"എന്റെ ഉപകരണം"</string>
diff --git a/service/res/values-mn/strings.xml b/service/res/values-mn/strings.xml
index b720a70..57faca2 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Загварыг буулгана."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"аппликэйшн эхлүүлэхийг хянаарай"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Аппликэйшн эхлүүлэхийг хянаарай."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"хуулбар процессыг чухалчлахыг удирдах"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Хуулбар процессыг чухалчлахыг удирдах."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus амжилтгүй болсон"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus хариу өгөхгүй байна. Хөгжим тоглуулагчийн хайрцгийг салгаад, дахин залгаж, машиныг дахин эхлүүлнэ үү"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Миний төхөөрөмж"</string>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index 4fdc968..8432a4f 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेम्पलेट रेंडर करा."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"लाँच होत असलेली अ‍ॅप्लिकेशन नियंत्रित करा"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"लाँच होत असलेली अ‍ॅप्लिकेशन नियंत्रित करा."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेडशी संबंधित प्राधान्य व्यवस्थापित करा"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेडशी संबंधित प्राधान्य व्यवस्थापित करा."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN बस अयशस्वी"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN बस प्रतिसाद देत नाही. हेडयुनिट बॉक्स अनप्लग करून पुन्हा प्लग करा आणि कार रीस्टार्ट करा"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"माझे डिव्हाइस"</string>
diff --git a/service/res/values-ms/strings.xml b/service/res/values-ms/strings.xml
index 28f1e31..79fd058 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Paparkan templat."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"mengawal pelancaran aplikasi"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Mengawal pelancaran aplikasi."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"urus keutamaan urutan"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Urus keutamaan urutan."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Bas CAN gagal"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Bas CAN tidak bertindak balas. Cabut dan palamkan kembali kotak unit stereo dan mulakan semula kereta"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Peranti Saya"</string>
diff --git a/service/res/values-my/strings.xml b/service/res/values-my/strings.xml
index 49e37f6..478227a 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"ကားအချက်အလက်"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုနိုင်သည်"</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုပါမည်"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"ကား၏ ကင်မရာကို အသုံးပြုပါမည်"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"သင့်ကား၏ ကင်မရာ(များ)ကို ဝင်ရောက်အသုံးပြုပါမည်။"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"ကား၏ စွမ်းအင်အချက်အလက်များကို ရယူပါမည်"</string>
@@ -142,8 +142,8 @@
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"အင်ဂျင်အားဖြင့် ကားဝင်ရိုးလည်ပတ်မှုအ‌ချက်အလက်များကို ရယူပါမည်"</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"ကား၏ ပါဝါအခြေအနေကို ကြည့်ပါမည်"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"ကား၏ ပါဝါအခြေအနေကို ရယူပါမည်။"</string>
-    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"စိတ်ချရသည့်စက်ပစ္စည်းကို စာရင်းသွင်းရန်"</string>
-    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"စိတ်ချရသည့်စက်ပစ္စည်း စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
+    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"ယုံကြည်ရသည့် ကိရိယာကို စာရင်းသွင်းရန်"</string>
+    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ယုံကြည်ရသည့် ကိရိယာအား စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
     <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ကား၏ ဝန်ဆောင်မှုများကို ပိတ်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"နမူနာပုံစံများ ပုံဖော်မည်။"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ဖွင့်ထားသည့် အပလီကေးရှင်းများကို ထိန်းချုပ်ခြင်း"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ဖွင့်ထားသည့် အပလီကေးရှင်းများကို ထိန်းချုပ်ခြင်း။"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ဦးစားပေး Thread စီမံရန်"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ဦးစားပေး Thread စီမံနိုင်သည်။"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"\"CAN bus\" စနစ် အသုံးပြုမှု မအောင်မြင်ပါ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus စနစ်က တုန့်ပြန်မှုမရှိပါ။ စက်အထိုင်ဘောက်စ်ကို ပလတ်ဖြုတ်ပြီး ပြန်တပ်ကာ ကားကို ပြန်လည်စတင်ပါ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ကျွန်ုပ်၏စက်"</string>
diff --git a/service/res/values-nb/strings.xml b/service/res/values-nb/strings.xml
index b2d85c2..c7057c3 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -68,7 +68,7 @@
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Tillater at en app kommuniserer med en enhet i AOAP-modus"</string>
     <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Lesetilgang til Occupant Awareness System"</string>
     <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Lar deg lese av status og registreringsdata for Occupant Awareness System"</string>
-    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontroller diagrammet for Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrollér diagrammet for Occupant Awareness System"</string>
     <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Lar deg kontrollere start og stopp av registreringsdiagrammet for Occupant Awareness System"</string>
     <string name="car_permission_label_diag_read" msgid="7248894224877702604">"lese diagnostikkdata"</string>
     <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Les diagnostikkdata fra bilen."</string>
@@ -99,17 +99,17 @@
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"få tilgang til tanklokket og ladeporten på bilen"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Tilgang til tanklokket og ladeporten på bilen."</string>
     <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrollere tanklokket og ladeporten på bilen"</string>
-    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontroller tanklokket og ladeporten på bilen."</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrollér tanklokket og ladeporten på bilen."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"lese bilens identifikator"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Tilgang til bilens identifikasjon."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrollére bildørene"</string>
-    <string name="car_permission_desc_control_car_doors" msgid="6287353311980590092">"Kontroller bildørene."</string>
+    <string name="car_permission_desc_control_car_doors" msgid="6287353311980590092">"Kontrollér bildørene."</string>
     <string name="car_permission_label_control_car_windows" msgid="2452854429996653029">"kontrollére bilvinduene"</string>
-    <string name="car_permission_desc_control_car_windows" msgid="7693657991521595635">"Kontroller bilvinduene."</string>
+    <string name="car_permission_desc_control_car_windows" msgid="7693657991521595635">"Kontrollér bilvinduene."</string>
     <string name="car_permission_label_control_car_mirrors" msgid="8470700538827409476">"kontrollére bilspeilene"</string>
-    <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontroller bilspeilene."</string>
+    <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrollér bilspeilene."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrollére bilsetene"</string>
-    <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontroller bilsetene."</string>
+    <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrollér bilsetene."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"få tilgang til grunnleggende informasjon om bilen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Tilgang til grunnleggende informasjon om bilen."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"få tilgang til bilens konfidensielle informasjon"</string>
@@ -123,11 +123,11 @@
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ha tilgang til bilens bindingskilde for kryptering"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ha tilgang til bilens bindingskilde for kryptering"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lese bilens utvendige lys"</string>
-    <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontroller bilens utvendige lys."</string>
+    <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrollér bilens utvendige lys."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"lese bilens innvendige lys"</string>
     <string name="car_permission_desc_car_interior_lights" msgid="6204775354692372506">"Tilgang til tilstanden til bilens innvendige lys."</string>
     <string name="car_permission_label_control_car_interior_lights" msgid="6685386372012664281">"kontrollére bilens utvendige lys"</string>
-    <string name="car_permission_desc_control_car_interior_lights" msgid="797201814109701538">"Kontroller bilens utvendige lys."</string>
+    <string name="car_permission_desc_control_car_interior_lights" msgid="797201814109701538">"Kontrollér bilens utvendige lys."</string>
     <string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"lese temperaturen utenfor bilen"</string>
     <string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Tilgang til temperaturen utenfor bilen."</string>
     <string name="car_permission_label_car_tires" msgid="4379255261197836840">"få informasjon om bildekkene"</string>
@@ -137,35 +137,33 @@
     <string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"lese bilens visningsenheter"</string>
     <string name="car_permission_desc_read_car_display_units" msgid="6891898275208542385">"Les visningsenheter."</string>
     <string name="car_permission_label_control_car_display_units" msgid="4975303668183173076">"kontrollére bilens visningsenheter"</string>
-    <string name="car_permission_desc_control_car_display_units" msgid="8744397195158556945">"Kontroller visningsenheter."</string>
+    <string name="car_permission_desc_control_car_display_units" msgid="8744397195158556945">"Kontrollér visningsenheter."</string>
     <string name="car_permission_label_car_powertrain" msgid="4586122326622134886">"lese informasjon om bilens drivlinje"</string>
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Tilgang til informasjon om bilens drivlinje."</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"lese bilens batterinivå"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"Tilgang til bilens batterinivå."</string>
     <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Registrer en godkjent enhet"</string>
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Tillat registrering av godkjente enheter"</string>
-    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontroller bilens testmodus"</string>
-    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontroller bilens testmodus"</string>
+    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrollér bilens testmodus"</string>
+    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrollér bilens testmodus"</string>
     <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Slå bilens funksjoner på eller av"</string>
     <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Slå bilens funksjoner på eller av."</string>
     <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"bruk vakthund for bil"</string>
     <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Bruk vakthund for bil."</string>
-    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"kontroller konfigurasjonen for bilens vakthund"</string>
-    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Kontroller konfigurasjonen for bilens vakthund."</string>
+    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"kontrollér konfigurasjonen for bilens vakthund"</string>
+    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Kontrollér konfigurasjonen for bilens vakthund."</string>
     <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"samle inn beregninger om bilens vakthund"</string>
     <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Samle inn beregninger om bilens vakthund."</string>
     <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"les bilens regler for av/på"</string>
     <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Les bilens regler for av/på."</string>
-    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"kontroller bilens regler for av/på"</string>
-    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Kontroller bilens regler for av/på."</string>
+    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"kontrollér bilens regler for av/på"</string>
+    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Kontrollér bilens regler for av/på."</string>
     <string name="car_permission_label_adjust_shutdown_process" msgid="184826150481255557">"justere nedstengingsprosessen"</string>
     <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"justere nedstengingsprosessen"</string>
     <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"gjengi maler"</string>
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Gjengi maler."</string>
-    <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontroller åpning av apper"</string>
-    <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontroller åpning av apper."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrer trådprioritet"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administrer trådprioritet"</string>
+    <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrollér åpning av apper"</string>
+    <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrollér åpning av apper."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus mislyktes"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus svarer ikke. Koble bilens hovedenhet ut og inn igjen, og start bilen på nytt"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Enheten min"</string>
diff --git a/service/res/values-ne/strings.xml b/service/res/values-ne/strings.xml
index 1c93755..9746593 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेम्प्लेटहरू रेन्डर गर्ने।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"एपहरू लन्च गर्ने कुरा नियन्त्रण गर्नुहोस्"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"एपहरू लन्च गर्ने कुरा नियन्त्रण गर्नुहोस्।"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेडको प्राथमिकता व्यवस्थापन गर्ने"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेडको प्राथमिकता व्यवस्थापन गर्ने।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus असफल भयो"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ले प्रतिक्रिया जनाएन। हेडयुनिट बाकसलाई प्लगबाट निकालेर फेरि प्लगमा घुसाउनुहोस् र कार पुनःसुरु गर्नुहोस्‌"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"मेरो डिभाइस"</string>
diff --git a/service/res/values-nl/strings.xml b/service/res/values-nl/strings.xml
index ee0de95..995ba18 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Templates renderen."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"starten van apps beheren"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Starten van apps beheren."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"thread-prioriteit beheren"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Thread-prioriteit beheren."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus is mislukt"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus reageert niet. Koppel de hoofdeenheid los en sluit deze vervolgens weer aan. Start de auto daarna opnieuw."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mijn apparaat"</string>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index 0686fba..69d50e2 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"କାର୍‌ର ସୂଚନା"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"କାର୍\'ର କ୍ୟାମେରାକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ଆପଣଙ୍କ କାର୍‍ର କ୍ୟାମେରା(ଗୁଡ଼ିକ) ଆକ୍ସେସ୍ କରିପାରେ।"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"କାର୍\'ର ଏନାର୍ଜି ସୂଚନାକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ଟେମ୍ପଲେଟ୍ ରେଣ୍ଡର୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ଆପ୍ଲିକେସନଗୁଡ଼ିକର ଲଞ୍ଚିଂକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ଆପ୍ଲିକେସନଗୁଡ଼ିକର ଲଞ୍ଚିଂକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ଥ୍ରେଡ ପ୍ରାଥମିକତାକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ଥ୍ରେଡ ପ୍ରାଥମିକତାକୁ ପରିଚାଳନା କରନ୍ତୁ।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ବସ୍ ବିଫଳ ହେଲା"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ବସ୍ ପ୍ରତିକ୍ରିୟା ଦେଉନାହିଁ। ହେଡୟୁନିଟ୍ ବାକ୍ସର ପ୍ଲଗ୍ କାଢ଼ି ପୁଣି ଲଗାନ୍ତୁ ଏବଂ କାର୍‍କୁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ମୋ ଡିଭାଇସ୍"</string>
diff --git a/service/res/values-pa/strings.xml b/service/res/values-pa/strings.xml
index 1195ea4..6c45f8d 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -76,8 +76,8 @@
     <string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"ਕਾਰ ਦਾ ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ।"</string>
     <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ਪ੍ਰਕਾਸ਼ਕ"</string>
     <string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS ਸੁਨੇਹੇ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ"</string>
-    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਸਬਸਕ੍ਰਾਈਬਰ"</string>
-    <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਗਾਹਕ"</string>
+    <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
     <string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਦਾ ਨਿਰੀਖਣ"</string>
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਵਰਤੋਂ ਦਾ ਨਿਰੀਖਣ"</string>
     <string name="car_permission_label_driving_state" msgid="7754624599537393650">"ਗੱਡੀ ਚਲਾਉਣ ਦੀ ਸਥਿਤੀ ਨੂੰ ਜਾਣਨਾ"</string>
@@ -85,13 +85,13 @@
     <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"ਕਾਰ ਟੈਲੀਮੀਟਰੀ ਸੇਵਾ ਵਰਤੋ"</string>
     <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"ਕਾਰ ਸਿਸਟਮ ਸਿਹਤ ਡਾਟਾ ਇਕੱਤਰ ਕਰੋ।"</string>
     <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"ਕਾਰ ਦੀ EVS ਸੇਵਾ ਵਰਤੋ"</string>
-    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
     <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਲਈ ਬੇਨਤੀ ਕਰੋ"</string>
     <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਲਾਂਚ ਕਰਨ ਲਈ ਸਿਸਟਮ ਨੂੰ ਬੇਨਤੀ ਕਰੋ"</string>
     <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"ਸਿਸਟਮ ਦੀ EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS ਕੈਮਰਾ ਵਰਤੋ"</string>
-    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
     <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰੋ"</string>
     <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਸੰਬੰਧੀ ਤਬਦੀਲੀਆਂ ਨੂੰ ਸੁਣੋ"</string>
     <string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"ਕਾਰ ਦੇ ਇੰਜਣ ਦੀ ਪੂਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ਟੈਮਪਲੇਟਾਂ ਨੂੰ ਰੈਂਡਰ ਕਰੋ।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ਲਾਂਚ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ਲਾਂਚ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ।"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ਥ੍ਰੈੱਡ ਸੰਬੰਧੀ ਤਰਜੀਹ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ਥ੍ਰੈੱਡ ਸੰਬੰਧੀ ਤਰਜੀਹ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ਬੱਸ ਅਸਫਲ ਰਹੀ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ਬੱਸ ਕੰਮ ਨਹੀਂ ਕਰਦੀ। ਹੈੱਡ ਯੂਨਿਟ ਬਾਕਸ ਨੂੰ ਅਨਪਲੱਗ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਪਲੱਗ ਲਗਾ ਕੇ ਕਾਰ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ਮੇਰਾ ਡੀਵਾਈਸ"</string>
diff --git a/service/res/values-pl/strings.xml b/service/res/values-pl/strings.xml
index b441fab..30b0180 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderowanie szablonów."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrola nad uruchamianiem aplikacji"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrola nad uruchamianiem aplikacji."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"zarządzanie priorytetem wątków"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Zarządzanie priorytetem wątków."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Błąd magistrali CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nie odpowiada. Odłącz i jeszcze raz podłącz moduł główny i ponownie uruchom samochód."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje urządzenie"</string>
diff --git a/service/res/values-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index f48e174..76b5daf 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar modelos."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controlar o início de aplicações"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlar o início de aplicações."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gerir prioridade das discussões"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Faça a gestão da prioridade das discussões."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no CAN bus."</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O CAN bus não responde. Desligue e volte a ligar a caixa da unidade principal e reinicie o automóvel."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
diff --git a/service/res/values-pt/strings.xml b/service/res/values-pt/strings.xml
index fbb6c98..d3d6871 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar modelos."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla a inicialização de aplicativos"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla a inicialização de aplicativos."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gerenciar prioridade da conversa"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gerenciar prioridade da conversa."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no barramento CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O barramento CAN parou de responder. Desconecte e conecte novamente a caixa da unidade principal, depois ligue o carro"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Meu dispositivo"</string>
diff --git a/service/res/values-ro/strings.xml b/service/res/values-ro/strings.xml
index d498f40..89a34e6 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_permission_label" msgid="2215078736675564541">"informațiile despre mașină"</string>
+    <string name="car_permission_label" msgid="2215078736675564541">"Accesează informațiile despre mașină"</string>
     <string name="car_permission_desc" msgid="3584369074931334964">"să acceseze informațiile despre mașină"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"Accesează camera mașinii"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Accesează camerele mașinii."</string>
@@ -24,8 +24,8 @@
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Accesează informațiile despre energie ale mașinii."</string>
     <string name="car_permission_label_control_car_energy" msgid="2788215385574313796">"să gestioneze setările pentru încărcarea mașinii electrice"</string>
     <string name="car_permission_desc_control_car_energy" msgid="8765015897869031807">"să gestioneze setările pentru încărcarea mașinii electrice."</string>
-    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustează restul distanței parcurse de mașină"</string>
-    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustează restul distanței parcurse de mașină."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustați restul distanței parcurse de mașină"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustați restul distanței parcurse de mașină."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"Accesează sistemul hvac al mașinii"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Accesează sistemul hvac al mașinii."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"Accesează informațiile despre kilometrajul mașinii"</string>
@@ -35,7 +35,7 @@
     <string name="car_permission_label_vehicle_dynamics_state" msgid="313779267420048367">"Accesează starea dinamică a mașinii"</string>
     <string name="car_permission_desc_vehicle_dynamics_state" msgid="8891506193446375660">"Accesează starea dinamică a mașinii."</string>
     <string name="car_permission_label_vendor_extension" msgid="7141601811734127361">"Accesează canalul furnizorului mașinii"</string>
-    <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Accesează canalul furnizorului auto pentru a face schimb de informații specifice mașinii."</string>
+    <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Accesați canalul furnizorului auto pentru a face schimb de informații specifice mașinii."</string>
     <string name="car_permission_label_radio" msgid="6009465291685935112">"Controlează radioul mașinii"</string>
     <string name="car_permission_desc_radio" msgid="3385999027478186964">"Accesează radioul mașinii."</string>
     <string name="car_permission_label_projection" msgid="9107156380287576787">"Proiectează o interfață de pe un telefon pe afișajul mașinii"</string>
@@ -45,23 +45,23 @@
     <string name="car_permission_label_audio_volume" msgid="310587969373137690">"Controlează volumul audio din mașină"</string>
     <string name="car_permission_label_audio_settings" msgid="6524703796944023977">"Gestionează setările audio ale mașinii"</string>
     <string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"Imită nivelul HAL al vehiculului"</string>
-    <string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"Primești evenimente de reducere a volumului audio"</string>
+    <string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"Primiți evenimente de reducere a volumului audio"</string>
     <string name="car_permission_desc_receive_ducking" msgid="776376388266656512">"Permite notificarea unei aplicații atunci când volumul acesteia este redus din cauza redării unui alt conținut audio în mașină."</string>
     <string name="car_permission_desc_mock_vehicle_hal" msgid="5235596491098649155">"Imită nivelul HAL al mașinii pentru testare internă."</string>
     <string name="car_permission_desc_audio_volume" msgid="536626185654307889">"Controlează volumul audio din mașină."</string>
-    <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Controlează setările audio ale mașinii"</string>
+    <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Controlați setările audio ale mașinii"</string>
     <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Blocarea aplicațiilor"</string>
-    <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Controlează blocarea aplicațiilor în timp ce conduci."</string>
+    <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Controlează blocarea aplicațiilor în timp ce conduceți."</string>
     <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Manager de navigare"</string>
     <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Raportează datele de navigare la grupul de instrumente"</string>
     <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Redare directă pe grupul de instrumente"</string>
-    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Permite unei aplicații să declare activitățile de afișat în grupul de instrumente"</string>
+    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Permiteți unei aplicații să declare activitățile de afișat în grupul de instrumente"</string>
     <string name="car_permission_car_cluster_control" msgid="1382247204230165674">"Control pentru grupul de instrumente"</string>
-    <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lansează aplicațiile din grupul de instrumente"</string>
+    <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lansați aplicațiile din grupul de instrumente"</string>
     <string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Starea de navigare în grupul de instrumente"</string>
-    <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ascultează modificările stării de navigare în grupul de instrumente"</string>
+    <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ascultați modificările stării de navigare în grupul de instrumente"</string>
     <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configurarea restricțiilor UX"</string>
-    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurează restricțiile UX"</string>
+    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurați restricțiile UX"</string>
     <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acces pentru citire la ID-ul de afișare privată"</string>
     <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Permite acces pentru citire la ID-ul de afișare privată"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunică cu dispozitivul USB în modul AOAP"</string>
@@ -82,18 +82,18 @@
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorizează utilizarea stocării flash"</string>
     <string name="car_permission_label_driving_state" msgid="7754624599537393650">"Ascultă starea La volan"</string>
     <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ascultă modificările stării La volan."</string>
-    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Folosește serviciul de telemetrie al mașinii"</string>
-    <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Colectează date despre starea sistemului mașinii"</string>
-    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Folosește serviciul EVS al mașinii"</string>
-    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonează-te la streamurile video EVS"</string>
-    <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicită activitatea de previzualizare EVS"</string>
-    <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicită sistemului să lanseze activitatea de previzualizare EVS"</string>
-    <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Gestionează activitatea de previzualizare EVS"</string>
-    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Gestionează activitatea de previzualizare EVS a sistemului"</string>
-    <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Folosește camera EVS"</string>
-    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonează-te la streamurile camerei EVS"</string>
-    <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizează starea serviciului EVS"</string>
-    <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Urmărește modificările de stare ale serviciului EVS"</string>
+    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Folosiți serviciul de telemetrie al mașinii"</string>
+    <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Colectați date despre starea sistemului mașinii"</string>
+    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Folosiți serviciul EVS al mașinii"</string>
+    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonați-vă la streamurile video EVS"</string>
+    <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitați activitatea de previzualizare EVS"</string>
+    <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitați sistemului să lanseze activitatea de previzualizare EVS"</string>
+    <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Gestionați activitatea de previzualizare EVS"</string>
+    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Gestionați activitatea de previzualizare EVS a sistemului"</string>
+    <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Folosiți camera EVS"</string>
+    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonați-vă la streamurile camerei EVS"</string>
+    <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizați starea serviciului EVS"</string>
+    <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Urmăriți modificările de stare ale serviciului EVS"</string>
     <string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"Accesează informațiile detaliate despre motorul mașinii"</string>
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accesează informațiile detaliate despre motorul mașinii"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accesează ușa de alimentare a mașinii și portul de încărcare"</string>
@@ -114,12 +114,12 @@
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accesează informațiile de bază despre mașină."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"să acceseze informațiile cu acces privilegiat ale mașinii"</string>
     <string name="car_permission_desc_privileged_car_info" msgid="2245117655328125350">"să acceseze informațiile cu acces privilegiat ale mașinii."</string>
-    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accesează informațiile despre permisiuni ale furnizorului mașinii"</string>
-    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accesează informațiile despre permisiuni ale furnizorului mașinii."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accesați informațiile despre permisiuni ale furnizorului mașinii"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accesați informațiile despre permisiuni ale furnizorului mașinii."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"Citește starea luminilor exterioare ale mașinii"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accesează starea luminilor exterioare ale mașinii."</string>
-    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accesează datele temporale ale mașinii"</string>
-    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accesează datele temporale ale mașinii."</string>
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accesați datele temporale ale mașinii"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accesați datele temporale ale mașinii."</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"accesează sursa de legătură a criptării mașinii"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Accesează sursa de legătură a criptării mașinii."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Citește starea luminilor exterioare ale mașinii"</string>
@@ -142,32 +142,30 @@
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Accesează informațiile powertrain ale mașinii."</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"Citește starea de încărcare a mașinii"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"Accesează starea de încărcare a mașinii."</string>
-    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Înscrie un dispozitiv de încredere"</string>
-    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permite înscrierea unui dispozitiv de încredere"</string>
-    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlează modul de testare a mașinii"</string>
-    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlează modul de testare a mașinii"</string>
-    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activează sau dezactivează funcțiile mașinii"</string>
-    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activează sau dezactivează funcțiile mașinii."</string>
-    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"folosește ceasul de gardă al mașinii"</string>
-    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Folosește ceasul de gardă al mașinii."</string>
-    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"gestionează configurația ceasului de gardă al mașinii"</string>
-    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Gestionează configurația ceasului de gardă al mașinii."</string>
-    <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"adună valori de la ceasul de gardă al mașinii"</string>
-    <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Adună valori de la ceasul de gardă al mașinii."</string>
-    <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"citește politica pentru încărcarea mașinii"</string>
-    <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Citește politica pentru încărcarea mașinii."</string>
-    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"controlează politica pentru încărcarea mașinii"</string>
-    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Controlează politica pentru încărcarea mașinii."</string>
+    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Înscrieți un dispozitiv de încredere"</string>
+    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permiteți înscrierea unui dispozitiv de încredere"</string>
+    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlați modul de testare a mașinii"</string>
+    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlați modul de testare a mașinii"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activați sau dezactivați funcțiile mașinii"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activați sau dezactivați funcțiile mașinii."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"folosiți ceasul de gardă al mașinii"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Folosiți ceasul de gardă al mașinii."</string>
+    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"gestionați configurația ceasului de gardă al mașinii"</string>
+    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Gestionați configurația ceasului de gardă al mașinii."</string>
+    <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"adunați valori de la ceasul de gardă al mașinii"</string>
+    <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Adunați valori de la ceasul de gardă al mașinii."</string>
+    <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"citiți politica pentru încărcarea mașinii"</string>
+    <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Citiți politica pentru încărcarea mașinii."</string>
+    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"controlați politica pentru încărcarea mașinii"</string>
+    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Controlați politica pentru încărcarea mașinii."</string>
     <string name="car_permission_label_adjust_shutdown_process" msgid="184826150481255557">"să ajusteze procesul de închidere"</string>
-    <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"Ajustează procesul de închidere."</string>
-    <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"redă șabloane"</string>
-    <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Redă șabloane."</string>
+    <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"Ajustați procesul de închidere."</string>
+    <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"redați șabloane"</string>
+    <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Redați șabloane."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"să controleze aplicațiile lansate"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlează aplicațiile lansate."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestionează prioritatea firelor"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestionează prioritatea firelor."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Magistrala CAN nu a reușit"</string>
-    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nu răspunde. Deconectează și reconectează unitatea radio, apoi repornește mașina"</string>
+    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nu răspunde. Deconectați și reconectați unitatea radio, apoi reporniți mașina"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispozitivul meu"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Invitat"</string>
 </resources>
diff --git a/service/res/values-ru/strings.xml b/service/res/values-ru/strings.xml
index 2a5c933..25a767b 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"Данные автомобиля"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"получать доступ к данным автомобиля."</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"Доступ к данным автомобиля"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"доступ к камере автомобиля"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Доступ к камерам автомобиля"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"доступ к данным об энергоресурсах автомобиля"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Обработка шаблонов."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"управление запуском приложений"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Управление запуском приложений."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управление приоритетом цепочек"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управление приоритетом цепочек"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Произошла ошибка шины CAN."</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Шина CAN не отвечает. Переподключите коннектор, а затем выключите зажигание и заведите машину снова."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мое устройство"</string>
diff --git a/service/res/values-si/strings.xml b/service/res/values-si/strings.xml
index a624b77..8c01b49 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"අච්චු විදහන්න."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"යෙදුම් දියත් කිරීම කළමනාකරණය කරන්න"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"යෙදුම් දියත් කිරීම කළමනාකරණය කරන්න."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"පොට ප්‍රමුඛතාවය කළමනාකරණය කරන්න"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"පොට ප්‍රමුඛතාවය කළමනාකරණය කරන්න."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN බස් අසාර්ථකයි"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN බස් ප්‍රතිචාර නොදක්වයි. හෙඩ්යුනිට් පෙට්ටිය පේනු ඉවත් කර ආපසු පේනුගත කර, මෝටර් රථය යළි අරඹන්න"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"මගේ උපාංගය"</string>
diff --git a/service/res/values-sk/strings.xml b/service/res/values-sk/strings.xml
index e88b08e..886ba76 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vykresľovanie šablón."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ovládanie spúšťaných aplikácií"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ovládanie spúšťaných aplikácií."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"správa priority vlákna"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Správa priority vlákna."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Zbernica CAN zlyhala"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Zbernica CAN nereaguje. Odpojte autorádio a znova ho pripojte. Potom auto znova naštartujte."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje zariadenie"</string>
diff --git a/service/res/values-sl/strings.xml b/service/res/values-sl/strings.xml
index 3911ed3..0271b10b 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Upodabljanje predlog."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"nadziranje zaganjanja aplikacij"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Nadziranje zaganjanja aplikacij"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prednosti niti"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prednosti niti."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Napaka vodila CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Vodilo CAN se ne odziva. Odklopite in znova priklopite ohišje avtomobilskega vmesnika ter znova zaženite avtomobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moja naprava"</string>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index 9a9a1e6..814a2ca 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Të paraqesë shabllonet."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrollo hapjen e aplikacioneve"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrollo hapjen e aplikacioneve."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"menaxho përparësinë në bashkëbisedim"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Menaxho përparësinë në bashkëbisedim."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Kanali i komunikimit CAN dështoi"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Kanali i komunikimit CAN nuk përgjigjet. Shkëput dhe lidh përsëri kutinë e njësisë kryesore dhe rindiz makinës"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Pajisja ime"</string>
diff --git a/service/res/values-sr/strings.xml b/service/res/values-sr/strings.xml
index daad63f..c4bdc06 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Приказивање шаблона."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"контрола покретања апликација"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Контролише покретање апликација."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управљање приоритетом нити"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управљање приоритетом нити."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка CAN магистрале"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN магистрала не реагује. Искључите и поново укључите главну јединицу и поново покрените аутомобил"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мој уређај"</string>
diff --git a/service/res/values-sv/strings.xml b/service/res/values-sv/strings.xml
index 083411d..623e197 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Rendera mallar."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"styr startande appar"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Styr startande appar."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"hantera trådprioritet"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Hantera trådprioritet."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Fel i CAN-bussen"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bussen svarar inte. Koppla från huvudenheten och koppla in den igen. Starta sedan om bilen"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Min enhet"</string>
diff --git a/service/res/values-sw/strings.xml b/service/res/values-sw/strings.xml
index e0572bf..08cac41 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Kutekeleza violezo."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kudhibiti programu za kufungua"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Dhibiti programu za kufungua."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"dhibiti kipaumbele cha mazungumzo"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Dhibiti kipaumbele cha mazungumzo."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Imeshindwa kuleta maelezo ya kebo CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Kebo ya CAN haifanyi kazi. Ondoa kisha urudishe tena kisanduku cha sehemu kuu na uzime kisha uwashe gari"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Kifaa Changu"</string>
diff --git a/service/res/values-ta/strings.xml b/service/res/values-ta/strings.xml
index c0e6781..4b9987f 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"டெம்ப்ளேட்டுகளைக் காட்டுதல்."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"தொடங்கும் ஆப்ஸைக் கட்டுப்படுத்தலாம்"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"தொடங்கும் ஆப்ஸைக் கட்டுப்படுத்தலாம்."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"மெசேஜ் தொடருக்கான முன்னுரிமையை நிர்வகித்தல்"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"மெசேஜ் தொடருக்கான முன்னுரிமையை நிர்வகித்தல்."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus அமைப்பு தோல்வியடைந்தது"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus அமைப்பு இயங்கவில்லை. ஹெட்யூனிட் பாக்ஸைப் பிளக்கில் இருந்து அகற்றிச் செருகியபின் காரை மீண்டும் தொடங்கவும்"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"எனது சாதனம்"</string>
diff --git a/service/res/values-te/strings.xml b/service/res/values-te/strings.xml
index 7462cc2..3dc67d3 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -53,9 +53,9 @@
     <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"యాప్ బ్లాక్ చేయడం"</string>
     <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"డ్రైవింగ్‌లో ఉన్నప్పుడు అప్లికేషన్‌లను బ్లాక్ చేయండి"</string>
     <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"నావిగేషన్ మేనేజర్"</string>
-    <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గ్రూపునకు నావిగేషన్ డేటాను రిపోర్ట్ చేయండి"</string>
-    <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"పరికర గ్రూపునకు ప్రత్యక్ష రెండరింగ్"</string>
-    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"పరికర గ్రూపులో ప్రదర్శించాల్సిన కార్యకలాపలని తెలియచెప్పడానికి అప్లికేషన్‌ను అనుమతించండి."</string>
+    <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గుంపుకు నావిగేషన్ డేటాని రిపోర్ట్ చేయండి"</string>
+    <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"పరికర గుంపుకు ప్రత్యక్ష రెండరింగ్"</string>
+    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"పరికర గుంపులో ప్రదర్శించాల్సిన కార్యకలాపలని తెలియచెప్పడానికి అప్లికేషన్‌ను అనుమతించండి."</string>
     <string name="car_permission_car_cluster_control" msgid="1382247204230165674">"పరికర గుంపు నియంత్రణ"</string>
     <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"పరికర గుంపు యాప్‌లను ప్రారంభించండి"</string>
     <string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"పరికర క్లస్టర్ నావిగేషన్ స్టేట్"</string>
@@ -74,9 +74,9 @@
     <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"కారు నుండి విశ్లేషణ డేటాను తెలుసుకోగలవు."</string>
     <string name="car_permission_label_diag_clear" msgid="4783070510879698157">"సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు"</string>
     <string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"కారు నుండి సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు."</string>
-    <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS పబ్లిషర్‌"</string>
+    <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ప్రచురణకర్త"</string>
     <string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS మెసేజ్‌లను పబ్లిష్ చేయండి"</string>
-    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సబ్‌స్క్రయిబర్"</string>
+    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సభ్యులు"</string>
     <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS మెసేజ్‌లను పొందడానికి సబ్‌స్క్రయిబ్ చేయండి"</string>
     <string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ఫ్లాష్ నిల్వ పర్యవేక్షణ"</string>
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ఫ్లాష్ నిల్వ వినియోగాన్ని పర్యవేక్షించండి"</string>
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"టెంప్లేట్‌లను రెండర్ చేస్తుంది."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"లాంచ్ చేయబడుతున్న యాప్‌లను కంట్రోల్ చేయండి"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"లాంచ్ చేయబడుతున్న యాప్‌లను కంట్రోల్ చేయండి."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"థ్రెడ్ ప్రాధాన్యతను మేనేజ్ చేయడానికి అనుమతి ఇవ్వండి"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"థ్రెడ్ ప్రాధాన్యతను మేనేజ్ చేయడానికి అనుమతి ఇవ్వండి."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN బస్సు విఫలమైంది"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN బస్సు స్పందించలేదు. హెడ్ యూనిట్ బాక్స్‌‍‌ని ప్లగ్ మరియు అన్‌ప్లగ్ చేసి కారుని పునఃప్రారంభించుము"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"నా పరికరం"</string>
diff --git a/service/res/values-th/strings.xml b/service/res/values-th/strings.xml
index 101f655..b04eabe 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"แสดงผลเทมเพลต"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ควบคุมการเปิดใช้งานแอปพลิเคชัน"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ควบคุมการเปิดใช้งานแอปพลิเคชัน"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"จัดการลำดับความสำคัญของชุดข้อความ"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"จัดการลำดับความสำคัญของชุดข้อความ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN Bus ล้มเหลว"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN Bus ไม่ตอบสนอง ถอดปลั๊กกล่องเครื่องเล่นวิทยุ (Headunit) แล้วเสียบกลับเข้าไป สตาร์ทรถอีกครั้ง"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"อุปกรณ์ของฉัน"</string>
diff --git a/service/res/values-tl/strings.xml b/service/res/values-tl/strings.xml
index 7b67373..e51e12e 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mag-render ng mga template."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrolin ang paglunsad ng mga application"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrolin ang paglunsad ng mga application."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"pamahalaan ang priyoridad ng thread"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Pamahalaan ang priyoridad ng thread."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Hindi gumana ang CAN bus"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Hindi tumugon ang CAN bus. Hugutin at muling isaksak ang headunit box at i-restart ang sasakyan"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Aking Device"</string>
diff --git a/service/res/values-tr/strings.xml b/service/res/values-tr/strings.xml
index 1e9bb9a..176b227 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Şablonları oluşturma."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"başlatılan uygulamaları kontrol etme"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Başlatılan uygulamaları kontrol etme."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ileti dizisi önceliğini yönetin."</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"İleti dizisi önceliğini yönetin."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN veri yolu başarısız"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN veri yolu yanıt vermiyor. Ana birim kutusunu söküp tekrar takın ve aracı yeniden çalıştırın"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 2bb9307..070e447 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Відображати шаблони."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"керувати додатками, що запускаються"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Керувати додатками, що запускаються."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"керувати пріоритетом ланцюжка"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Керувати пріоритетом ланцюжка."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Помилка CAN-шини"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-шина не відповідає. Від’єднайте та знову під’єднайте головний пристрій аудіосистеми й заведіть автомобіль ще раз"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мій пристрій"</string>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index a28b091..2047e43 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"تمثیلات تیار کریں۔"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"شروع ہونے والی ایپلیکیشنز کو کنٹرول کریں"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"شروع ہونے والی ایپلیکیشنز کو کنٹرول کریں۔"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"سلسلے کی ترجیح کا نظم کریں"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"سلسلے کی ترجیح کا نظم کریں۔"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"کین بس ناکام ہو گئی"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"کین بس جواب نہیں دیتی ہے۔ ہیڈیونٹ باکس کو ان پلگ کر کے دوبارہ پلگ کریں اور کار کو دوبارہ شروع کریں"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"میرا آلہ"</string>
diff --git a/service/res/values-uz/strings.xml b/service/res/values-uz/strings.xml
index 1dc37e8..5c9e233 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Andozalarni renderlash."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ilovani ishga tushirishni boshqarish"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ilovani ishga tushirishni boshqarish."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mavzu ustuvorligini boshqarish"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mavzu ustuvorligini boshqarish."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN shinalarida xatolik yuz berdi"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN javob bermayapti. Konnektorni chiqaring va qayta ulang, keyin avtomobilni oʻt oldiring"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Qurilmam"</string>
diff --git a/service/res/values-vi/strings.xml b/service/res/values-vi/strings.xml
index 9804c65..c92ddc3 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mẫu kết xuất hình ảnh."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kiểm soát việc mở ứng dụng"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kiểm soát việc mở ứng dụng."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"quản lý mức độ ưu tiên của chuỗi"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Quản lý mức độ ưu tiên của chuỗi."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Đường dẫn chính CAN không hoạt động"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Đường dẫn chính CAN không phản hồi. Rút rồi cắm lại hộp bộ đầu và khởi động lại ô tô"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Thiết bị của tôi"</string>
diff --git a/service/res/values-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index 70d371f..e401aca 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"渲染模板。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制应用启动"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制应用启动。"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理会话优先级"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理会话优先级。"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 总线故障"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN 总线没有响应。请将主机盒插头拔下并插回,然后重新启动汽车"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的设备"</string>
diff --git a/service/res/values-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index a42a8c0..fc2b163 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"輸出範本。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制啟動應用程式"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制啟動應用程式。"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理郵件串優先次序"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理郵件串優先次序。"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路操作失敗"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"控制器區域網路未有回覆。請拔除並重新插上汽車音響主機,然後重新啟動汽車"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
diff --git a/service/res/values-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index ad7d0f6..4d8809e 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"算繪範本。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制要啟動的應用程式"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制要啟動的應用程式。"</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理會話串優先順序"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理會話串優先順序。"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路發生問題"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"控制器區域網路無回應。請將主機盒插頭拔下並插回,然後重新啟動車輛"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
diff --git a/service/res/values-zu/strings.xml b/service/res/values-zu/strings.xml
index c3e0af4..406f309 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -164,8 +164,6 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Nikezela izifanekiso."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"lawula ama-application okuqalisa"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Lawula ama-application okuqalisa."</string>
-    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"phatha okubalulekile kochungechunge"</string>
-    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Phatha okubalulekile kochungechunge."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Ibhasi ye-CAN yehlulekile"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Ibhasi ye-CAN ayiphenduli. Nqamula futhi uxhume ibhokisi le-headunit ukuze uqalise kabusha imoto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Idivayisi yami"</string>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 460935d..36464a5 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -490,4 +490,38 @@
     <!-- How many milli-seconds CarService should wait before managing pre-created users after
          system start. This property only applied when config_userPreCreationStage flag is 2. -->
     <integer name="config_userPreCreationDelay">5000</integer>
+
+    <!-- This is the component name for the OEM customization service. OEM can choose to implement
+         this service to customize car service behavior for different policies. If OEMs choose to
+         implement it, they have to implement a service extending OemCarService exposed by car-lib,
+         and implement the needed component services.
+         If the component name is invalid, CarService would not connect to any OEM service.
+         Component name can not be a third party package. It should be pre-installed -->
+   <string name="config_oemCarService" translatable="false"></string>
+
+    <!-- Related to OEM customization service. How many milliseconds CarService should wait for
+         OEM service to connect. If `config_oemCarService` is set and oem service package exists,
+         then CarService would wait for this much time for OEM service to connect. If OEM service
+         doesn't connect within this time, CarService would crash itself. -->
+    <integer name="config_oemCarService_connection_timeout_ms">5000</integer>
+
+    <!-- Related to OEM customization service. How many milliseconds CarService should wait for
+         OEM service to be ready. This is the wait time after OEM service is connected to
+         CarService. CarService would poll OEM service for being ready, if OEM service not ready
+         within timeout, CarService would crash. -->
+    <integer name="config_oemCarService_serviceReady_timeout_ms">5000</integer>
+
+    <!-- Related to OEM customization service. Default timeout for calls made by CarService to
+         OEM service. After this, CarService would timeout the call. If OEM service returns the
+         results after timeout, it would be ignored. -->
+    <integer name="config_oemCarService_regularCall_timeout_ms">5000</integer>
+
+    <!-- Related to OEM customization service. Default timeout for critical calls made by CarService
+         to OEM service. After this timeout, CarService would itself and OEM Service. -->
+    <integer name="config_oemCarService_crashCall_timeout_ms">10000</integer>
+
+    <!-- Related to OEM customization service. Default thread pool size for communicating with the
+         OEM Service. The value can only be between 8 and 16. If value is higher than 16, thread
+         pool size will be 16. If value is lower than 8, thread pool size will be 8.-->
+    <integer name="config_oemCarService_thread_pool_size">8</integer>
 </resources>
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
index 449fde2..2cc338b 100644
--- a/service/res/values/overlayable.xml
+++ b/service/res/values/overlayable.xml
@@ -108,6 +108,12 @@
           <item type="bool" name="config_enableExternalCarTimeToExternalTimeSuggestion"/>
           <item type="integer" name="config_userPreCreationStage"/>
           <item type="integer" name="config_userPreCreationDelay"/>
+          <item type="string" name="config_oemCarService" translatable="false"/>
+          <item type="integer" name="config_oemCarService_connection_timeout_ms"/>
+          <item type="integer" name="config_oemCarService_serviceReady_timeout_ms"/>
+          <item type="integer" name="config_oemCarService_regularCall_timeout_ms"/>
+          <item type="integer" name="config_oemCarService_crashCall_timeout_ms"/>
+          <item type="integer" name="config_oemCarService_thread_pool_size"/>
           <!-- Params from config.xml that can be overlaid -->
 
           <!-- XML files that can be overlaid -->
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index b3f0d11..697d09c 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -33,6 +33,10 @@
     <string name="car_permission_label_control_car_energy">Control car\u2019s EV charge settings</string>
     <!-- Permission text: can control your car's EV charge settings [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_control_car_energy">Control your car\u2019s EV charge settings.</string>
+    <!-- Permission text: can control oem car service binding [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_bind_oem_car_service" translatable="false">Controls OEM Car Service binding</string>
+    <!-- Permission text: can control oem car service binding [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_bind_oem_car_service" translatable="false">Controls which service can bind to OemCarService</string>
     <!-- Permission text: can adjust value of your car's range remaining [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_adjust_range_remaining">adjust car\u2019s range remaining</string>
     <!-- Permission text: can adjust value of your car's range remaining [CHAR LIMIT=NONE] -->
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index 784f05d..e2cf486 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -36,7 +36,6 @@
 import android.car.hardware.power.ICarPowerPolicyListener;
 import android.car.hardware.power.PowerComponent;
 import android.car.media.CarMediaManager;
-import android.car.media.CarMediaManager.MediaSourceChangedListener;
 import android.car.media.CarMediaManager.MediaSourceMode;
 import android.car.media.ICarMedia;
 import android.car.media.ICarMediaSourceListener;
@@ -860,12 +859,16 @@
                     .equals(mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_PLAYBACK])) {
                 mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_PLAYBACK] = null;
             }
+            startMediaConnectorService(
+                    shouldStartPlayback(mPlayOnMediaSourceChangedConfig),
+                    UserHandle.of(ActivityManager.getCurrentUser()));
+        } else {
+            Slogf.i(
+                    CarLog.TAG_MEDIA,
+                    "Media source is null, skip starting media connector service");
         }
 
         notifyListeners(MEDIA_SOURCE_MODE_PLAYBACK);
-
-        startMediaConnectorService(shouldStartPlayback(mPlayOnMediaSourceChangedConfig),
-                UserHandle.of(ActivityManager.getCurrentUser()));
         // Reset current playback state for the new source, in the case that the app is in an error
         // state (e.g. not signed in). This state will be updated from the app callback registered
         // below, to make sure mCurrentPlaybackState reflects the current source only.
diff --git a/service/src/com/android/car/CarTestService.java b/service/src/com/android/car/CarTestService.java
index ece2a1e..19f63fd 100644
--- a/service/src/com/android/car/CarTestService.java
+++ b/service/src/com/android/car/CarTestService.java
@@ -103,6 +103,11 @@
         releaseToken(token);
     }
 
+    @Override
+    public String getOemServiceName() {
+        return mICarImpl.getOemServiceName();
+    }
+
     private void releaseToken(IBinder token) {
         Slogf.d(TAG, "releaseToken, token: " + token);
         synchronized (mLock) {
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index f35c745..aa21108 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -75,6 +75,7 @@
 import com.android.car.internal.ICarServiceHelper;
 import com.android.car.internal.ICarSystemServerClient;
 import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.car.oem.CarOemProxyService;
 import com.android.car.os.CarPerformanceService;
 import com.android.car.pm.CarPackageManagerService;
 import com.android.car.power.CarPowerManagementService;
@@ -117,6 +118,7 @@
 
     private final SystemInterface mSystemInterface;
 
+    private final CarOemProxyService mCarOemService;
     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
     private final CarPowerManagementService mCarPowerManagementService;
     private final CarPackageManagerService mCarPackageManagerService;
@@ -207,6 +209,10 @@
         } else {
             mCarServiceBuiltinPackageContext = builtinContext;
         }
+
+        mCarOemService = constructWithTrace(t, CarOemProxyService.class,
+                () -> new CarOemProxyService(serviceContext));
+
         mSystemInterface = systemInterface;
         CarLocalServices.addService(SystemInterface.class, mSystemInterface);
         mHal = constructWithTrace(t, VehicleHal.class,
@@ -487,8 +493,10 @@
             service.init();
             t.traceEnd();
         }
+        t.traceBegin("CarOemService.initComplete");
+        mCarOemService.onInitComplete();
+        t.traceEnd();
         t.traceEnd(); // "CarService.initAllServices"
-
         t.traceEnd(); // "ICarImpl.init"
     }
 
@@ -736,6 +744,7 @@
                 dumpAllHals(writer);
                 return;
             }
+
             int length = args.length - 1;
             String[] halNames = new String[length];
             System.arraycopy(args, 1, halNames, 0, length);
@@ -747,6 +756,13 @@
         } else if ("--data-dir".equals(args[0])) {
             dumpDataDir(writer);
             return;
+        } else if ("--oem-service".equals(args[0])) {
+            if (args.length > 1 && args[1].equalsIgnoreCase("--name-only")) {
+                writer.println(getOemServiceName());
+            } else {
+                dumpOemService(writer);
+            }
+            return;
         } else if ("--help".equals(args[0])) {
             showDumpHelp(writer);
         } else {
@@ -754,6 +770,22 @@
         }
     }
 
+    private void dumpOemService(IndentingPrintWriter writer) {
+        mCarOemService.dump(writer);
+    }
+
+    public String getOemServiceName() {
+        return mCarOemService.getOemServiceName();
+    }
+
+    private void dumpAll(IndentingPrintWriter writer) {
+        writer.println("*Dump car service*");
+        dumpVersions(writer);
+        dumpAllServices(writer);
+        dumpAllHals(writer);
+        dumpRROs(writer);
+    }
+
     private void dumpRROs(IndentingPrintWriter writer) {
         writer.println("*Dump Car Service RROs*");
 
diff --git a/service/src/com/android/car/evs/CarEvsService.java b/service/src/com/android/car/evs/CarEvsService.java
index c1026dd..142e7b3 100644
--- a/service/src/com/android/car/evs/CarEvsService.java
+++ b/service/src/com/android/car/evs/CarEvsService.java
@@ -467,11 +467,7 @@
                         return ERROR_BUSY;
                     }
 
-                    if (callback != null) {
-                        stopVideoStreamAndUnregisterCallback(callback);
-                    } else {
-                        stopService();
-                    }
+                    stopService(callback);
                     break;
 
                 default:
@@ -600,6 +596,7 @@
                     if (mStreamCallback != null) {
                         // keep old reference for Runnable.
                         ICarEvsStreamCallback previousCallback = mStreamCallback;
+                        mStreamCallback = null;
                         mHandler.post(() -> notifyStreamStopped(previousCallback));
                     }
 
@@ -684,7 +681,7 @@
     // Stops a current video stream and unregisters a callback
     private void stopVideoStreamAndUnregisterCallback(ICarEvsStreamCallback callback) {
         synchronized (mLock) {
-            if (callback.asBinder() != mStreamCallback.asBinder()) {
+            if (callback == null || callback.asBinder() != mStreamCallback.asBinder()) {
                 Slogf.i(TAG_EVS, "Declines a request to stop a video not from a current client.");
                 return;
             }
@@ -1023,7 +1020,6 @@
     public void stopVideoStream(@NonNull ICarEvsStreamCallback callback) {
         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_EVS_CAMERA);
         Objects.requireNonNull(callback);
-
         synchronized (mLock) {
             if (mStreamCallback == null || callback.asBinder() != mStreamCallback.asBinder()) {
                 Slogf.i(TAG_EVS, "Ignores a video stream request not from current stream client.");
@@ -1243,16 +1239,32 @@
 
     /** Stops a current service */
     private void stopService() {
+        stopService(/* callback= */ null);
+    }
+
+    private void stopService(ICarEvsStreamCallback callback) {
         try {
+            synchronized (mLock) {
+                if (callback != null && callback.asBinder() != mStreamCallback.asBinder()) {
+                    Slogf.w(TAG_EVS, "Decline a request to stop a video from an unknown client.");
+                    return;
+                }
+
+                unlinkToDeathStreamCallbackLocked();
+                mStreamCallback = null;
+            }
+            Slogf.i(TAG_EVS, "Last stream client has been disconnected.");
+
+            // Notify the client that the stream has ended.
+            if (callback != null) {
+                notifyStreamStopped(callback);
+            }
+
+            // Request to stop a video stream if it is active.
             mHalWrapper.requestToStopVideoStream();
         } catch (RuntimeException e) {
             Slogf.w(TAG_EVS, Log.getStackTraceString(e));
         } finally {
-            // Unregister all stream callbacks.
-            synchronized (mLock) {
-                mStreamCallback = null;
-            }
-
             // We simply drop all buffer records; the native method will return all pending buffers
             // to the native Extended System View service if it is alive.
             synchronized (mBufferRecords) {
@@ -1261,6 +1273,9 @@
 
             // Cancel a pending message to check a request timeout
             mHandler.removeCallbacks(mActivityRequestTimeoutRunnable);
+
+            // Close current camera
+            mHalWrapper.closeCamera();
         }
     }
 
diff --git a/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java b/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java
new file mode 100644
index 0000000..ae55a45
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.oem;
+
+import android.car.builtin.util.Slogf;
+import android.car.oem.IOemCarAudioFocusService;
+import android.media.AudioFocusInfo;
+import android.os.RemoteException;
+
+import com.android.car.CarLog;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Provides functionality of the OEM Audio Focus Service.
+ */
+public final class CarOemAudioFocusProxyService {
+
+    private static final String TAG = CarLog.tagFor(CarOemAudioFocusProxyService.class);
+    private static final String CALLER_TAG = CarLog.tagFor(CarOemAudioFocusProxyService.class);
+
+    private final CarOemProxyServiceHelper mHelper;
+    private final IOemCarAudioFocusService mOemCarAudioFocusService;
+
+    public CarOemAudioFocusProxyService(CarOemProxyServiceHelper helper,
+            IOemCarAudioFocusService oemAudioFocusService) {
+        mHelper = helper;
+        mOemCarAudioFocusService = oemAudioFocusService;
+    }
+
+    /**
+     * Updates audio focus changes.
+     */
+    public void audioFocusChanged(List<AudioFocusInfo> currentFocusHolders,
+            List<AudioFocusInfo> currentFocusLosers, int zoneId) {
+        mHelper.doBinderOneWayCall(CALLER_TAG, () -> {
+            try {
+                mOemCarAudioFocusService
+                        .audioFocusChanged(currentFocusHolders, currentFocusLosers, zoneId);
+            } catch (RemoteException e) {
+                Slogf.e(TAG, e,
+                        "audioFocusChanged call received RemoteException- currentFocusHolders:%s, "
+                        + "currentFocusLosers:%s, ZoneId: %s, , calling to crash CarService",
+                        currentFocusHolders, currentFocusLosers, zoneId);
+            }
+        });
+    }
+}
diff --git a/service/src/com/android/car/oem/CarOemProxyService.java b/service/src/com/android/car/oem/CarOemProxyService.java
new file mode 100644
index 0000000..5624267
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemProxyService.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.oem;
+
+import android.annotation.Nullable;
+import android.car.builtin.content.pm.PackageManagerHelper;
+import android.car.builtin.os.BuildHelper;
+import android.car.builtin.util.Slogf;
+import android.car.oem.IOemCarAudioFocusService;
+import android.car.oem.IOemCarService;
+import android.car.oem.IOemCarServiceCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+import com.android.car.CarServiceUtils;
+import com.android.car.R;
+import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Manages access to OemCarService.
+ *
+ * <p>All calls in this class are blocking on OEM service initialization, so should be called as
+ *  late as possible.
+ *
+ * <b>NOTE</b>: All {@link CarOemProxyService} call should be after init of ICarImpl. If any
+ * component calls {@link CarOemProxyService} before init of ICarImpl complete, it would throw
+ * {@link IllegalStateException}.
+ */
+public final class CarOemProxyService implements CarServiceBase {
+
+    private static final String TAG = CarOemProxyService.class.getSimpleName();
+    private static final String CALL_TAG = CarOemProxyService.class.getSimpleName();
+    private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+    // mock component name for testing if system property is set.
+    private static final String PROPERTY_EMULATED_OEM_CAR_SERVICE =
+            "persist.com.android.car.internal.debug.oem_car_service";
+
+    private final int mOemServiceConnectionTimeoutMs;
+    private final int mOemServiceReadyTimeoutMs;
+    private final Object mLock = new Object();
+    private final boolean mIsFeatureEnabled;
+    private final Context mContext;
+    private final boolean mIsOemServiceBound;
+    private final CarOemProxyServiceHelper mHelper;
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+    @GuardedBy("mLock")
+    private final ArrayList<CarOemProxyServiceCallback> mCallbacks = new ArrayList<>();
+
+
+    private String mComponentName;
+
+    // True once OemService return true for {@code isOemServiceReady} call. It means that OEM
+    // service has completed all the initialization and ready to serve requests.
+    @GuardedBy("mLock")
+    private boolean mIsOemServiceReady;
+    // True once OEM service is connected. It means that OEM service has return binder for
+    // communication. OEM service may still not be ready.
+    @GuardedBy("mLock")
+    private boolean mIsOemServiceConnected;
+
+    @GuardedBy("mLock")
+    private boolean mInitComplete;
+    @GuardedBy("mLock")
+    private IOemCarService mOemCarService;
+    @GuardedBy("mLock")
+    private CarOemAudioFocusProxyService mCarOemAudioFocusProxyService;
+
+    private final ServiceConnection mCarOemServiceConnection = new ServiceConnection() {
+
+        @Override
+        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+            Slogf.i(TAG, "onServiceConnected: %s, %s", componentName, iBinder);
+            synchronized (mLock) {
+                if (mOemCarService == IOemCarService.Stub.asInterface(iBinder)) {
+                    return; // already connected.
+                }
+                Slogf.i(TAG, "car oem service binder changed, was %s now: %s",
+                        mOemCarService, iBinder);
+                mOemCarService = IOemCarService.Stub.asInterface(iBinder);
+                Slogf.i(TAG, "**CarOemService connected**");
+                mIsOemServiceConnected = true;
+                mLock.notifyAll();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName componentName) {
+            Slogf.e(TAG, "OEM service crashed. Crashing the CarService. ComponentName:%s",
+                    componentName);
+            mHelper.crashCarService("Service Disconnected");
+        }
+    };
+
+    private final CountDownLatch mOemServiceReadyLatch = new CountDownLatch(1);
+
+    private final IOemCarServiceCallback mOemCarServiceCallback = new IOemCarServiceCallbackImpl();
+
+    @VisibleForTesting
+    public CarOemProxyService(Context context) {
+        this(context, null);
+    }
+
+    @VisibleForTesting
+    public CarOemProxyService(Context context, CarOemProxyServiceHelper helper) {
+        this(context, helper, null);
+    }
+
+    public CarOemProxyService(Context context, CarOemProxyServiceHelper helper, Handler handler) {
+        // Bind to the OemCarService
+        mContext = context;
+        Resources res = mContext.getResources();
+        mOemServiceConnectionTimeoutMs = res
+                .getInteger(R.integer.config_oemCarService_connection_timeout_ms);
+        mOemServiceReadyTimeoutMs = res
+                .getInteger(R.integer.config_oemCarService_serviceReady_timeout_ms);
+
+        String componentName = res.getString(R.string.config_oemCarService);
+
+        if (TextUtils.isEmpty(componentName)) {
+            // mock component name for testing if system property is set.
+            String emulatedOemCarService = SystemProperties.get(PROPERTY_EMULATED_OEM_CAR_SERVICE,
+                    "");
+            if (!BuildHelper.isUserBuild() && emulatedOemCarService != null
+                    && !emulatedOemCarService.isEmpty()) {
+                componentName = emulatedOemCarService;
+                Slogf.i(TAG, "Using emulated componentname for testing. ComponentName: %s",
+                        mComponentName);
+            }
+        }
+
+        mComponentName = componentName;
+
+        Slogf.i(TAG, "Oem Car Service Config. Connection timeout:%s, Service Ready timeout:%d, "
+                + "component Name:%s", mOemServiceConnectionTimeoutMs, mOemServiceReadyTimeoutMs,
+                mComponentName);
+
+        if (isInvalidComponentName(context, mComponentName)) {
+            // feature disabled
+            mIsFeatureEnabled = false;
+            mIsOemServiceBound = false;
+            mHelper = null;
+            mHandlerThread = null;
+            mHandler = null;
+            Slogf.i(TAG, "**CarOemService is disabled.**");
+            return;
+        }
+
+        Intent intent = (new Intent())
+                .setComponent(ComponentName.unflattenFromString(mComponentName));
+
+        Slogf.i(TAG, "Binding to Oem Service with intent: %s", intent);
+        mHandlerThread = CarServiceUtils.getHandlerThread("car_oem_service");
+        mHandler = handler == null ? new Handler(mHandlerThread.getLooper()) : handler;
+
+        mIsOemServiceBound = mContext.bindServiceAsUser(intent, mCarOemServiceConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM);
+
+        if (mIsOemServiceBound) {
+            mIsFeatureEnabled = true;
+            Slogf.i(TAG, "OemCarService bounded.");
+        } else {
+            mIsFeatureEnabled = false;
+            Slogf.e(TAG,
+                    "Couldn't bound to OemCarService. Oem service feature is marked disabled.");
+        }
+        mHelper = helper ==  null ? new CarOemProxyServiceHelper(mContext) : helper;
+    }
+
+    private boolean isInvalidComponentName(Context context, String componentName) {
+        if (componentName == null || componentName.isEmpty()) {
+            if (DBG) {
+                Slogf.d(TAG, "ComponentName is null or empty.");
+            }
+            return true;
+        }
+
+        // Only pre-installed package can be used for OEM Service.
+        String packageName = ComponentName.unflattenFromString(componentName).getPackageName();
+        PackageInfo info;
+        try {
+            info = context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0);
+        } catch (NameNotFoundException e) {
+            Slogf.e(TAG, "componentName %s not found.", componentName);
+            return true;
+        }
+
+        if (info == null || info.applicationInfo == null
+                || !(PackageManagerHelper.isSystemApp(info.applicationInfo)
+                        || PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo)
+                        || PackageManagerHelper.isOemApp(info.applicationInfo)
+                        || PackageManagerHelper.isOdmApp(info.applicationInfo)
+                        || PackageManagerHelper.isVendorApp(info.applicationInfo)
+                        || PackageManagerHelper.isProductApp(info.applicationInfo)
+                        || PackageManagerHelper.isSystemExtApp(info.applicationInfo))) {
+            if (DBG) {
+                Slogf.d(TAG, "Invalid component name. Info: %s", info);
+            }
+            return true;
+        }
+
+        if (DBG) {
+            Slogf.d(TAG, "Valid component name %s, ", componentName);
+        }
+
+        return false;
+    }
+
+    /**
+     * Registers callback to be called once OEM service is ready.
+     *
+     * <p>Other CarService components cannot call OEM service. But they can register a callback
+     * which would be called as soon as OEM Service is ready./
+     */
+    public void registerCallback(CarOemProxyServiceCallback callback) {
+        synchronized (mLock) {
+            mCallbacks.add(callback);
+        }
+    }
+
+    /**
+     * Informs if OEM service is enabled.
+     */
+    public boolean isOemServiceEnabled() {
+        synchronized (mLock) {
+            return mIsFeatureEnabled;
+        }
+    }
+
+    /**
+     * Informs if OEM service is ready.
+     */
+    public boolean isOemServiceReady() {
+        synchronized (mLock) {
+            return mIsOemServiceReady;
+        }
+    }
+
+    @Override
+    public void init() {
+        // Nothing to be done as OemCarService was initialized in the constructor.
+    }
+
+    @Override
+    public void release() {
+        // Stop OEM Service;
+        if (mIsOemServiceBound) {
+            Slogf.i(TAG, "Unbinding Oem Service");
+            mContext.unbindService(mCarOemServiceConnection);
+        }
+    }
+
+    @Override
+    public void dump(IndentingPrintWriter writer) {
+        writer.println("***CarOemProxyService dump***");
+        writer.increaseIndent();
+        synchronized (mLock) {
+            writer.printf("mIsFeatureEnabled: %s\n", mIsFeatureEnabled);
+            writer.printf("mIsOemServiceBound: %s\n", mIsOemServiceBound);
+            writer.printf("mIsOemServiceReady: %s\n", mIsOemServiceReady);
+            writer.printf("mIsOemServiceConnected: %s\n", mIsOemServiceConnected);
+            writer.printf("mInitComplete: %s\n", mInitComplete);
+            writer.printf("OEM_CAR_SERVICE_CONNECTED_TIMEOUT_MS: %s\n",
+                    mOemServiceConnectionTimeoutMs);
+            writer.printf("OEM_CAR_SERVICE_READY_TIMEOUT_MS: %s\n", mOemServiceReadyTimeoutMs);
+            writer.printf("mComponentName: %s\n", mComponentName);
+            writer.printf("mCallbacks size: %d\n", mCallbacks.size());
+            // Dump OEM service stack
+            if (mIsOemServiceReady) {
+                writer.printf("OEM callstack\n");
+                int timeoutMs = 2000;
+                try {
+                    writer.printf(mHelper.doBinderTimedCallWithTimeout(CALL_TAG,
+                            () -> getOemService().getAllStackTraces(), timeoutMs));
+                } catch (TimeoutException e) {
+                    writer.printf("Didn't received OEM stack within %d milliseconds.\n", timeoutMs);
+                }
+            }
+            // Dump helper
+            mHelper.dump(writer);
+        }
+        writer.decreaseIndent();
+    }
+
+    public String getOemServiceName() {
+        return mComponentName;
+    }
+
+    /**
+     * Gets OEM audio focus service.
+     */
+    @Nullable
+    public CarOemAudioFocusProxyService getCarOemAudioFocusService() {
+        if (!mIsFeatureEnabled) {
+            if (DBG) {
+                Slogf.d(TAG, "Oem Car Service is disabled, returning null for"
+                        + " getCarOemAudioFocusService");
+            }
+            return null;
+        }
+
+        synchronized (mLock) {
+            if (mCarOemAudioFocusProxyService != null) {
+                return mCarOemAudioFocusProxyService;
+            }
+        }
+
+        waitForOemService();
+
+        // TODO(b/240615622): Domain owner to decide if retry or default or crash.
+        IOemCarAudioFocusService oemAudioFocusService = mHelper.doBinderTimedCallWithDefaultValue(
+                CALL_TAG, () -> getOemService().getOemAudioFocusService(),
+                /* defaultValue= */ null);
+
+        if (oemAudioFocusService == null) {
+            if (DBG) {
+                Slogf.d(TAG, "Oem Car Service doesn't implement AudioFocusService, returning null"
+                        + " for getCarOemAudioFocusService");
+            }
+            return null;
+        }
+
+        CarOemAudioFocusProxyService carOemAudioFocusProxyService =
+                new CarOemAudioFocusProxyService(mHelper, oemAudioFocusService);
+        synchronized (mLock) {
+            if (mCarOemAudioFocusProxyService != null) {
+                return mCarOemAudioFocusProxyService;
+            }
+            mCarOemAudioFocusProxyService = carOemAudioFocusProxyService;
+            Slogf.i(TAG, "CarOemAudioFocusProxyService is ready.");
+            return mCarOemAudioFocusProxyService;
+        }
+    }
+
+    /**
+     * Should be called when CarService is ready for communication. It updates the OEM service that
+     * CarService is ready.
+     */
+    public void onCarServiceReady() {
+        waitForOemServiceConnected();
+        mHelper.doBinderOneWayCall(CALL_TAG, () -> {
+            try {
+                getOemService().onCarServiceReady(mOemCarServiceCallback);
+            } catch (RemoteException ex) {
+                Slogf.e(TAG, "Binder call received RemoteException, calling to crash CarService",
+                        ex);
+            }
+        });
+        waitForOemServiceReady();
+    }
+
+    private void waitForOemServiceConnected() {
+        synchronized (mLock) {
+            if (!mInitComplete) {
+                // No CarOemService call should be made before or during init of ICarImpl.
+                throw new IllegalStateException(
+                        "CarOemService should not be call before CarService initialization");
+            }
+
+            if (mIsOemServiceConnected) {
+                return;
+            }
+            waitForOemServiceConnectedLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void waitForOemServiceConnectedLocked() {
+        long startTime = SystemClock.elapsedRealtime();
+        long remainingTime = mOemServiceConnectionTimeoutMs;
+
+        while (!mIsOemServiceConnected && remainingTime > 0) {
+            try {
+                Slogf.i(TAG, "waiting to connect to OemService. wait time: %s", remainingTime);
+                mLock.wait(mOemServiceConnectionTimeoutMs);
+                remainingTime = mOemServiceConnectionTimeoutMs
+                        - (SystemClock.elapsedRealtime() - startTime);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                Slogf.w(TAG, "InterruptedException received. Reset interrupted status.", e);
+            }
+        }
+
+        if (!mIsOemServiceConnected) {
+            Slogf.e(TAG, "OEM Service is not connected within: %dms, calling to crash CarService",
+                    mOemServiceConnectionTimeoutMs);
+            mHelper.crashCarService("OEM Service not connected");
+        }
+    }
+
+    private void waitForOemService() {
+        waitForOemServiceConnected();
+        waitForOemServiceReady();
+    }
+
+    private void waitForOemServiceReady() {
+        synchronized (mLock) {
+            if (mIsOemServiceReady) {
+                return;
+            }
+        }
+
+        try {
+            mOemServiceReadyLatch.await(mOemServiceReadyTimeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            Slogf.i(TAG, "Exception while waiting for OEM Service to be ready.", e);
+        }
+
+        synchronized (mLock) {
+            if (!mIsOemServiceReady) {
+                Slogf.e(TAG, "OEM Service is not ready within: " + mOemServiceReadyTimeoutMs
+                        + "ms, calling to crash CarService");
+                mHelper.crashCarService("OEM Service not ready");
+            }
+        }
+        Slogf.i(TAG, "OEM Service is ready.");
+    }
+
+    // Initialize all OEM related components.
+    private void initOemServiceComponents() {
+        // Initialize all Oem Service components
+        getCarOemAudioFocusService();
+
+        // Callback registered Car Service components for OEM service.
+        callCarServiceComponents();
+    }
+
+    private void callCarServiceComponents() {
+        synchronized (mLock) {
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                mCallbacks.get(i).onOemServiceReady();
+            }
+        }
+    }
+
+    /**
+     * Informs CarOemService that ICarImpl's init is complete.
+     */
+    // This would set mInitComplete, which is an additional check so that no car service component
+    // calls CarOemService during or before ICarImpl's init.
+    public void onInitComplete() {
+        if (!mIsFeatureEnabled) {
+            if (DBG) {
+                Slogf.d(TAG, "Oem Car Service is disabled, No-op for onInitComplete");
+            }
+            return;
+        }
+
+        synchronized (mLock) {
+            mInitComplete = true;
+        }
+        // inform OEM Service that CarService is ready for communication.
+        // It has to be posted on the different thread as this call is part of init process.
+        mHandler.post(() -> onCarServiceReady());
+    }
+
+    private IOemCarService getOemService() {
+        synchronized (mLock) {
+            return mOemCarService;
+        }
+    }
+
+    private class IOemCarServiceCallbackImpl extends IOemCarServiceCallback.Stub {
+        @Override
+        public void sendOemCarServiceReady() {
+            synchronized (mLock) {
+                mIsOemServiceReady = true;
+            }
+            mOemServiceReadyLatch.countDown();
+            int pid = Binder.getCallingPid();
+            Slogf.i(TAG, "OEM Car service is ready and running. Process ID of OEM Car Service is:"
+                    + " %d", pid);
+            mHelper.updateOemPid(pid);
+            mHelper.updateOemStackCall(() -> getOemService().getAllStackTraces());
+            // Initialize other components on handler thread so that main thread is not
+            // blocked
+            mHandler.post(() -> initOemServiceComponents());
+        }
+    }
+}
diff --git a/service/src/com/android/car/oem/CarOemProxyServiceCallback.java b/service/src/com/android/car/oem/CarOemProxyServiceCallback.java
new file mode 100644
index 0000000..277f64d
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemProxyServiceCallback.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.oem;
+
+/**
+ * Callback for other CarService components when OEM service is ready.
+ *
+ * <p>Other CarService components are not expected to call OEM Service during init process. If they
+ * need to make call to OEM service as soon as OEM service is ready, then can register this
+ * callback to {link CarOemProxyService}. This callback will be called for all callback registered
+ * during init calls. The callback will be made only once after OEM service is connected.
+ */
+public interface CarOemProxyServiceCallback {
+    /**
+     * Called when OEM service is ready.
+     */
+    void onOemServiceReady();
+
+}
diff --git a/service/src/com/android/car/oem/CarOemProxyServiceHelper.java b/service/src/com/android/car/oem/CarOemProxyServiceHelper.java
new file mode 100644
index 0000000..9f194f0
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemProxyServiceHelper.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.oem;
+
+import android.annotation.Nullable;
+import android.car.builtin.util.Slogf;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.car.CarLog;
+import com.android.car.R;
+import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+// TODO(b/239698894):Enhance logging to keep track of timeout calls, and dump last 10 timeout calls.
+
+/**
+ * This class does following:
+ * <ul>
+ *   <li>Handles binder call to OEM Service and exposes multiple APIs to call OEM Service.
+ *   <li>Handles OEM service crash.
+ *   <li>Tracks circular call for OEM Service.
+ * </ul>
+ * <p>
+ * If there is more than {@link MAX_CIRCULAR_CALLS_PER_CALLER} circular calls per binder or more
+ * than {@link MAX_CIRCULAR_CALL_TOTAL} circular calls overall, Car Service and OEM service
+ * would be crashed.
+ */
+public final class CarOemProxyServiceHelper {
+
+    private static final String TAG = CarLog.tagFor(CarOemProxyServiceHelper.class);
+    private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+
+    private static final int EXIT_FLAG = 10;
+
+    private static final int MAX_CIRCULAR_CALLS_PER_CALLER = 5;
+    private static final int MAX_CIRCULAR_CALL_TOTAL = 10;
+    private static final int MAX_THREAD_POOL_SIZE = 16;
+    private static final int MIN_THREAD_POOL_SIZE = 8;
+
+    private final Object mLock = new Object();
+
+    private final int mRegularCallTimeoutMs;
+    private final int mCrashCallTimeoutMs;
+    // Kept for dumping
+    private final int mThreadPoolSizeFromRRO;
+
+    // Thread pool size will be read from resource overlay. The default value is 8. The maximum
+    // and minimum thread pool size can be MAX_THREAD_POOL_SIZE and MIN_THREAD_POOL_SIZE
+    // respectively. If resource overlay value is more than MAX_THREAD_POOL_SIZE, then thread
+    // pool size will be MAX_THREAD_POOL_SIZE. If resource overlay value is less than
+    // MIN_THREAD_POOL_SIZE, then thread pool size will be MIN_THREAD_POOL_SIZE.
+    private final int mBinderDispatchThreadPoolSize;
+
+    /**
+     * This map would keep track of possible circular calls
+     * <p>
+     * Ideally there should not be any call from OEM service to Car Service but it may be required
+     * for some reason. In such situation, It is important that it doesn't create circular calls.
+     *
+     * For example:
+     * <ol>
+     *   <li>CarService calling OEM Service
+     *   <li>OEM Service calling car-lib
+     *   <li>Car-lib calling CarService
+     *   <li>CarService calling OEM Service again
+     * </ol>
+     * <p>
+     * This may create infinite loop. If something like this is detected, CarService and OEM Service
+     * would be crashed, and this map would keep track of such circular calls.
+     */
+    @GuardedBy("mLock")
+    private final ArrayMap<String, Integer> mCallerTracker = new ArrayMap<String, Integer>(2);
+
+    private final ExecutorService mThreadPool;
+    @GuardedBy("mLock")
+    private Callable<String> mOemStackTracer;
+    @GuardedBy("mLock")
+    private int mTotalCircularCallsInProcess;
+    @GuardedBy("mLock")
+    private int mOemCarServicePid;
+
+    public CarOemProxyServiceHelper(Context context) {
+        Resources res = context.getResources();
+        mRegularCallTimeoutMs = res
+                .getInteger(R.integer.config_oemCarService_regularCall_timeout_ms);
+        mCrashCallTimeoutMs = res
+                .getInteger(R.integer.config_oemCarService_crashCall_timeout_ms);
+        mThreadPoolSizeFromRRO = res
+                .getInteger(R.integer.config_oemCarService_thread_pool_size);
+        if (mThreadPoolSizeFromRRO > MAX_THREAD_POOL_SIZE) {
+            mBinderDispatchThreadPoolSize = MAX_THREAD_POOL_SIZE;
+        } else if (mThreadPoolSizeFromRRO < MIN_THREAD_POOL_SIZE) {
+            mBinderDispatchThreadPoolSize = MIN_THREAD_POOL_SIZE;
+        } else {
+            mBinderDispatchThreadPoolSize = mThreadPoolSizeFromRRO;
+        }
+
+        mThreadPool = Executors.newFixedThreadPool(mBinderDispatchThreadPoolSize);
+
+        Slogf.i(TAG, "RegularCallTimeoutMs: %d, CrashCallTimeoutMs: %d, ThreadPoolSizeFromRRO: %d,"
+                + " ThreadPoolSize: %d.", mRegularCallTimeoutMs,
+                mCrashCallTimeoutMs, mThreadPoolSizeFromRRO, mBinderDispatchThreadPoolSize);
+    }
+
+    /**
+     * Does timed call to the OEM service and returns default value if OEM service timed out or
+     * throws any other Exception.
+     *
+     * <p>Caller would not know if the call to OEM service timed out or returned a valid value which
+     * could be same as defaultValue. It is preferred way to call OEM service if the defaultValue is
+     * an acceptable result.
+     *
+     * @param <T> Type of the result.
+     * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+     * @param callable containing binder call.
+     * @param defaultValue to be returned if call timeout or any other exception is thrown.
+     *
+     * @return Result of the binder call. Result can be null.
+     */
+    @Nullable
+    public <T> T doBinderTimedCallWithDefaultValue(String callerTag, Callable<T> callable,
+            T defaultValue) {
+        if (DBG) {
+            Slogf.d(TAG, "Received doBinderTimedCallWithDefaultValue call for caller tag: %s.",
+                    callerTag);
+        }
+        startTracking(callerTag);
+        try {
+            Future<T> result = mThreadPool.submit(callable);
+            try {
+                return result.get(mRegularCallTimeoutMs, TimeUnit.MILLISECONDS);
+            } catch (Exception e) {
+                if (e instanceof InterruptedException) {
+                    Thread.currentThread().interrupt(); // Restore the interrupted status
+                }
+                Slogf.w(TAG, "Binder call threw an exception. Return default value %s for caller "
+                        + "tag: %s", defaultValue, callerTag);
+                return defaultValue;
+            }
+        } finally {
+            stopTracking(callerTag);
+        }
+    }
+
+    /**
+     * Does timed call to the OEM service and throws timeout exception.
+     *
+     * <p>Throws timeout exception if OEM service times out. If OEM service throw any other
+     * exception, it is wrapped in Timeout exception.
+     *
+     * @param <T> Type of the result.
+     * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+     * @param callable containing binder call.
+     * @param timeoutMs in milliseconds.
+     *
+     * @return result of the binder call. Result can be null.
+     *
+     * @throws TimeoutException if call times out or throws any other exception.
+     */
+    @Nullable
+    public <T> T doBinderTimedCallWithTimeout(String callerTag, Callable<T> callable,
+            long timeoutMs) throws TimeoutException {
+        if (DBG) {
+            Slogf.d(TAG, "Received doBinderTimedCallWithTimeout call for caller tag: %s.",
+                    callerTag);
+        }
+        startTracking(callerTag);
+        try {
+            Future<T> result = mThreadPool.submit(callable);
+            try {
+                return result.get(timeoutMs, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException | ExecutionException e) {
+                Slogf.w(TAG, "Binder call received Exception", e);
+                if (e instanceof InterruptedException) {
+                    Thread.currentThread().interrupt(); // Restore the interrupted status
+                }
+                // Throw timeout exception even for other exception as caller knows how to handle
+                // timeout exception in this case.
+                TimeoutException exception = new TimeoutException();
+                exception.initCause(e);
+                throw exception;
+            }
+        } finally {
+            stopTracking(callerTag);
+        }
+    }
+
+    /**
+     * Does timed call to OEM service with two different timeouts.
+     *
+     * <p>If OEM service returns before the {@code defaultTimeoutMs}, it would return OEM response.
+     * After {@code defaultTimeoutMs}, call will return {@link Optional#empty()} and queue a tracker
+     * for OEM service response asynchronously. Tracker would wait for {@code mCrashCallTimeoutMs}
+     * for OEM service to response. If OEM service respond before {code mCrashCallTimeoutMs},
+     * callback {@code CallbackForDelayedResult} will be used to post the OEM results on the
+     * original caller. If OEM service doesn't respond within {code mCrashCallTimeoutMs}, CarService
+     * and OEM service both will be crashed.
+     *
+     * <p>This call should be used if it is okay to quickly check for results from OEM Service, and
+     * it is possible to incorporate results from OEM service if delivered late.
+     *
+     * <p>If the binder to OEM service throw any exception during short timeout, it would be ignored
+     * and {@link Optional#empty()} is returned. If the binder to OEM service throw timeout
+     * exception after the longer timeout, it would rash the CarService and OEM Service. If the
+     * binder to OEM service throw any other exception during longer timeout, it would be ignored
+     * and {@link Optional#empty()} is returned.
+     *
+     * @param <T> Type of the result.
+     * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+     * @param callable containing binder call.
+     * @param defaultTimeoutMs in milliseconds.
+     * @param callback for the delayed results. Callback waits for {@code mCrashCallTimeoutMs}.
+     *
+     * @return Optional carrying result of the binder call. Optional can be empty.
+     */
+    public <T> Optional<T> doBinderCallWithDefaultValueAndDelayedWaitAndCrash(String callerTag,
+            Callable<T> callable, long defaultTimeoutMs,
+            CallbackForDelayedResult<T> callback) {
+        if (DBG) {
+            Slogf.d(TAG, "Received doBinderCallWithDefaultValueAndDelayedWaitAndCrash call for"
+                    + " caller tag: %s.", callerTag);
+        }
+        startTracking(callerTag);
+        try {
+            Future<T> result = mThreadPool.submit(callable);
+            try {
+                return Optional.ofNullable(result.get(defaultTimeoutMs, TimeUnit.MILLISECONDS));
+            } catch (Exception e) {
+                if (e instanceof InterruptedException) {
+                    Thread.currentThread().interrupt(); // Restore the interrupted status
+                }
+                Slogf.e(TAG, "Binder call received Exception", e);
+            }
+
+            // Queue for long wait time check
+            mThreadPool.execute(() -> {
+                startTracking(callerTag);
+                try {
+                    callback.onDelayedResults(
+                            Optional.ofNullable(
+                                    result.get(mCrashCallTimeoutMs, TimeUnit.MILLISECONDS)));
+                } catch (TimeoutException e) {
+                    Slogf.e(TAG, "Binder call received TimeoutException", e);
+                    crashCarService("TimeoutException");
+                } catch (InterruptedException | ExecutionException e) {
+                    if (e instanceof InterruptedException) {
+                        Thread.currentThread().interrupt(); // Restore the interrupted status
+                    }
+                    Slogf.e(TAG, "Binder call received Eexception", e);
+                    callback.onDelayedResults(Optional.empty());
+                } finally {
+                    stopTracking(callerTag);
+                }
+            });
+        } finally {
+            stopTracking(callerTag);
+        }
+
+        return Optional.empty();
+    }
+
+    /**
+     * Callback for getting OEM results after default timeout.
+     *
+     * @param <T> Type of the result.
+     */
+    public interface CallbackForDelayedResult<T> {
+        /**
+         * Invoked when OEM results are received after default timeout.
+         *
+         * @param result received from OEM service
+         */
+        void onDelayedResults(Optional<T> result);
+    }
+
+    private void stopTracking(String callerTag) {
+        synchronized (mLock) {
+            if (Binder.getCallingPid() != mOemCarServicePid) return;
+        }
+        // update tracker
+        synchronized (mLock) {
+            int currentCircularCallForTag = mCallerTracker.getOrDefault(callerTag, 0);
+            if (currentCircularCallForTag <= 0 || mTotalCircularCallsInProcess <= 0) {
+                Slogf.wtf(TAG, "Current Circular Calls for %s is %d which is unexpected.",
+                        callerTag, currentCircularCallForTag);
+            }
+            mCallerTracker.put(callerTag, currentCircularCallForTag - 1);
+            mTotalCircularCallsInProcess = mTotalCircularCallsInProcess - 1;
+        }
+    }
+
+    private void startTracking(String callerTag) {
+        synchronized (mLock) {
+            if (Binder.getCallingPid() != mOemCarServicePid) return;
+        }
+
+        int currentCircularCallForTag;
+        int totalCircularCallsInProcess;
+
+        synchronized (mLock) {
+            currentCircularCallForTag = mCallerTracker.getOrDefault(callerTag, 0);
+            totalCircularCallsInProcess = mTotalCircularCallsInProcess;
+        }
+
+        Slogf.w(TAG, "Possible circular call for %s. Current circular calls are %d."
+                + " Total circular calls are %d.", callerTag, currentCircularCallForTag,
+                totalCircularCallsInProcess);
+
+        if (currentCircularCallForTag + 1 > MAX_CIRCULAR_CALLS_PER_CALLER) {
+            Slogf.e(TAG, "Current Circular Calls for %s is %d which is more than the limit %d."
+                    + " Calling to crash CarService", callerTag, (currentCircularCallForTag + 1),
+                    MAX_CIRCULAR_CALLS_PER_CALLER);
+            crashCarService("Max Circular call for " + callerTag);
+        }
+
+        if (totalCircularCallsInProcess + 1 > MAX_CIRCULAR_CALL_TOTAL) {
+            Slogf.e(TAG, "Total Circular Calls is %d which is more than the limit %d."
+                    + " Calling to crash CarService", (totalCircularCallsInProcess + 1),
+                    MAX_CIRCULAR_CALL_TOTAL);
+            crashCarService("Max Circular calls overall");
+        }
+
+        // update tracker
+        synchronized (mLock) {
+            mCallerTracker.put(callerTag, mCallerTracker.getOrDefault(callerTag, 0) + 1);
+            mTotalCircularCallsInProcess = mTotalCircularCallsInProcess + 1;
+        }
+    }
+
+    /**
+     * Does timed call to the OEM service and crashes the OEM and Car Service if call is not served
+     * within time.
+     *
+     * <p>If OEM service throw TimeoutException, it would crash the CarService and OEM service. If
+     * OemService throws any other exception, {@link Optional#empty()} is returned.
+     *
+     * @param <T> Type of the result.
+     * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+     * @param callable containing binder call.
+     *
+     * @return Optional carrying result of the binder call. Optional can be empty.
+     */
+    public <T> Optional<T> doBinderCallWithTimeoutCrash(String callerTag, Callable<T> callable) {
+        if (DBG) {
+            Slogf.d(TAG, "Received doBinderCallWithTimeoutCrash call for caller tag: %s.",
+                    callerTag);
+        }
+        startTracking(callerTag);
+        try {
+            Future<T> result = mThreadPool.submit(callable);
+            try {
+                return Optional.ofNullable(result.get(mCrashCallTimeoutMs, TimeUnit.MILLISECONDS));
+            } catch (TimeoutException e) {
+                Slogf.e(TAG, "Binder call received Exception", e);
+                crashCarService("TimeoutException");
+            } catch (InterruptedException | ExecutionException e) {
+                if (e instanceof InterruptedException) {
+                    Thread.currentThread().interrupt(); // Restore the interrupted status
+                }
+                Slogf.e(TAG, "Binder call received Exception", e);
+                return Optional.empty();
+            }
+        } finally {
+            stopTracking(callerTag);
+        }
+
+        throw new AssertionError("Should not return from crashCarService");
+    }
+
+    /**
+     * Does one way call to OEM Service. Runnable will be queued to threadpool and not waited for
+     * completion.
+     *
+     * <p>It is recommended to use callable with some result if waiting for call to complete is
+     * required.
+     *
+     * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+     * @param runnable containing binder call
+     */
+    public void doBinderOneWayCall(String callerTag, Runnable runnable) {
+        if (DBG) {
+            Slogf.d(TAG, "Received doBinderOneWayCall call for caller tag: %s.", callerTag);
+        }
+
+        mThreadPool.execute(() -> {
+            startTracking(callerTag);
+            try {
+                Future<?> result = mThreadPool.submit(runnable);
+                try {
+                    result.get(mRegularCallTimeoutMs, TimeUnit.MILLISECONDS);
+                } catch (Exception e) {
+                    if (e instanceof InterruptedException) {
+                        Thread.currentThread().interrupt(); // Restore the interrupted status
+                    }
+                    Slogf.e(TAG, "Exception while running a runnable for caller tag: " + callerTag,
+                            e);
+                }
+            } finally {
+                stopTracking(callerTag);
+            }
+        });
+    }
+
+    /**
+     * Crashes CarService and OEM Service.
+     */
+    public void crashCarService(String reason) {
+        Slogf.e(TAG, "****Crashing CarService and OEM service because %s****", reason);
+        Slogf.e(TAG, "Car Service stack-");
+        Slogf.e(TAG, Log.getStackTraceString(new Exception()));
+
+        Callable<String> oemStackTracer = null;
+        synchronized (mLock) {
+            oemStackTracer = mOemStackTracer;
+        }
+
+        if (oemStackTracer != null) {
+            Slogf.e(TAG, "OEM Service stack-");
+            int timeoutMs = 2000;
+            try {
+                String stack = doBinderTimedCallWithTimeout(TAG, oemStackTracer, timeoutMs);
+                Slogf.e(TAG, stack);
+            } catch (TimeoutException e) {
+                Slogf.e(TAG, "Didn't received OEM stack within %d milliseconds.\n", timeoutMs);
+            }
+        }
+
+        int carServicePid = Process.myPid();
+        int oemCarServicePid;
+        synchronized (mLock) {
+            oemCarServicePid = mOemCarServicePid;
+        }
+
+        if (oemCarServicePid != 0) {
+            Slogf.e(TAG, "Killing OEM service process with PID %d.", oemCarServicePid);
+            Process.killProcess(oemCarServicePid);
+        }
+        Slogf.e(TAG, "Killing Car service process with PID %d.", carServicePid);
+        Process.killProcess(carServicePid);
+        System.exit(EXIT_FLAG);
+    }
+
+    /**
+     * Updates PID of the OEM process.
+     */
+    public void updateOemPid(int pid) {
+        synchronized (mLock) {
+            mOemCarServicePid = pid;
+        }
+    }
+
+    /**
+     * Dumps
+     */
+    public void dump(IndentingPrintWriter writer) {
+        writer.println("***CarOemProxyServiceHelper dump***");
+        writer.increaseIndent();
+        synchronized (mLock) {
+            writer.printf("mOemCarServicePid: %d\n", mOemCarServicePid);
+            writer.printf("mCallerTracker.size: %d\n", mCallerTracker.size());
+            if (mCallerTracker.size() > 0) {
+                writer.increaseIndent();
+                for (int i = 0; i < mCallerTracker.size(); i++) {
+                    writer.printf("mCallerTracker entry: %d, CallerTag: %s, CircularCalls: %d\n", i,
+                            mCallerTracker.keyAt(i), mCallerTracker.valueAt(i));
+                }
+                writer.decreaseIndent();
+            }
+            writer.printf("mRegularCallTimeoutMs: %d\n", mRegularCallTimeoutMs);
+            writer.printf("mCrashCallTimeoutMs: %d\n", mCrashCallTimeoutMs);
+            writer.printf("mBinderDispatchThreadPoolSize: %d\n", mBinderDispatchThreadPoolSize);
+            writer.printf("ThreadPoolSizeFromRRO: %d\n", mThreadPoolSizeFromRRO);
+        }
+        writer.decreaseIndent();
+    }
+
+    /**
+     * Updates call for getting OEM stack trace.
+     */
+    public void updateOemStackCall(Callable<String> oemStackTracer) {
+        synchronized (mLock) {
+            mOemStackTracer = oemStackTracer;
+        }
+    }
+}
diff --git a/service/src/com/android/car/power/CarPowerManagementService.java b/service/src/com/android/car/power/CarPowerManagementService.java
index 8caf3ca..8966abb 100644
--- a/service/src/com/android/car/power/CarPowerManagementService.java
+++ b/service/src/com/android/car/power/CarPowerManagementService.java
@@ -569,6 +569,14 @@
         // TODO(b/177478420): Restore Wifi, Audio, Location, and Bluetooth, if they are artificially
         // modified for S2R.
         mSilentModeHandler.querySilentModeHwState();
+
+        applyDefaultPowerPolicyForState(CarPowerManager.STATE_WAIT_FOR_VHAL,
+                    PolicyReader.POWER_POLICY_ID_INITIAL_ON);
+
+        if (!mSilentModeHandler.isSilentMode()) {
+            cancelPreemptivePowerPolicy();
+        }
+
         sendPowerManagerEvent(carPowerStateListenerState, INVALID_TIMEOUT);
         // Inspect CarPowerStateListenerState to decide which message to send via VHAL
         switch (carPowerStateListenerState) {
@@ -1977,23 +1985,25 @@
             }
             // We failed to suspend. Block the thread briefly and try again.
             synchronized (mLock) {
-                if (mPendingPowerStates.isEmpty()) {
-                    Slogf.w(TAG, "Failed to Suspend; will retry after %dms", retryIntervalMs);
-                    try {
-                        mLock.wait(retryIntervalMs);
-                    } catch (InterruptedException ignored) {
-                        Thread.currentThread().interrupt();
-                    }
-                    totalWaitDurationMs += retryIntervalMs;
-                    retryIntervalMs = Math.min(retryIntervalMs * 2, MAX_RETRY_INTERVAL_MS);
-                } else {
+                if (!mPendingPowerStates.isEmpty()) {
                     // Check for a new power state now, before going around the loop again.
                     CpmsState state = mPendingPowerStates.peekFirst();
                     if (state != null && needPowerStateChangeLocked(state)) {
-                        Slogf.i(TAG, "Terminating the attempt to %s", suspendTarget);
+                        Slogf.i(TAG, "Terminating the attempt to suspend target = %s,"
+                                        + " currentState = %s, pendingState = %s", suspendTarget,
+                                mCurrentState.stateToString(), state.stateToString());
                         return false;
                     }
                 }
+
+                Slogf.w(TAG, "Failed to Suspend; will retry after %dms", retryIntervalMs);
+                try {
+                    mLock.wait(retryIntervalMs);
+                } catch (InterruptedException ignored) {
+                    Thread.currentThread().interrupt();
+                }
+                totalWaitDurationMs += retryIntervalMs;
+                retryIntervalMs = Math.min(retryIntervalMs * 2, MAX_RETRY_INTERVAL_MS);
             }
         }
         // Too many failures trying to suspend. Shut down.
diff --git a/service/src/com/android/car/power/PolicyReader.java b/service/src/com/android/car/power/PolicyReader.java
index 9a2e9f3..2fb792c 100644
--- a/service/src/com/android/car/power/PolicyReader.java
+++ b/service/src/com/android/car/power/PolicyReader.java
@@ -36,6 +36,7 @@
 import android.hardware.automotive.vehicle.VehicleApPowerStateReport;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
@@ -98,6 +99,7 @@
     private static final String TAG_OTHER_COMPONENTS = "otherComponents";
     private static final String TAG_COMPONENT = "component";
     private static final String TAG_SYSTEM_POLICY_OVERRIDES = "systemPolicyOverrides";
+    private static final String ATTR_DEFAULT_POLICY_GROUP = "defaultPolicyGroup";
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_ID = "id";
     private static final String ATTR_STATE = "state";
@@ -155,6 +157,7 @@
     private ArrayMap<String, CarPowerPolicy> mRegisteredPowerPolicies;
     private ArrayMap<String, SparseArray<String>> mPolicyGroups;
     private ArrayMap<String, CarPowerPolicy> mPreemptivePowerPolicies;
+    private String mDefaultPolicyGroupId;
 
     /**
      * Gets {@code CarPowerPolicy} corresponding to the given policy ID.
@@ -170,7 +173,8 @@
      */
     @Nullable
     CarPowerPolicy getDefaultPowerPolicyForState(String groupId, int state) {
-        SparseArray<String> group = mPolicyGroups.get(groupId);
+        SparseArray<String> group = mPolicyGroups.get(
+                (groupId == null || groupId.isEmpty()) ? mDefaultPolicyGroupId : groupId);
         if (group == null) {
             return null;
         }
@@ -200,6 +204,16 @@
         return mPreemptivePowerPolicies.containsKey(policyId);
     }
 
+    /**
+     * Gets default power policy group ID.
+     *
+     * @return {@code String} containing power policy group ID or {@code null} if it is not defined
+     */
+    @Nullable
+    String getDefaultPowerPolicyGroup() {
+        return mDefaultPolicyGroupId;
+    }
+
     void init() {
         initPolicies();
         readPowerPolicyConfiguration();
@@ -346,6 +360,7 @@
         ArrayMap<String, CarPowerPolicy> registeredPolicies = new ArrayMap<>();
         ArrayMap<String, SparseArray<String>> policyGroups = new ArrayMap<>();
         CarPowerPolicy systemPolicyOverride = null;
+        String defaultGroupPolicyId = null;
 
         int type;
         while ((type = parser.next()) != END_DOCUMENT && type != END_TAG) {
@@ -355,6 +370,8 @@
                     registeredPolicies = parsePolicies(parser, true);
                     break;
                 case TAG_POLICY_GROUPS:
+                    defaultGroupPolicyId = parser.getAttributeValue(NAMESPACE,
+                            ATTR_DEFAULT_POLICY_GROUP);
                     policyGroups = parsePolicyGroups(parser);
                     break;
                 case TAG_SYSTEM_POLICY_OVERRIDES:
@@ -365,8 +382,9 @@
                             + TAG_POWER_POLICY);
             }
         }
-        validatePolicyGroups(policyGroups, registeredPolicies);
+        validatePolicyGroups(policyGroups, registeredPolicies, defaultGroupPolicyId);
 
+        mDefaultPolicyGroupId = defaultGroupPolicyId;
         mRegisteredPowerPolicies = registeredPolicies;
         registerBasicPowerPolicies();
         mPolicyGroups = policyGroups;
@@ -576,7 +594,8 @@
     }
 
     private void validatePolicyGroups(ArrayMap<String, SparseArray<String>> policyGroups,
-            ArrayMap<String, CarPowerPolicy> registeredPolicies) throws PolicyXmlException {
+            ArrayMap<String, CarPowerPolicy> registeredPolicies, String defaultGroupPolicyId)
+            throws PolicyXmlException {
         for (Map.Entry<String, SparseArray<String>> entry : policyGroups.entrySet()) {
             SparseArray<String> group = entry.getValue();
             for (int i = 0; i < group.size(); i++) {
@@ -587,6 +606,16 @@
                 }
             }
         }
+
+        if ((defaultGroupPolicyId == null || defaultGroupPolicyId.isEmpty())
+                && !policyGroups.isEmpty()) {
+            Log.w(TAG, "No defaultGroupPolicyId is defined");
+        }
+
+        if (defaultGroupPolicyId != null && !policyGroups.containsKey(defaultGroupPolicyId)) {
+            throw new PolicyXmlException(
+                    "defaultGroupPolicyId is defined, but group with this ID doesn't exist ");
+        }
     }
 
     private void reconstructSystemPowerPolicy(@Nullable CarPowerPolicy policyOverride) {
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
index 74e2bbd..91e9af5 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -46,10 +46,12 @@
 
 import com.android.car.CarLog;
 import com.android.car.CarServiceUtils;
+import com.android.car.internal.LargeParcelable;
 import com.android.car.telemetry.CarTelemetryService;
 import com.android.car.telemetry.ResultStore;
 import com.android.car.telemetry.publisher.AbstractPublisher;
 import com.android.car.telemetry.publisher.PublisherFactory;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
 import com.android.car.telemetry.util.IoUtils;
@@ -83,7 +85,6 @@
     /** Maximum wait time for a script to finish. */
     private static final long MAX_SCRIPT_EXECUTION_TIME_MILLIS = 30_000L; // 30 seconds
 
-    // TODO(b/216134347): Find a better way to find the package.
     private static final String[] SCRIPT_EXECUTOR_PACKAGE_CANDIDATES =
             {"com.android.car.scriptexecutor", "com.google.android.car.scriptexecutor"};
     private static final String SCRIPT_EXECUTOR_CLASS =
@@ -487,6 +488,14 @@
                             mCurrentMetricsConfigName);
                 }
                 invokeScriptForLargeInput(task);
+            } else if (task.isBundleList()) {
+                if (DEBUG) {
+                    Slogf.d(CarLog.TAG_TELEMETRY,
+                            "Running with bundle list func %s of %s in ScriptExecutor.",
+                            task.getHandlerName(),
+                            mCurrentMetricsConfigName);
+                }
+                invokeScriptForBundleList(task);
             } else {
                 if (DEBUG) {
                     Slogf.d(CarLog.TAG_TELEMETRY, "Running func %s of %s in ScriptExecutor.",
@@ -549,6 +558,30 @@
         }
     }
 
+    /**
+     * Sends bundle list with LargeParcelable mechanism.
+     *
+     * @param task containing all the necessary parameters for ScriptExecutor API.
+     * @throws RemoteException if ScriptExecutor failed.
+     */
+    private void invokeScriptForBundleList(@NonNull ScriptExecutionTask task)
+            throws RemoteException {
+        BundleList bl = new BundleList();
+        bl.bundles = task.getBundleList();
+        bl = (BundleList) LargeParcelable.toLargeParcelable(
+                bl, () -> {
+                    BundleList bundleList = new BundleList();
+                    bundleList.bundles = new ArrayList<>();
+                    return bundleList;
+                });
+        mScriptExecutor.invokeScriptForBundleList(
+                task.getMetricsConfig().getScript(),
+                task.getHandlerName(),
+                bl,
+                mResultStore.getInterimResult(mCurrentMetricsConfigName),
+                mScriptExecutorListener);
+    }
+
     private TelemetryError buildTelemetryError(
             @NonNull TelemetryError.ErrorType errorType,
             @NonNull String message,
diff --git a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
index ab77318..a560bcc 100644
--- a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
+++ b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
@@ -21,6 +21,7 @@
 import android.os.PersistableBundle;
 import android.os.SystemClock;
 
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -88,6 +89,20 @@
 
     /**
      * Creates a {@link ScriptExecutionTask} and pushes it to the priority queue where the task
+     * will be pending execution.
+     *
+     * @param bundleList The published bundle list data.
+     * @return The number of tasks that are pending execution that are produced by the calling
+     * publisher.
+     */
+    public int push(@NonNull List<PersistableBundle> bundleList) {
+        ScriptExecutionTask task = new ScriptExecutionTask(
+                this, bundleList, SystemClock.elapsedRealtime(), getPublisherType());
+        return mDataBroker.addTaskToQueue(task);
+    }
+
+    /**
+     * Creates a {@link ScriptExecutionTask} and pushes it to the priority queue where the task
      * will be pending execution. Defaults isLargeData flag to false.
      *
      * @param data The published data.
diff --git a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
index 796792c..26881c9 100644
--- a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
+++ b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
@@ -17,9 +17,12 @@
 package com.android.car.telemetry.databroker;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.car.telemetry.TelemetryProto;
 import android.os.PersistableBundle;
 
+import java.util.List;
+
 /**
  * A wrapper class containing all the necessary information to invoke the ScriptExecutor API. It
  * is enqueued into the priority queue where it pends execution by {@link DataBroker}.
@@ -31,8 +34,10 @@
     private final int mPublisherType;
     private final long mTimestampMillis;
     private final DataSubscriber mSubscriber;
-    private final PersistableBundle mData;
-    private final boolean mIsLargeData;
+
+    private PersistableBundle mData = null;
+    private List<PersistableBundle> mBundleList = null;
+    private boolean mIsLargeData = false;
 
     ScriptExecutionTask(
             @NonNull DataSubscriber subscriber,
@@ -47,6 +52,17 @@
         mPublisherType = publisherType;
     }
 
+    ScriptExecutionTask(
+            @NonNull DataSubscriber subscriber,
+            @NonNull List<PersistableBundle> bundleList,
+            long elapsedRealtimeMillis,
+            int publisherType) {
+        mTimestampMillis = elapsedRealtimeMillis;
+        mSubscriber = subscriber;
+        mBundleList = bundleList;
+        mPublisherType = publisherType;
+    }
+
     public int getPublisherType() {
         return mPublisherType;
     }
@@ -74,11 +90,17 @@
     }
 
     /** Returns the data being sent to the subscriber. */
-    @NonNull
+    @Nullable
     public PersistableBundle getData() {
         return mData;
     }
 
+    /** Returns the bundle list data being sent to subscriber. */
+    @Nullable
+    public List<PersistableBundle> getBundleList() {
+        return mBundleList;
+    }
+
     /**
      * Indicates whether the task is associated with MetricsConfig specified by its name.
      */
@@ -93,6 +115,13 @@
         return mIsLargeData;
     }
 
+    /**
+     * Returns if the data is a list of bundles.
+     */
+    public boolean isBundleList() {
+        return mBundleList != null;
+    }
+
     /** Determines if the task is eligible to bypass script executor. */
     public boolean bypassScriptExecutor() {
         return getHandlerName().isEmpty();
diff --git a/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java b/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
index f161cd5..2bc7a8c 100644
--- a/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
@@ -173,7 +173,11 @@
         }
         try {
             for (QueryParam param : mSubscribers.keySet()) {
-                mTransportPreviousNetstats.put(param, getSummaryForAllUid(param));
+                RefinedStats summary = getSummaryForAllUid(param);
+                if (summary == null) {
+                    continue;
+                }
+                mTransportPreviousNetstats.put(param, summary);
             }
         } catch (RemoteException e) {
             // Can't do much if the NetworkStatsService is not available. Next netstats pull
@@ -204,7 +208,7 @@
                 continue;
             }
             PersistableBundle data = previousSessionData.getPersistableBundle(key);
-            if (!data.containsKey(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)) {
+            if (!data.containsKey(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)) {
                 Slogf.e(CarLog.TAG_TELEMETRY,
                         "Session annotations is unexpectedly missing. Skipping this batch.");
                 continue;
@@ -233,13 +237,17 @@
         RefinedStats current;
         try {
             current = getSummaryForAllUid(param);
-        } catch (RemoteException | NullPointerException e) {
+        } catch (RemoteException e) {
             // If the NetworkStatsService is not available, it retries in the next pull.
             Slogf.w(CarLog.TAG_TELEMETRY, e);
             mTraceLog.traceEnd();
             return null;
         }
 
+        if (current == null) {
+            mTraceLog.traceEnd();
+            return null;
+        }
 
         // By subtracting, it calculates network usage since the last pull.
         RefinedStats diff = RefinedStats.subtract(current, previous);
@@ -260,7 +268,7 @@
      *
      * <p>TODO(b/218529196): run this method on a separate thread for better performance.
      */
-    @NonNull
+    @Nullable
     private RefinedStats getSummaryForAllUid(@NonNull QueryParam param) throws RemoteException {
         if (DEBUG) {
             Slogf.d(CarLog.TAG_TELEMETRY, "getSummaryForAllUid " + param);
@@ -273,12 +281,22 @@
                 - elapsedMillisSinceBoot
                 - NETSTATS_UID_DEFAULT_BUCKET_DURATION_MILLIS;
 
-        NetworkStatsWrapper nonTaggedStats =
-                mNetworkStatsManager.querySummary(
-                        param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
-        NetworkStatsWrapper taggedStats =
-                mNetworkStatsManager.queryTaggedSummary(
-                        param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
+        NetworkStatsWrapper nonTaggedStats;
+        NetworkStatsWrapper taggedStats;
+        // querySummary and queryTaggedSummary may throw NPE propagated from NetworkStatsService
+        // when its NetworkStatsRecorder failed to initialize and
+        // NetworkStatsRecorder.getOrLoadCompleteLocked() is called.
+        try {
+            nonTaggedStats =
+                    mNetworkStatsManager.querySummary(
+                            param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
+            taggedStats =
+                    mNetworkStatsManager.queryTaggedSummary(
+                            param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
+        } catch (NullPointerException e) {
+            Slogf.w(CarLog.TAG_TELEMETRY, e);
+            return null;
+        }
 
         RefinedStats result = new RefinedStats(startMillis, currentTimeInMillis);
         result.addNetworkStats(nonTaggedStats);
diff --git a/service/src/com/android/car/telemetry/publisher/Constants.java b/service/src/com/android/car/telemetry/publisher/Constants.java
index edc4b3f..53db170 100644
--- a/service/src/com/android/car/telemetry/publisher/Constants.java
+++ b/service/src/com/android/car/telemetry/publisher/Constants.java
@@ -30,8 +30,56 @@
  * populated.
  */
 public final class Constants {
-    public static final String CAR_TELEMETRYD_BUNDLE_KEY_ID = "id";
-    public static final String CAR_TELEMETRYD_BUNDLE_KEY_CONTENT = "content";
+    // Session Annotations
+    public static final String ANNOTATION_BUNDLE_KEY_SESSION_ID = "session.sessionId";
+    public static final String ANNOTATION_BUNDLE_KEY_SESSION_STATE = "session.sessionState";
+    public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS =
+            "session.createdAtSinceBootMillis";
+    public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS = "session.createdAtMillis";
+    public static final String ANNOTATION_BUNDLE_KEY_BOOT_REASON = "session.bootReason";
+
+    // StatsPublisher
+    public static final String STATS_BUNDLE_KEY_PREFIX = "stats.";
+    public static final String STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP = "stats.elapsed_timestamp_nanos";
+
+    // CarTelemetrydPublisher
+    public static final String CAR_TELEMETRYD_BUNDLE_KEY_ID = "ct.id";
+    public static final String CAR_TELEMETRYD_BUNDLE_KEY_CONTENT = "ct.content";
+
+    // MemoryPublisher
+    public static final String MEMORY_BUNDLE_KEY_PREFIX = "mem.";
+    public static final String MEMORY_BUNDLE_KEY_MEMINFO = "mem.meminfo";
+    public static final String MEMORY_BUNDLE_KEY_TIMESTAMP = "mem.timestamp_millis";
+    public static final String MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS = "mem.total_swappable_pss";
+    public static final String MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY = "mem.total_private_dirty";
+    public static final String MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY = "mem.total_shared_dirty";
+    public static final String MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN = "mem.total_private_clean";
+    public static final String MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN = "mem.total_shared_clean";
+
+    // ConnectivityPublisher
+    public static final String CONNECTIVITY_BUNDLE_KEY_START_MILLIS = "conn.startMillis";
+    public static final String CONNECTIVITY_BUNDLE_KEY_END_MILLIS = "conn.endMillis";
+    public static final String CONNECTIVITY_BUNDLE_KEY_SIZE = "conn.size";
+    public static final String CONNECTIVITY_BUNDLE_KEY_UID = "conn.uid";
+    public static final String CONNECTIVITY_BUNDLE_KEY_PACKAGES = "conn.packages";
+    public static final String CONNECTIVITY_BUNDLE_KEY_TAG = "conn.tag";
+    public static final String CONNECTIVITY_BUNDLE_KEY_RX_BYTES = "conn.rxBytes";
+    public static final String CONNECTIVITY_BUNDLE_KEY_TX_BYTES = "conn.txBytes";
+
+    // VehiclePropertyPublisher
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_TIMESTAMP = "vp.timestamp";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_PROP_ID = "vp.propertyId";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_AREA_ID = "vp.areaId";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_STATUS = "vp.status";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_STRING = "vp.stringVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN = "vp.boolVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_INT = "vp.intVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY = "vp.intArrayVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_LONG = "vp.longVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY = "vp.longArrayVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT = "vp.floatVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY = "vp.floatArrayVal";
+    public static final String VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY = "vp.byteArrayVal";
 
     private Constants() {
     }
diff --git a/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java b/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
index 5c53fd1..7d30fe0 100644
--- a/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
@@ -17,14 +17,20 @@
 package com.android.car.telemetry.publisher;
 
 import android.annotation.NonNull;
+import android.app.ActivityManager;
 import android.car.builtin.os.TraceHelper;
+import android.car.builtin.util.Slogf;
 import android.car.builtin.util.TimingsTraceLog;
 import android.car.telemetry.TelemetryProto;
 import android.car.telemetry.TelemetryProto.Publisher.PublisherCase;
+import android.content.Context;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.PersistableBundle;
+import android.provider.Settings;
 
 import com.android.car.CarLog;
+import com.android.car.telemetry.CarTelemetryService;
 import com.android.car.telemetry.ResultStore;
 import com.android.car.telemetry.databroker.DataSubscriber;
 import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
@@ -36,7 +42,12 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Publisher implementation for {@link TelemetryProto.MemoryPublisher}.
@@ -48,25 +59,45 @@
  *
  * <p>Failure to read from /proc/meminfo will cause a {@link TelemetryProto.TelemetryError} to be
  * returned to the client.
+ *
+ * <p>The published data format is:
+ * <code>
+ * - mem.timestamp_millis :              long
+ * - mem.meminfo :                       string (device meminfo)
+ * - package_name:uid:process_name : PersistableBundle (parsed from Debug.MemInfo, listed below)
+ *   - mem.summary.total-pss : int
+ *   - mem.summary.java-heap : int
+ *   - mem.summary.native-heap : int
+ *   - mem.summary.stack : int
+ *   - mem.summary.system : int
+ *   - mem.summary.code : int
+ *   - mem.summary.graphics : int
+ *   - mem.summary.private-other : int
+ *   - mem.summary.total-swap : int
+ *   - mem.total_shared_clean : int
+ *   - mem.total_shared_dirty : int
+ *   - mem.total_private_clean : int
+ *   - mem.total_private_dirty : int
+ *   - mem.total_swappable_pss : int
+ * </code>
  */
 public class MemoryPublisher extends AbstractPublisher {
 
     private static final int MILLIS_IN_SECOND = 1000;
+    private static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
     @VisibleForTesting
     static final int THROTTLE_MILLIS = 60 * MILLIS_IN_SECOND;
     @VisibleForTesting
     static final String BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH = "num_snapshots_left";
     @VisibleForTesting
     static final String BUNDLE_KEY_COLLECT_INDEFINITELY = "collect_indefinitely";
-    @VisibleForTesting
-    static final String DATA_BUNDLE_KEY_MEMINFO = "meminfo";
-    @VisibleForTesting
-    static final String DATA_BUNDLE_KEY_TIMESTAMP = "timestamp";
 
-    private final Runnable mReadMeminfoRunnable = this::readMemInfo;
+    private final ActivityManager mActivityManager;
+    private final Context mContext;
     private final Handler mTelemetryHandler;
     private final Path mMeminfoPath;
     private final ResultStore mResultStore;
+    private final Runnable mReadMeminfoRunnable = this::readMemInfo;
     private final TimingsTraceLog mTraceLog;
 
     private MemorySubscriberWrapper mSubscriber;
@@ -74,25 +105,29 @@
     private SessionAnnotation mSessionAnnotation;
 
     MemoryPublisher(
+            @NonNull Context context,
             @NonNull PublisherListener listener,
             @NonNull Handler telemetryHandler,
             @NonNull ResultStore resultStore,
             @NonNull SessionController sessionController) {
-        this(listener, telemetryHandler, resultStore, sessionController,
+        this(context, listener, telemetryHandler, resultStore, sessionController,
                 Paths.get("/proc/meminfo"));
     }
 
     @VisibleForTesting
     MemoryPublisher(
+            @NonNull Context context,
             @NonNull PublisherListener listener,
             @NonNull Handler telemetryHandler,
             @NonNull ResultStore resultStore,
             @NonNull SessionController sessionController,
             @NonNull Path meminfoPath) {
         super(listener);
+        mContext = context;
         mTelemetryHandler = telemetryHandler;
         mResultStore = resultStore;
         mMeminfoPath = meminfoPath;
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
         mPublisherState = mResultStore.getPublisherData(
                 MemoryPublisher.class.getSimpleName(), false);
         mTraceLog = new TimingsTraceLog(
@@ -176,10 +211,10 @@
             resetPublisher();
             return;
         }
-        mTraceLog.traceBegin("Reading /proc/meminfo and publishing");
+        mTraceLog.traceBegin("Reading meminfo and publishing");
         // Read timestamp and meminfo and create published data
         PersistableBundle data = new PersistableBundle();
-        data.putLong(DATA_BUNDLE_KEY_TIMESTAMP, System.currentTimeMillis());
+        data.putLong(Constants.MEMORY_BUNDLE_KEY_TIMESTAMP, System.currentTimeMillis());
         String meminfo;
         try {
             meminfo = new String(Files.readAllBytes(mMeminfoPath));
@@ -190,7 +225,12 @@
             mTraceLog.traceEnd();
             return;
         }
-        data.putString(DATA_BUNDLE_KEY_MEMINFO, meminfo);
+        data.putString(Constants.MEMORY_BUNDLE_KEY_MEMINFO, meminfo);
+
+        if (!mSubscriber.mPackageNames.isEmpty()) {
+            readProcessMeminfo(data);
+        }
+
         // add sessions info to published data if available
         if (mSessionAnnotation != null) {
             mSessionAnnotation.addAnnotationsToBundle(data);
@@ -213,13 +253,91 @@
         // if there are too many pending tasks from this publisher, throttle this publisher
         // by reducing the publishing frequency
         int delayMillis = numPendingTasks < mSubscriber.mMaxPendingTasks
-                ? mSubscriber.mPublisherProto.getMemory().getReadIntervalSec() * MILLIS_IN_SECOND
+                ? mSubscriber.mPublisherProto.getReadIntervalSec() * MILLIS_IN_SECOND
                 : THROTTLE_MILLIS;
         // schedule the next Runnable to read meminfo
         mTelemetryHandler.postDelayed(mReadMeminfoRunnable, delayMillis);
         mTraceLog.traceEnd();
     }
 
+    /**
+     * Helper method to get process meminfo statistics from the declared packages in
+     * {@code mSubscriber}. Each process meminfo is a PersistableBundle and it will be put into the
+     * parameter {@code data};
+     */
+    private void readProcessMeminfo(PersistableBundle data) {
+        mTraceLog.traceBegin("reading process meminfo");
+        // update the throttle time for ActivityManager#getProcessMemoryInfo API call
+        String restore = Settings.Global.getString(
+                mContext.getContentResolver(), ACTIVITY_MANAGER_CONSTANTS);
+        Settings.Global.putString(
+                mContext.getContentResolver(),
+                ACTIVITY_MANAGER_CONSTANTS,
+                "memory_info_throttle_time=1");
+        // find PIDs from package names because the API accept an array of PIDs
+        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses =
+                mActivityManager.getRunningAppProcesses();
+        // the 2 lists run in parallel, where pidList.get(i) is the pid of the pkgList.get(i)
+        List<Integer> pidList = new ArrayList<>();
+        List<String> bundleKeys = new ArrayList<>();
+        // find PIDs from package names specified by the MetricsConfig
+        for (ActivityManager.RunningAppProcessInfo process : runningAppProcesses) {
+            // Default apps use package name as process name, some apps will have the format
+            // package_name:process_name, so we extract package name and process name with split
+            String[] split = process.processName.split(":");
+            if (mSubscriber.mPackageNames.contains(split[0])) {
+                if (CarTelemetryService.DEBUG) {
+                    Slogf.d(CarLog.TAG_TELEMETRY,
+                            "MemoryPublisher found matching process " + process.processName);
+                }
+                pidList.add(process.pid);
+                bundleKeys.add(split[0] + ":" + process.uid + ":" + split[split.length - 1]);
+            }
+        }
+
+        // return early if no matching process found
+        if (pidList.size() == 0) {
+            return;
+        }
+
+        // convert ArrayList<Integer> into int[]
+        int[] pids = new int[pidList.size()];
+        for (int i = 0; i < pids.length; i++) {
+            pids[i] = pidList.get(i);
+        }
+        // get process meminfo and parse it into a PersistableBundle
+        Debug.MemoryInfo[] mis = mActivityManager.getProcessMemoryInfo(pids);
+        for (int i = 0; i < mis.length; i++) {
+            Debug.MemoryInfo mi = mis[i];
+            PersistableBundle processMeminfoBundle = new PersistableBundle();
+            processMeminfoBundle.putInt(
+                    Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+                    Integer.valueOf(mi.getTotalSwappablePss()));
+            processMeminfoBundle.putInt(
+                    Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+                    Integer.valueOf(mi.getTotalPrivateDirty()));
+            processMeminfoBundle.putInt(
+                    Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+                    Integer.valueOf(mi.getTotalSharedDirty()));
+            processMeminfoBundle.putInt(
+                    Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+                    Integer.valueOf(mi.getTotalPrivateClean()));
+            processMeminfoBundle.putInt(
+                    Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+                    Integer.valueOf(mi.getTotalSharedClean()));
+            Map<String, String> map = mi.getMemoryStats();
+            for (Map.Entry<String, String> entry : map.entrySet()) {
+                processMeminfoBundle.putInt(Constants.MEMORY_BUNDLE_KEY_PREFIX + entry.getKey(),
+                        Integer.valueOf(entry.getValue()));
+            }
+            data.putPersistableBundle(bundleKeys.get(i), processMeminfoBundle);
+        }
+        // restore the settings constant to the original state
+        Settings.Global.putString(mContext.getContentResolver(),
+                ACTIVITY_MANAGER_CONSTANTS, restore);
+        mTraceLog.traceEnd();
+    }
+
     private static final class MemorySubscriberWrapper {
         /**
          * Whether to keep collecting the meminfo snapshots until end of MetricsConfig lifecycle or
@@ -227,18 +345,20 @@
          * This flag should be set to true when the max_snapshots field is unspecified in
          * {@link TelemetryProto.Publisher}.
          */
-        private boolean mCollectIndefinitely;
+        private final boolean mCollectIndefinitely;
+        /**
+         * Maximum number of memory-related pending tasks before throttling this publisher
+         */
+        private final int mMaxPendingTasks;
+        private final DataSubscriber mDataSubscriber;
+        private final TelemetryProto.MetricsConfig mMetricsConfig;
+        private final TelemetryProto.MemoryPublisher mPublisherProto;
+        private final Set<String> mPackageNames = new HashSet<>();
+
         /**
          * Number of snapshots until the publisher stops collecting data.
          */
         private int mNumSnapshotsLeft;
-        /**
-         * Maximum number of memory-related pending tasks before throttling this publisher
-         */
-        private int mMaxPendingTasks;
-        private DataSubscriber mDataSubscriber;
-        private TelemetryProto.MetricsConfig mMetricsConfig;
-        private TelemetryProto.Publisher mPublisherProto;
 
         private MemorySubscriberWrapper(
                 DataSubscriber dataSubscriber, int numSnapshotsLeft, boolean collectIndefinitely) {
@@ -246,8 +366,9 @@
             mNumSnapshotsLeft = numSnapshotsLeft;
             mCollectIndefinitely = collectIndefinitely;
             mMetricsConfig = dataSubscriber.getMetricsConfig();
-            mPublisherProto = dataSubscriber.getPublisherParam();
-            mMaxPendingTasks = mPublisherProto.getMemory().getMaxPendingTasks();
+            mPublisherProto = dataSubscriber.getPublisherParam().getMemory();
+            mMaxPendingTasks = mPublisherProto.getMaxPendingTasks();
+            mPackageNames.addAll(mPublisherProto.getPackageNamesList());
         }
 
         /** Publishes data and returns the number of pending tasks by this publisher. */
@@ -255,7 +376,10 @@
             if (mNumSnapshotsLeft > 0) {
                 mNumSnapshotsLeft--;
             }
-            return mDataSubscriber.push(data);
+            boolean isLargeData =
+                    data.toString().length() >= DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES
+                            ? true : false;
+            return mDataSubscriber.push(data, isLargeData);
         }
 
         private boolean isDone() {
diff --git a/service/src/com/android/car/telemetry/publisher/PublisherFactory.java b/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
index 546ffea..8866831 100644
--- a/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
+++ b/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
@@ -123,7 +123,7 @@
                 case TelemetryProto.Publisher.MEMORY_FIELD_NUMBER:
                     if (mMemoryPublisher == null) {
                         mMemoryPublisher = new MemoryPublisher(
-                                mPublisherListener, mTelemetryHandler, mResultStore,
+                                mContext, mPublisherListener, mTelemetryHandler, mResultStore,
                                 mSessionController);
                     }
                     return mMemoryPublisher;
diff --git a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
index 328ef2c..2897f2c 100644
--- a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
@@ -21,6 +21,7 @@
 import static com.android.car.telemetry.AtomsProto.Atom.APP_CRASH_OCCURRED_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.Atom.APP_START_MEMORY_STATE_CAPTURED_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_CPU_TIME_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_MEMORY_STATE_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.Atom.WTF_OCCURRED_FIELD_NUMBER;
 import static com.android.car.telemetry.CarTelemetryService.DEBUG;
@@ -41,6 +42,7 @@
 
 import com.android.car.CarLog;
 import com.android.car.telemetry.AtomsProto.ProcessCpuTime;
+import com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot;
 import com.android.car.telemetry.AtomsProto.ProcessMemoryState;
 import com.android.car.telemetry.ResultStore;
 import com.android.car.telemetry.StatsLogProto;
@@ -98,6 +100,10 @@
     static final long WTF_OCCURRED_ATOM_MATCHER_ID = 13;
     @VisibleForTesting
     static final long WTF_OCCURRED_EVENT_METRIC_ID = 14;
+    @VisibleForTesting
+    static final long PROCESS_MEMORY_SNAPSHOT_ATOM_MATCHER_ID = 15;
+    @VisibleForTesting
+    static final long PROCESS_MEMORY_SNAPSHOT_GAUGE_METRIC_ID = 16;
 
     // TODO(b/202115033): Flatten the load spike by pulling reports for each MetricsConfigs
     //                    using separate periodical timers.
@@ -135,6 +141,30 @@
                             .setField(ProcessCpuTime.SYSTEM_TIME_MILLIS_FIELD_NUMBER))
                     .build();
 
+    @VisibleForTesting
+    static final StatsdConfigProto.FieldMatcher PROCESS_MEMORY_SNAPSHOT_FIELDS_MATCHER =
+            StatsdConfigProto.FieldMatcher.newBuilder()
+                    .setField(
+                            PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot.PID_FIELD_NUMBER))
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot.OOM_SCORE_ADJ_FIELD_NUMBER))
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot.RSS_IN_KILOBYTES_FIELD_NUMBER))
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot.ANON_RSS_IN_KILOBYTES_FIELD_NUMBER))
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot.SWAP_IN_KILOBYTES_FIELD_NUMBER))
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot
+                                    .ANON_RSS_AND_SWAP_IN_KILOBYTES_FIELD_NUMBER))
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot.GPU_MEMORY_KB_FIELD_NUMBER))
+                    .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                            .setField(ProcessMemorySnapshot.HAS_FOREGROUND_SERVICES_FIELD_NUMBER))
+                    .build();
+
     private final StatsManagerProxy mStatsManager;
     private final ResultStore mResultStore;
     private final Handler mTelemetryHandler;
@@ -192,12 +222,10 @@
 
         if (!mIsPullingReports) {
             if (DEBUG) {
-                Slogf.d(CarLog.TAG_TELEMETRY, "Stats report will be pulled in "
-                        + PULL_REPORTS_PERIOD.toMinutes() + " minutes.");
+                Slogf.d(CarLog.TAG_TELEMETRY, "Triggering pull stats reports");
             }
             mIsPullingReports = true;
-            mTelemetryHandler.postDelayed(
-                    mPullReportsPeriodically, PULL_REPORTS_PERIOD.toMillis());
+            mTelemetryHandler.post(mPullReportsPeriodically);
         }
     }
 
@@ -247,12 +275,17 @@
             case WTF_OCCURRED:
                 metricId = WTF_OCCURRED_EVENT_METRIC_ID;
                 break;
+            case PROCESS_MEMORY_SNAPSHOT:
+                metricId = PROCESS_MEMORY_SNAPSHOT_GAUGE_METRIC_ID;
+                break;
             default:
                 return;
         }
         if (!metricBundles.containsKey(metricId)) {
             Slogf.w(CarLog.TAG_TELEMETRY,
-                    "No reports for metric id " + metricId + " for config " + configKey);
+                    "No reports for metric id " + metricId + " ("
+                            + subscriber.getPublisherParam().getStats().getSystemMetric()
+                            + ") for config " + configKey);
             return;
         }
         PersistableBundle bundle = metricBundles.get(metricId);
@@ -551,6 +584,8 @@
                 return buildAnrOccurredStatsdConfig(builder);
             case WTF_OCCURRED:
                 return buildWtfOccurredStatsdConfig(builder);
+            case PROCESS_MEMORY_SNAPSHOT:
+                return buildProcessMemorySnapshotStatsdConfig(builder);
             default:
                 throw new IllegalArgumentException("Unsupported metric " + metric.name());
         }
@@ -702,6 +737,39 @@
                 .build();
     }
 
+    @NonNull
+    private static StatsdConfig buildProcessMemorySnapshotStatsdConfig(
+            @NonNull StatsdConfig.Builder builder) {
+        return builder
+                .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
+                        // The id must be unique within StatsdConfig/matchers
+                        .setId(PROCESS_MEMORY_SNAPSHOT_ATOM_MATCHER_ID)
+                        .setSimpleAtomMatcher(StatsdConfigProto.SimpleAtomMatcher.newBuilder()
+                                .setAtomId(PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)))
+                .addGaugeMetric(StatsdConfigProto.GaugeMetric.newBuilder()
+                        // The id must be unique within StatsdConfig/metrics
+                        .setId(PROCESS_MEMORY_SNAPSHOT_GAUGE_METRIC_ID)
+                        .setWhat(PROCESS_MEMORY_SNAPSHOT_ATOM_MATCHER_ID)
+                        .setDimensionsInWhat(StatsdConfigProto.FieldMatcher.newBuilder()
+                                .setField(PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)
+                                .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                                        .setField(ProcessMemorySnapshot.UID_FIELD_NUMBER))
+                                .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+                                        .setField(ProcessMemorySnapshot.PROCESS_NAME_FIELD_NUMBER))
+                        )
+                        .setGaugeFieldsFilter(StatsdConfigProto.FieldFilter.newBuilder()
+                                .setFields(PROCESS_MEMORY_SNAPSHOT_FIELDS_MATCHER)
+                        )  // setGaugeFieldsFilter
+                        .setSamplingType(
+                                StatsdConfigProto.GaugeMetric.SamplingType.RANDOM_ONE_SAMPLE)
+                        .setBucket(StatsdConfigProto.TimeUnit.FIVE_MINUTES)
+                )
+                .addPullAtomPackages(StatsdConfigProto.PullAtomPackages.newBuilder()
+                        .setAtomId(PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)
+                        .addPackages("AID_SYSTEM"))
+                .build();
+    }
+
     @Override
     protected void handleSessionStateChange(SessionAnnotation annotation) {}
 }
diff --git a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
index 95f9184..8db436a 100644
--- a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
@@ -16,6 +16,8 @@
 
 package com.android.car.telemetry.publisher;
 
+import static com.android.car.telemetry.CarTelemetryService.DEBUG;
+
 import static java.lang.Integer.toHexString;
 
 import android.annotation.NonNull;
@@ -38,9 +40,11 @@
 import com.android.car.CarPropertyService;
 import com.android.car.telemetry.databroker.DataSubscriber;
 import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -50,32 +54,12 @@
  * property id of the subscriber and starts pushing the change events to the subscriber.
  */
 public class VehiclePropertyPublisher extends AbstractPublisher {
-    private static final boolean DEBUG = false;  // STOPSHIP if true
-
-    public static final String BUNDLE_TIMESTAMP_KEY = "timestamp";
-    public static final String BUNDLE_STRING_KEY = "stringVal";
-    public static final String BUNDLE_BOOLEAN_KEY = "boolVal";
-    public static final String BUNDLE_INT_KEY = "intVal";
-    public static final String BUNDLE_INT_ARRAY_KEY = "intArrayVal";
-    public static final String BUNDLE_LONG_KEY = "longVal";
-    public static final String BUNDLE_LONG_ARRAY_KEY = "longArrayVal";
-    public static final String BUNDLE_FLOAT_KEY = "floatVal";
-    public static final String BUNDLE_FLOAT_ARRAY_KEY = "floatArrayVal";
-    public static final String BUNDLE_BYTE_ARRAY_KEY = "byteArrayVal";
 
     private final CarPropertyService mCarPropertyService;
     private final Handler mTelemetryHandler;
-
     // The class only reads, no need to synchronize this object.
     // Maps property_id to CarPropertyConfig.
     private final SparseArray<CarPropertyConfig> mCarPropertyList;
-
-    // SparseArray and ArraySet are memory optimized, but they can be bit slower for more
-    // than 100 items. We're expecting much less number of subscribers, so these DS are ok.
-    // Maps property_id to the set of DataSubscriber.
-    private final SparseArray<ArraySet<DataSubscriber>> mCarPropertyToSubscribers =
-            new SparseArray<>();
-
     private final ICarPropertyEventListener mCarPropertyEventListener =
             new ICarPropertyEventListener.Stub() {
                 @Override
@@ -90,6 +74,11 @@
                 }
             };
 
+    // Maps property id to the PropertyData containing batch of its bundles and subscribers.
+    // Each property is batched separately.
+    private final SparseArray<PropertyData> mPropertyDataLookup = new SparseArray<>();
+    private long mBatchIntervalMillis = 100L;  // Batch every 100 milliseconds = 10Hz
+
     public VehiclePropertyPublisher(
             @NonNull CarPropertyService carPropertyService,
             @NonNull PublisherListener listener,
@@ -122,18 +111,18 @@
                         || config.getAccess()
                         == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
                 "No access. Cannot read " + VehiclePropertyIds.toString(propertyId) + ".");
-
-        ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
-        if (subscribers == null) {
-            subscribers = new ArraySet<>();
-            mCarPropertyToSubscribers.put(propertyId, subscribers);
-            // Register the listener only once per propertyId.
+        PropertyData propertyData = mPropertyDataLookup.get(propertyId);
+        if (propertyData == null) {
+            propertyData = new PropertyData(config);
+            mPropertyDataLookup.put(propertyId, propertyData);
+        }
+        if (propertyData.subscribers.isEmpty()) {
             mCarPropertyService.registerListener(
                     propertyId,
                     publisherParam.getVehicleProperty().getReadRate(),
                     mCarPropertyEventListener);
         }
-        subscribers.add(subscriber);
+        propertyData.subscribers.add(subscriber);
     }
 
     @Override
@@ -146,14 +135,13 @@
             return;
         }
         int propertyId = publisherParam.getVehicleProperty().getVehiclePropertyId();
-
-        ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
-        if (subscribers == null) {
+        PropertyData propertyData = mPropertyDataLookup.get(propertyId);
+        if (propertyData == null) {
             return;
         }
-        subscribers.remove(subscriber);
-        if (subscribers.isEmpty()) {
-            mCarPropertyToSubscribers.remove(propertyId);
+        propertyData.subscribers.remove(subscriber);
+        if (propertyData.subscribers.isEmpty()) {
+            mPropertyDataLookup.remove(propertyId);
             // Doesn't throw exception as listener is not null. mCarPropertyService and
             // local mCarPropertyToSubscribers will not get out of sync.
             mCarPropertyService.unregisterListener(propertyId, mCarPropertyEventListener);
@@ -162,13 +150,13 @@
 
     @Override
     public void removeAllDataSubscribers() {
-        for (int i = 0; i < mCarPropertyToSubscribers.size(); i++) {
-            int propertyId = mCarPropertyToSubscribers.keyAt(i);
+        for (int i = 0; i < mPropertyDataLookup.size(); i++) {
             // Doesn't throw exception as listener is not null. mCarPropertyService and
             // local mCarPropertyToSubscribers will not get out of sync.
-            mCarPropertyService.unregisterListener(propertyId, mCarPropertyEventListener);
+            mCarPropertyService.unregisterListener(
+                    mPropertyDataLookup.keyAt(i), mCarPropertyEventListener);
         }
-        mCarPropertyToSubscribers.clear();
+        mPropertyDataLookup.clear();
     }
 
     @Override
@@ -178,10 +166,18 @@
             return false;
         }
         int propertyId = publisherParam.getVehicleProperty().getVehiclePropertyId();
-        ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
-        return subscribers != null && subscribers.contains(subscriber);
+        return mPropertyDataLookup.contains(propertyId)
+                && mPropertyDataLookup.get(propertyId).subscribers.contains(subscriber);
     }
 
+    @VisibleForTesting
+    public void setBatchIntervalMillis(long intervalMillis) {
+        mBatchIntervalMillis = intervalMillis;
+    }
+
+    @Override
+    protected void handleSessionStateChange(SessionAnnotation annotation) {}
+
     /**
      * Called when publisher receives new event. It's executed on a CarPropertyService's
      * worker thread.
@@ -190,103 +186,127 @@
         // move the work from CarPropertyService's worker thread to the telemetry thread
         mTelemetryHandler.post(() -> {
             CarPropertyValue propValue = event.getCarPropertyValue();
+            int propertyId = propValue.getPropertyId();
+            PropertyData propertyData = mPropertyDataLookup.get(propertyId);
             PersistableBundle bundle = parseCarPropertyValue(
-                    propValue, mCarPropertyList.get(propValue.getPropertyId()).getConfigArray());
-            for (DataSubscriber subscriber
-                    : mCarPropertyToSubscribers.get(propValue.getPropertyId())) {
-                subscriber.push(bundle);
+                    propValue, propertyData.config.getConfigArray());
+            propertyData.pendingData.add(bundle);
+            if (propertyData.pendingData.size() == 1) {
+                mTelemetryHandler.postDelayed(
+                        () -> {
+                            pushPendingDataToSubscribers(propertyData);
+                        },
+                        mBatchIntervalMillis);
             }
         });
     }
 
     /**
+     * Pushes bundle batch to subscribers and resets batch.
+     */
+    private void pushPendingDataToSubscribers(PropertyData propertyData) {
+        for (DataSubscriber subscriber : propertyData.subscribers) {
+            subscriber.push(propertyData.pendingData);
+        }
+        propertyData.pendingData = new ArrayList<>();
+    }
+
+    /**
      * Parses the car property value into a PersistableBundle.
      */
     private PersistableBundle parseCarPropertyValue(
             CarPropertyValue propValue, List<Integer> configArray) {
-        Object value = propValue.getValue();
         PersistableBundle bundle = new PersistableBundle();
-        bundle.putLong(BUNDLE_TIMESTAMP_KEY, propValue.getTimestamp());
+        bundle.putLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_TIMESTAMP, propValue.getTimestamp());
+        bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_PROP_ID, propValue.getPropertyId());
+        bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_AREA_ID, propValue.getAreaId());
+        bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STATUS, propValue.getStatus());
         int type = propValue.getPropertyId() & VehiclePropertyType.MASK;
+        Object value = propValue.getValue();
         if (VehiclePropertyType.BOOLEAN == type) {
-            bundle.putBoolean(BUNDLE_BOOLEAN_KEY, (Boolean) value);
+            bundle.putBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN, (Boolean) value);
         } else if (VehiclePropertyType.FLOAT == type) {
-            bundle.putDouble(BUNDLE_FLOAT_KEY, ((Float) value).doubleValue());
+            bundle.putDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT,
+                    ((Float) value).doubleValue());
         } else if (VehiclePropertyType.INT32 == type) {
-            bundle.putInt(BUNDLE_INT_KEY, (Integer) value);
+            bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT, (Integer) value);
         } else if (VehiclePropertyType.INT64 == type) {
-            bundle.putLong(BUNDLE_LONG_KEY, (Long) value);
+            bundle.putLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG, (Long) value);
         } else if (VehiclePropertyType.FLOAT_VEC == type) {
             Float[] floats = (Float[]) value;
             double[] doubles = new double[floats.length];
             for (int i = 0; i < floats.length; i++) {
                 doubles[i] = floats[i].doubleValue();
             }
-            bundle.putDoubleArray(BUNDLE_FLOAT_ARRAY_KEY, doubles);
+            bundle.putDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY, doubles);
         } else if (VehiclePropertyType.INT32_VEC == type) {
             Integer[] integers = (Integer[]) value;
             int[] ints = new int[integers.length];
             for (int i = 0; i < integers.length; i++) {
                 ints[i] = integers[i];
             }
-            bundle.putIntArray(BUNDLE_INT_ARRAY_KEY, ints);
+            bundle.putIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY, ints);
         } else if (VehiclePropertyType.INT64_VEC == type) {
             Long[] oldLongs = (Long[]) value;
             long[] longs = new long[oldLongs.length];
             for (int i = 0; i < oldLongs.length; i++) {
                 longs[i] = oldLongs[i];
             }
-            bundle.putLongArray(BUNDLE_LONG_ARRAY_KEY, longs);
+            bundle.putLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY, longs);
         } else if (VehiclePropertyType.STRING == type) {
-            bundle.putString(BUNDLE_STRING_KEY, (String) value);
+            bundle.putString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING, (String) value);
         } else if (VehiclePropertyType.BYTES == type) {
             bundle.putString(
-                    BUNDLE_BYTE_ARRAY_KEY, new String((byte[]) value, StandardCharsets.UTF_8));
+                    Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY,
+                    new String((byte[]) value, StandardCharsets.UTF_8));
         } else if (VehiclePropertyType.MIXED == type) {
             Object[] mixed = (Object[]) value;
             int k = 0;
             if (configArray.get(0) == 1) {  // Has single String
-                bundle.putString(BUNDLE_STRING_KEY, (String) mixed[k++]);
+                bundle.putString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING, (String) mixed[k++]);
             }
             if (configArray.get(1) == 1) {  // Has single Boolean
-                bundle.putBoolean(BUNDLE_BOOLEAN_KEY, (Boolean) mixed[k++]);
+                bundle.putBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN,
+                        (Boolean) mixed[k++]);
             }
             if (configArray.get(2) == 1) {  // Has single Integer
-                bundle.putInt(BUNDLE_INT_KEY, (Integer) mixed[k++]);
+                bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT, (Integer) mixed[k++]);
             }
             if (configArray.get(3) != 0) {  // Integer[] length is non-zero
                 int[] ints = new int[configArray.get(3)];
                 for (int i = 0; i < configArray.get(3); i++) {
                     ints[i] = (Integer) mixed[k++];
                 }
-                bundle.putIntArray(BUNDLE_INT_ARRAY_KEY, ints);
+                bundle.putIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY, ints);
             }
             if (configArray.get(4) == 1) {  // Has single Long
-                bundle.putLong(BUNDLE_LONG_KEY, (Long) mixed[k++]);
+                bundle.putLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG, (Long) mixed[k++]);
             }
             if (configArray.get(5) != 0) {  // Long[] length is non-zero
                 long[] longs = new long[configArray.get(5)];
                 for (int i = 0; i < configArray.get(5); i++) {
                     longs[i] = (Long) mixed[k++];
                 }
-                bundle.putLongArray(BUNDLE_LONG_ARRAY_KEY, longs);
+                bundle.putLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY, longs);
             }
             if (configArray.get(6) == 1) {  // Has single Float
-                bundle.putDouble(BUNDLE_FLOAT_KEY, ((Float) mixed[k++]).doubleValue());
+                bundle.putDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT,
+                        ((Float) mixed[k++]).doubleValue());
             }
             if (configArray.get(7) != 0) {  // Float[] length is non-zero
                 double[] doubles = new double[configArray.get(7)];
                 for (int i = 0; i < configArray.get(7); i++) {
                     doubles[i] = ((Float) mixed[k++]).doubleValue();
                 }
-                bundle.putDoubleArray(BUNDLE_FLOAT_ARRAY_KEY, doubles);
+                bundle.putDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY, doubles);
             }
             if (configArray.get(8) != 0) {  // Byte[] length is non-zero
                 byte[] bytes = new byte[configArray.get(8)];
                 for (int i = 0; i < configArray.get(8); i++) {
                     bytes[i] = (Byte) mixed[k++];
                 }
-                bundle.putString(BUNDLE_BYTE_ARRAY_KEY, new String(bytes, StandardCharsets.UTF_8));
+                bundle.putString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY,
+                        new String(bytes, StandardCharsets.UTF_8));
             }
         } else {
             throw new IllegalArgumentException(
@@ -295,6 +315,19 @@
         return bundle;
     }
 
-    @Override
-    protected void handleSessionStateChange(SessionAnnotation annotation) {}
+    /**
+     * Container class holding all the relevant information for a property.
+     */
+    private static final class PropertyData {
+        // The config containing info on how to parse the property value.
+        public final CarPropertyConfig config;
+        // Subscribers subscribed to the property this PropertyData is mapped to.
+        public final ArraySet<DataSubscriber> subscribers = new ArraySet<>();
+        // The list of bundles that are batched together and pushed to subscribers
+        public List<PersistableBundle> pendingData = new ArrayList<>();
+
+        PropertyData(CarPropertyConfig propConfig) {
+            config = propConfig;
+        }
+    }
 }
diff --git a/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java b/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java
index 9789254..9d1dccc 100644
--- a/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java
+++ b/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java
@@ -23,6 +23,7 @@
 import com.android.car.internal.util.IntArray;
 import com.android.car.internal.util.LongArray;
 import com.android.car.telemetry.UidPackageMapper;
+import com.android.car.telemetry.publisher.Constants;
 
 /**
  * Restructured {@link NetworkStats} to simplify subtract/add arithmetics, as well as converting
@@ -147,20 +148,20 @@
     @NonNull
     public PersistableBundle toPersistableBundle(@NonNull UidPackageMapper uidMapper) {
         PersistableBundle data = new PersistableBundle();
-        data.putLong("startMillis", mStartMillis);
-        data.putLong("endMillis", mEndMillis);
-        data.putInt("size", mUid.size());
+        data.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS, mStartMillis);
+        data.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS, mEndMillis);
+        data.putInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE, mUid.size());
         // TODO(b/218596960): send empty array anyway for data schema consistency.
         if (mUid.size() > 0) {
-            data.putIntArray("uid", mUid.toArray());
+            data.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID, mUid.toArray());
             String[] packages = new String[mUid.size()];
             for (int i = 0; i < mUid.size(); i++) {
                 packages[i] = String.join(",", uidMapper.getPackagesForUid(mUid.get(i)));
             }
-            data.putStringArray("packages", packages);
-            data.putIntArray("tag", mTag.toArray());
-            data.putLongArray("rxBytes", mRxBytes.toArray());
-            data.putLongArray("txBytes", mTxBytes.toArray());
+            data.putStringArray(Constants.CONNECTIVITY_BUNDLE_KEY_PACKAGES, packages);
+            data.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG, mTag.toArray());
+            data.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES, mRxBytes.toArray());
+            data.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES, mTxBytes.toArray());
         }
         return data;
     }
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java
index c01d483..14d969d 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java
@@ -16,6 +16,8 @@
 
 package com.android.car.telemetry.publisher.statsconverters;
 
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.PersistableBundle;
@@ -123,7 +125,7 @@
                     valueList.add(atomFieldAccessor.getField(atomData));
                 }
                 setPersistableBundleArrayField(
-                        atomFieldAccessor.getFieldName(), valueList, bundle);
+                        createBundleKey(atomFieldAccessor.getFieldName()), valueList, bundle);
             }
         }
         // Check if there are dimension fields needing conversion
@@ -139,7 +141,7 @@
                 valueList.add(extractDimensionsValue(dvList.get(i), hashToStringMap));
             }
             setPersistableBundleArrayField(
-                    getAtomFieldAccessorMap().get(fieldId).getFieldName(),
+                    createBundleKey(getAtomFieldAccessorMap().get(fieldId).getFieldName()),
                     valueList,
                     bundle);
         }
@@ -227,4 +229,16 @@
             bundle.putDoubleArray(name, doubleArray);
         }
     }
+
+    /**
+     * Creates the bundle key string for a metric field.
+     *
+     * The bundle key differs from the original metric field name by having a namespace prefix.
+     *
+     * @param metricFieldName the metric field name string.
+     * @return the bundle key string.
+     */
+    private String createBundleKey(String metricFieldName) {
+        return STATS_BUNDLE_KEY_PREFIX + metricFieldName;
+    }
 }
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java
index c9227f5..85e0eae 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java
@@ -44,7 +44,8 @@
     // Map of pulled atom cases to corresponding atom converter.
     private static Map<Atom.PulledCase, AbstractAtomConverter<?>> sPulledCaseConverters = Map.of(
             Atom.PulledCase.PROCESS_MEMORY_STATE, new ProcessMemoryStateConverter(),
-            Atom.PulledCase.PROCESS_CPU_TIME, new ProcessCpuTimeConverter());
+            Atom.PulledCase.PROCESS_CPU_TIME, new ProcessCpuTimeConverter(),
+            Atom.PulledCase.PROCESS_MEMORY_SNAPSHOT, new ProcessMemorySnapshotConverter());
 
     /**
      * Converts a list of atoms to separate the atoms fields values into arrays to be put into the
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java
index 38be940..ad72e73 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java
@@ -16,6 +16,8 @@
 
 package com.android.car.telemetry.publisher.statsconverters;
 
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+
 import android.annotation.NonNull;
 import android.os.PersistableBundle;
 
@@ -29,8 +31,6 @@
  * Class for converting event metric data to {@link PersistableBundle} compatible format.
  */
 public class EventMetricDataConverter {
-    static final String ELAPSED_TIME_NANOS = "elapsed_timestamp_nanos";
-
     /**
      * Converts a list of {@link StatsLogProto.EventMetricData} to {@link PersistableBundle} format
      * such that along with the elapsed time array each field of the atom has an associated array
@@ -67,7 +67,7 @@
         for (int i = 0; i < elapsedTimes.size(); ++i) {
             elapsedTimesArray[i] = elapsedTimes.get(i);
         }
-        bundle.putLongArray(ELAPSED_TIME_NANOS, elapsedTimesArray);
+        bundle.putLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP, elapsedTimesArray);
         return bundle;
     }
 }
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java
index cc29aa4..d260e04 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java
@@ -16,6 +16,8 @@
 
 package com.android.car.telemetry.publisher.statsconverters;
 
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.PersistableBundle;
@@ -34,8 +36,6 @@
  * Class for converting gauge metric data to {@link PersistableBundle} compatible format.
  */
 public class GaugeMetricDataConverter {
-    static final String ELAPSED_TIME_NANOS = "elapsed_timestamp_nanos";
-
     /**
      * Converts a list of {@link StatsLogProto.GaugeMetricData} to {@link PersistableBundle}
      * format such that along with the elapsed time array each field of the atom has an associated
@@ -97,7 +97,7 @@
         for (int i = 0; i < elapsedTimes.size(); ++i) {
             elapsedTimesArray[i] = elapsedTimes.get(i);
         }
-        bundle.putLongArray(ELAPSED_TIME_NANOS, elapsedTimesArray);
+        bundle.putLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP, elapsedTimesArray);
         return bundle;
     }
 }
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverter.java
new file mode 100644
index 0000000..42845e8
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverter.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry.publisher.statsconverters;
+
+import android.annotation.NonNull;
+import android.util.SparseArray;
+
+import com.android.car.telemetry.AtomsProto.Atom;
+import com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Atom data converter for atoms of type {@link ProcessMemorySnapshot}.
+ */
+public class ProcessMemorySnapshotConverter extends AbstractAtomConverter<ProcessMemorySnapshot> {
+
+    private static final SparseArray<AtomFieldAccessor<ProcessMemorySnapshot, ?>>
+            sAtomFieldAccessorMap = new SparseArray<>();
+    static {
+        sAtomFieldAccessorMap.append(1, new AtomFieldAccessor<>(
+                "uid",
+                a -> a.hasUid(),
+                a -> a.getUid()
+        ));
+        sAtomFieldAccessorMap.append(2, new AtomFieldAccessor<>(
+                "process_name",
+                a -> a.hasProcessName(),
+                a -> a.getProcessName()
+        ));
+        sAtomFieldAccessorMap.append(3, new AtomFieldAccessor<>(
+                "pid",
+                a -> a.hasPid(),
+                a -> a.getPid()
+        ));
+        sAtomFieldAccessorMap.append(4, new AtomFieldAccessor<>(
+                "oom_score_adj",
+                a -> a.hasOomScoreAdj(),
+                a -> a.getOomScoreAdj()
+        ));
+        sAtomFieldAccessorMap.append(5, new AtomFieldAccessor<>(
+                "rss_in_kilobytes",
+                a -> a.hasRssInKilobytes(),
+                a -> a.getRssInKilobytes()
+        ));
+        sAtomFieldAccessorMap.append(6, new AtomFieldAccessor<>(
+                "anon_rss_in_kilobytes",
+                a -> a.hasAnonRssInKilobytes(),
+                a -> a.getAnonRssInKilobytes()
+        ));
+        sAtomFieldAccessorMap.append(7, new AtomFieldAccessor<>(
+                "swap_in_kilobytes",
+                a -> a.hasSwapInKilobytes(),
+                a -> a.getSwapInKilobytes()
+        ));
+        sAtomFieldAccessorMap.append(8, new AtomFieldAccessor<>(
+                "anon_rss_and_swap_in_kilobytes",
+                a -> a.hasAnonRssAndSwapInKilobytes(),
+                a -> a.getAnonRssAndSwapInKilobytes()
+        ));
+        sAtomFieldAccessorMap.append(9, new AtomFieldAccessor<>(
+                "gpu_memory_kb",
+                a -> a.hasGpuMemoryKb(),
+                a -> a.getGpuMemoryKb()
+        ));
+        sAtomFieldAccessorMap.append(10, new AtomFieldAccessor<>(
+                "has_foreground_services",
+                a -> a.hasHasForegroundServices(),
+                a -> a.getHasForegroundServices()
+        ));
+    }
+
+    ProcessMemorySnapshotConverter() {
+        super();
+    }
+
+    @NonNull
+    @Override
+    SparseArray<AtomFieldAccessor<ProcessMemorySnapshot, ?>> getAtomFieldAccessorMap() {
+        return sAtomFieldAccessorMap;
+    }
+
+    @NonNull
+    @Override
+    ProcessMemorySnapshot getAtomData(@NonNull Atom atom) {
+        Preconditions.checkArgument(
+                atom.hasProcessMemorySnapshot(), "Atom doesn't contain ProcessMemorySnapshot");
+        return atom.getProcessMemorySnapshot();
+    }
+
+    @NonNull
+    @Override
+    String getAtomDataClassName() {
+        return ProcessMemorySnapshot.class.getSimpleName();
+    }
+}
diff --git a/service/src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl b/service/src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl
new file mode 100644
index 0000000..89e7d1d
--- /dev/null
+++ b/service/src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry.scriptexecutorinterface;
+
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+
+parcelable BundleList {
+  List<PersistableBundle> bundles;
+
+  // Used by LargeParcelable for SharedMemory allocation
+  @nullable ParcelFileDescriptor sharedMemoryFd;
+}
\ No newline at end of file
diff --git a/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl b/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl
index 3101634..86bc1b7 100644
--- a/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl
+++ b/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl
@@ -18,6 +18,7 @@
 
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
 
 /**
@@ -59,4 +60,22 @@
                     in ParcelFileDescriptor publishedDataFileDescriptor,
                     in @nullable PersistableBundle savedState,
                     in IScriptExecutorListener listener);
+
+  /**
+   * Executes a specified function in a provided Lua script with given input arguments.
+   * This is a specialized version of invokeScript API above for sending a list of bundles. The
+   * data is delivered use LargeParcelable so it can handle large data sizes automatically.
+   *
+   * @param scriptBody complete body of Lua script that also contains the function to be invoked
+   * @param functionName the name of the function to execute
+   * @param bundleList the list of bundles as input data which the scripts will handle
+   * @param savedState key-value pairs preserved from the previous invocation of the function
+   * @param listener callback for the sandboxed environment to report back script execution results,
+   * errors, and logs
+   */
+  void invokeScriptForBundleList(String scriptBody,
+                    String functionName,
+                    in BundleList bundleList,
+                    in @nullable PersistableBundle savedState,
+                    in IScriptExecutorListener listener);
 }
diff --git a/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java b/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java
index 7e4d44c..d24e06d 100644
--- a/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java
+++ b/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.os.PersistableBundle;
 
+import com.android.car.telemetry.publisher.Constants;
+
 import java.util.Objects;
 
 /**
@@ -27,13 +29,6 @@
  * respective public fields are equal by value.
  */
 public class SessionAnnotation {
-    public static final String ANNOTATION_BUNDLE_KEY_SESSION_ID = "sessionId";
-    public static final String ANNOTATION_BUNDLE_KEY_SESSION_STATE = "sessionState";
-    public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS =
-            "createdAtSinceBootMillis";
-    public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS = "createdAtMillis";
-    public static final String ANNOTATION_BUNDLE_KEY_BOOT_REASON = "bootReason";
-
     public final int sessionId;
     public final int sessionState;
     public final long createdAtSinceBootMillis; // Milliseconds since boot.
@@ -66,15 +61,15 @@
     public String toString() {
         return new StringBuilder()
                 .append("{")
-                .append(ANNOTATION_BUNDLE_KEY_SESSION_ID).append(": ")
+                .append(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID).append(": ")
                 .append(sessionId).append(", ")
-                .append(ANNOTATION_BUNDLE_KEY_SESSION_STATE).append(": ")
+                .append(Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE).append(": ")
                 .append(sessionState).append(", ")
-                .append(ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS).append(": ")
+                .append(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS).append(": ")
                 .append(createdAtSinceBootMillis).append(", ")
-                .append(ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS).append(": ")
+                .append(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS).append(": ")
                 .append(createdAtMillis).append(", ")
-                .append(ANNOTATION_BUNDLE_KEY_BOOT_REASON).append(": ")
+                .append(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON).append(": ")
                 .append(bootReason)
                 .append("}")
                 .toString();
@@ -107,12 +102,12 @@
      * @param bundle A {@link PersistableBundle} that we want to get the annotations to.
      */
     public void addAnnotationsToBundle(@NonNull PersistableBundle bundle) {
-        bundle.putInt(ANNOTATION_BUNDLE_KEY_SESSION_ID, sessionId);
-        bundle.putInt(ANNOTATION_BUNDLE_KEY_SESSION_STATE, sessionState);
-        bundle.putLong(ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS,
+        bundle.putInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID, sessionId);
+        bundle.putInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE, sessionState);
+        bundle.putLong(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS,
                 createdAtSinceBootMillis);
-        bundle.putLong(ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS, createdAtMillis);
-        bundle.putString(ANNOTATION_BUNDLE_KEY_BOOT_REASON, bootReason);
+        bundle.putLong(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS, createdAtMillis);
+        bundle.putString(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON, bootReason);
     }
 
 }
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index fc5787a..8f3475f 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -101,6 +101,13 @@
             "com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS";
     static final String ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION =
             "com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION";
+    // TODO(b/244474850): Delete the intent in W release. After TM-QPR2, it is not used anymore by
+    //  the notification helper.
+    /**
+     * @deprecated - Prefer dismissing resource over notifications using the
+     * {@code ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION} intent action.
+     */
+    @Deprecated
     static final String ACTION_RESOURCE_OVERUSE_DISABLE_APP =
             "com.android.car.watchdog.ACTION_RESOURCE_OVERUSE_DISABLE_APP";
 
@@ -225,6 +232,8 @@
                     // to database until after shutdown enter.
                     mWatchdogPerfHandler.writeToDatabase();
                     break;
+                case PowerCycle.POWER_CYCLE_SUSPEND_EXIT:
+                    break;
                 // ON covers resume.
                 case PowerCycle.POWER_CYCLE_RESUME:
                     // There might be outdated & incorrect info. We should reset them before
@@ -587,8 +596,8 @@
     }
 
     private void notifyPowerCycleChange(@PowerCycle int powerCycle) {
-        if (powerCycle == PowerCycle.NUM_POWER_CYLES) {
-            Slogf.e(TAG, "Skipping notifying invalid power cycle (%d)", powerCycle);
+        if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_2)
+                && powerCycle == PowerCycle.POWER_CYCLE_SUSPEND_EXIT) {
             return;
         }
         try {
@@ -649,7 +658,7 @@
         if (powerService != null) {
             int powerState = powerService.getPowerState();
             int powerCycle = carPowerStateToPowerCycle(powerState);
-            if (powerCycle != PowerCycle.NUM_POWER_CYLES) {
+            if (powerCycle >= 0) {
                 notifyPowerCycleChange(powerCycle);
             } else {
                 Slogf.i(TAG, "Skipping notifying %d power state", powerState);
@@ -799,7 +808,7 @@
                 Context.RECEIVER_NOT_EXPORTED);
     }
 
-    private static @PowerCycle int carPowerStateToPowerCycle(int powerState) {
+    private static int carPowerStateToPowerCycle(int powerState) {
         switch (powerState) {
             // SHUTDOWN_PREPARE covers suspend and shutdown.
             case CarPowerManager.STATE_SHUTDOWN_PREPARE:
@@ -808,11 +817,14 @@
             case CarPowerManager.STATE_SUSPEND_ENTER:
             case CarPowerManager.STATE_HIBERNATION_ENTER:
                 return PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER;
+            case CarPowerManager.STATE_SUSPEND_EXIT:
+            case CarPowerManager.STATE_HIBERNATION_EXIT:
+                return PowerCycle.POWER_CYCLE_SUSPEND_EXIT;
             // ON covers resume.
             case CarPowerManager.STATE_ON:
                 return PowerCycle.POWER_CYCLE_RESUME;
         }
-        return PowerCycle.NUM_POWER_CYLES;
+        return -1;
     }
 
     private static String toGarageModeString(@GarageMode int garageMode) {
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index c0874dc9..54dbaee 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -377,6 +377,7 @@
          * TODO(b/183436216): Implement this method.
          */
         synchronized (mLock) {
+            writer.println("Current UX state: " + toUxStateString(mCurrentUxState));
             writer.println("List of disabled packages per user due to resource overuse: "
                     + mDisabledUserPackagesByUserId);
         }
@@ -2634,6 +2635,19 @@
         }
     }
 
+    private static String toUxStateString(@UxStateType int uxState) {
+        switch (uxState) {
+            case UX_STATE_NO_DISTRACTION:
+                return "UX_STATE_NO_DISTRACTION";
+            case UX_STATE_USER_NOTIFICATION:
+                return "UX_STATE_USER_NOTIFICATION";
+            case UX_STATE_NO_INTERACTION:
+                return "UX_STATE_NO_INTERACTION";
+            default:
+                return "UNKNOWN UX STATE";
+        }
+    }
+
     private final class PackageResourceUsage {
         public final String genericPackageName;
         public @UserIdInt final int userId;
diff --git a/tests/BugReportApp/res/values-en-rCA/strings.xml b/tests/BugReportApp/res/values-en-rCA/strings.xml
index d8e579d..02e32cd 100644
--- a/tests/BugReportApp/res/values-en-rCA/strings.xml
+++ b/tests/BugReportApp/res/values-en-rCA/strings.xml
@@ -17,24 +17,24 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="2596316479611335185">"Bug Report"</string>
+    <string name="app_name" msgid="2596316479611335185">"Bug report"</string>
     <string name="bugreport_info_quit" msgid="5590138890181142473">"Close"</string>
-    <string name="bugreport_info_start" msgid="667324824650830832">"Start Bug Report"</string>
+    <string name="bugreport_info_start" msgid="667324824650830832">"Start bug report"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"Status:"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"This bug report will expire soon"</string>
     <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Submit"</string>
     <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Cancel"</string>
     <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Upload"</string>
     <string name="bugreport_dialog_save" msgid="3291363266190644226">"Save"</string>
-    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Show Bug Reports"</string>
+    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Show bug reports"</string>
     <string name="bugreport_dialog_close" msgid="289925437277364266">"Close"</string>
-    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Speak &amp; Describe The Issue"</string>
+    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Speak and describe the issue"</string>
     <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Audio message for bug report at %s"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Recording finished"</string>
     <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Bug report is in progress"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"A bug report has been collected"</string>
-    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Add Audio"</string>
-    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Add Audio &amp; Upload"</string>
+    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Add audio"</string>
+    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Add audio and upload"</string>
     <string name="bugreport_move_button_text" msgid="1245698439228323880">"Move to USB"</string>
     <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Upload"</string>
     <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Upload to GCS"</string>
diff --git a/tests/BugReportApp/res/values-hy/strings.xml b/tests/BugReportApp/res/values-hy/strings.xml
index 41ecfac..e39e460 100644
--- a/tests/BugReportApp/res/values-hy/strings.xml
+++ b/tests/BugReportApp/res/values-hy/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="2596316479611335185">"Հաղորդում վրիպակի մասին"</string>
     <string name="bugreport_info_quit" msgid="5590138890181142473">"Փակել"</string>
-    <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին հաղորդումը"</string>
+    <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին զեկույցը"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"Կարգավիճակը՝"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"Վրիպակի մասին այս հաղորդման ժամկետը շուտով կլրանա"</string>
     <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Ուղարկել"</string>
@@ -31,7 +31,7 @@
     <string name="bugreport_dialog_title" msgid="3315160684205929910">"Բարձրաձայն նկարագրեք սխալը"</string>
     <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Վրիպակների մասին հաշվետվության վերաբերյալ ձայնային հաղորդագրություն, ժամը՝ %s։"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Գրանցումն ավարտվեց"</string>
-    <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
+    <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"Սխալի մասին զեկույցը բեռնվել է"</string>
     <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Ավելացնել աուդիո"</string>
     <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Ավելացնել աուդիո և վերբեռնել"</string>
@@ -39,12 +39,12 @@
     <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Վերբեռնել"</string>
     <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Վերբեռնել GCS"</string>
     <string name="toast_permissions_denied" msgid="7054832711916992770">"Տրամադրեք թույլտվություններ"</string>
-    <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
-    <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին հաղորդումը ստեղծվում է"</string>
+    <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
+    <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին զեկույցը ստեղծվում է"</string>
     <string name="toast_status_failed" msgid="6365384202315043395">"Վրիպակի զեկույցի հետ կապված սխալ առաջացավ"</string>
     <string name="toast_status_screencap_failed" msgid="2187083897594745149">"Չհաջողվեց ստեղծել սքրինշոթ"</string>
     <string name="toast_status_dump_state_failed" msgid="3496460783060512078">"Dumpstate ծառայության սխալ"</string>
-    <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
-    <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին հաղորդումը բեռնվել է"</string>
-    <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին հաղորդման կարգավիճակի ալիք"</string>
+    <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
+    <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին զեկույցը բեռնվել է"</string>
+    <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին զեկույցի կարգավիճակի ալիք"</string>
 </resources>
diff --git a/tests/BugReportApp/res/values-kn/strings.xml b/tests/BugReportApp/res/values-kn/strings.xml
index 0b5dd81..77e563c 100644
--- a/tests/BugReportApp/res/values-kn/strings.xml
+++ b/tests/BugReportApp/res/values-kn/strings.xml
@@ -29,7 +29,7 @@
     <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ಬಗ್ ವರದಿಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="bugreport_dialog_close" msgid="289925437277364266">"ಮುಚ್ಚಿರಿ"</string>
     <string name="bugreport_dialog_title" msgid="3315160684205929910">"ಸಮಸ್ಯೆಯ ಕುರಿತು ಮಾತನಾಡಿ ಮತ್ತು ವಿವರಿಸಿ"</string>
-    <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೋ ಸಂದೇಶ"</string>
+    <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೊ ಸಂದೇಶ"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"ರೆಕಾರ್ಡಿಂಗ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"ಬಗ್ ವರದಿಮಾಡುವಿಕೆ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿದೆ"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"ಬಗ್ ವರದಿಯನ್ನು ಸಂಗ್ರಹಿಸಲಾಗಿದೆ"</string>
diff --git a/tests/BugReportApp/res/values-or/strings.xml b/tests/BugReportApp/res/values-or/strings.xml
index d4a7771..79ce668 100644
--- a/tests/BugReportApp/res/values-or/strings.xml
+++ b/tests/BugReportApp/res/values-or/strings.xml
@@ -23,7 +23,7 @@
     <string name="bugreport_info_status" msgid="7211044508792815451">"ସ୍ଥିତି:"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"ଏହି ବଗ୍ ରିପୋର୍ଟର ମିଆଦ ଶୀଘ୍ର ସମାପ୍ତ ହେବ"</string>
     <string name="bugreport_dialog_submit" msgid="2789636252713280633">"ଦାଖଲ କରନ୍ତୁ"</string>
-    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ କରନ୍ତୁ"</string>
+    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ୍ କରନ୍ତୁ"</string>
     <string name="bugreport_dialog_upload" msgid="2517386929450370781">"ଅପ୍‌ଲୋଡ୍"</string>
     <string name="bugreport_dialog_save" msgid="3291363266190644226">"ସେଭ୍ କରନ୍ତୁ"</string>
     <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ବଗ୍ ରିପୋର୍ଟ୍‍ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
diff --git a/tests/BugReportApp/res/values-ro/strings.xml b/tests/BugReportApp/res/values-ro/strings.xml
index 01790c9..490a056 100644
--- a/tests/BugReportApp/res/values-ro/strings.xml
+++ b/tests/BugReportApp/res/values-ro/strings.xml
@@ -18,27 +18,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="2596316479611335185">"Raport de eroare"</string>
-    <string name="bugreport_info_quit" msgid="5590138890181142473">"Închide"</string>
-    <string name="bugreport_info_start" msgid="667324824650830832">"Începe raportul de eroare"</string>
+    <string name="bugreport_info_quit" msgid="5590138890181142473">"Închideți"</string>
+    <string name="bugreport_info_start" msgid="667324824650830832">"Începeți raportul de eroare"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"Stare:"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"Acest raport de eroare va expira în curând"</string>
-    <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Trimite"</string>
-    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Anulează"</string>
-    <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Încarcă"</string>
-    <string name="bugreport_dialog_save" msgid="3291363266190644226">"Salvează"</string>
-    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Afișează rapoartele de eroare"</string>
-    <string name="bugreport_dialog_close" msgid="289925437277364266">"Închide"</string>
-    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Vorbește și descrie problema"</string>
+    <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Trimiteți"</string>
+    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Anulați"</string>
+    <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Încărcați"</string>
+    <string name="bugreport_dialog_save" msgid="3291363266190644226">"Salvați"</string>
+    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Afișați rapoartele de eroare"</string>
+    <string name="bugreport_dialog_close" msgid="289925437277364266">"Închideți"</string>
+    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Vorbiți și descrieți problema"</string>
     <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Mesaj audio pentru raportul de eroare la %s"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Înregistrarea s-a încheiat"</string>
     <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Raportul de eroare este în curs"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"S-a colectat un raport de eroare"</string>
-    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Adaugă conținut audio"</string>
-    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Adaugă conținut audio și încarcă"</string>
-    <string name="bugreport_move_button_text" msgid="1245698439228323880">"Mută pe USB"</string>
-    <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Încarcă"</string>
-    <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Încarcă în GCS"</string>
-    <string name="toast_permissions_denied" msgid="7054832711916992770">"Acordă permisiuni"</string>
+    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Adăugați conținut audio"</string>
+    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Adăugați conținut audio și încărcați"</string>
+    <string name="bugreport_move_button_text" msgid="1245698439228323880">"Mutați pe USB"</string>
+    <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Încărcați"</string>
+    <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Încărcați în GCS"</string>
+    <string name="toast_permissions_denied" msgid="7054832711916992770">"Acordați permisiuni"</string>
     <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Raportul de eroare este în curs"</string>
     <string name="toast_bug_report_started" msgid="891404618481185195">"Raportul de eroare a fost inițiat"</string>
     <string name="toast_status_failed" msgid="6365384202315043395">"Raportul de eroare nu s-a realizat"</string>
diff --git a/tests/CarEvsCameraPreviewApp/Android.bp b/tests/CarEvsCameraPreviewApp/Android.bp
index fea6aaf..a570123 100644
--- a/tests/CarEvsCameraPreviewApp/Android.bp
+++ b/tests/CarEvsCameraPreviewApp/Android.bp
@@ -43,11 +43,14 @@
     },
 
     libs: [
+        "android.car",
         "android.car-system-stubs",
-        "androidx.annotation_annotation",
     ],
 
-    static_libs: ["androidx.annotation_annotation"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "car-evs-helper-lib",
+    ],
 
     // To make this app be able to re-installed
     use_embedded_native_libs: true,
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraGLSurfaceView.java b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraGLSurfaceView.java
deleted file mode 100644
index 0383b74..0000000
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraGLSurfaceView.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.car.evs;
-
-import android.content.Context;
-import android.opengl.GLSurfaceView;
-import android.view.MotionEvent;
-
-/**
- * GPU-backed SurfaceView to render a hardware buffer described by CarEvsBufferDescriptor.
- */
-public final class CarEvsCameraGLSurfaceView extends GLSurfaceView {
-    private static final String TAG = CarEvsCameraGLSurfaceView.class.getSimpleName();
-
-    private final GLES20CarEvsCameraPreviewRenderer mRenderer;
-
-    public CarEvsCameraGLSurfaceView(Context context, CarEvsCameraPreviewActivity activity) {
-        super(context);
-        setEGLContextClientVersion(2);
-
-        mRenderer = new GLES20CarEvsCameraPreviewRenderer(context, activity);
-        setRenderer(mRenderer);
-
-        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent e) {
-        float x = e.getX();
-        float y = e.getY();
-
-        // Update a location of a text to tell the rearview is not available.
-        mRenderer.setTextLocation(x, y);
-
-        return true;
-    }
-
-    public void clearBuffer() {
-        mRenderer.clearBuffer();
-    }
-}
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
index f5c9337..4bdcf03 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
+++ b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
@@ -44,12 +44,26 @@
 
 import androidx.annotation.GuardedBy;
 
+import com.android.car.internal.evs.CarEvsGLSurfaceView;
+import com.android.car.internal.evs.GLES20CarEvsBufferRenderer;
+
 import java.util.ArrayList;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-public class CarEvsCameraPreviewActivity extends Activity {
+public class CarEvsCameraPreviewActivity extends Activity
+        implements CarEvsGLSurfaceView.BufferCallback {
+
     private static final String TAG = CarEvsCameraPreviewActivity.class.getSimpleName();
+    /**
+     * ActivityManagerService encodes the reason for a request to close system dialogs with this
+     * key.
+     */
+    private final static String EXTRA_DIALOG_CLOSE_REASON = "reason";
+    /** This string literal is from com.android.systemui.car.systembar.CarSystemBarButton class. */
+    private final static String DIALOG_CLOSE_REASON_CAR_SYSTEMBAR_BUTTON = "carsystembarbutton";
+    /** This string literal is from com.android.server.policy.PhoneWindowManager class. */
+    private final static String DIALOG_CLOSE_REASON_HOME_KEY = "homekey";
 
     /**
      * Defines internal states.
@@ -88,7 +102,7 @@
     private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1);
 
     /** GL backed surface view to render the camera preview */
-    private CarEvsCameraGLSurfaceView mEvsView;
+    private CarEvsGLSurfaceView mEvsView;
     private ViewGroup mRootView;
     private LinearLayout mPreviewContainer;
 
@@ -133,7 +147,7 @@
                 if (mStreamState == STREAM_STATE_INVISIBLE) {
                     // When the activity becomes invisible (e.g. goes background), we immediately
                     // returns received frame buffers instead of stopping a video stream.
-                    returnBufferLocked(buffer);
+                    doneWithBufferLocked(buffer);
                 } else {
                     // Enqueues a new frame and posts a rendering job
                     mBufferQueue.add(buffer);
@@ -199,6 +213,17 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                Bundle extras = intent.getExtras();
+                if (extras != null) {
+                    String reason = extras.getString(EXTRA_DIALOG_CLOSE_REASON);
+                    if (!DIALOG_CLOSE_REASON_CAR_SYSTEMBAR_BUTTON.equals(reason) &&
+                        !DIALOG_CLOSE_REASON_HOME_KEY.equals(reason)) {
+                        Log.i(TAG, "Ignore a request to close the system dialog with a reason = " +
+                                   reason);
+                        return;
+                    }
+                    Log.d(TAG, "Requested to close the dialog, reason = " + reason);
+                }
                 finish();
             } else {
                 Log.e(TAG, "Unexpected intent " + intent);
@@ -213,7 +238,7 @@
         // Need to register the receiver for all users, because we want to receive the Intent after
         // the user is changed.
         registerReceiverForAllUsers(mBroadcastReceiver, filter, /* broadcastPermission= */ null,
-                /* scheduler= */ null, Context.RECEIVER_NOT_EXPORTED);
+                /* scheduler= */ null, Context.RECEIVER_EXPORTED);
     }
 
     @Override
@@ -235,7 +260,8 @@
         Car.createCar(getApplicationContext(), /* handler = */ null,
                 Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mCarServiceLifecycleListener);
 
-        mEvsView = new CarEvsCameraGLSurfaceView(getApplication(), this);
+        mEvsView = CarEvsGLSurfaceView.create(getApplication(), this, getApplicationContext()
+                .getResources().getInteger(R.integer.config_evsRearviewCameraInPlaneRotationAngle));
         mRootView = (ViewGroup) LayoutInflater.from(this).inflate(
                 R.layout.evs_preview_activity, /* root= */ null);
         mPreviewContainer = mRootView.findViewById(R.id.evs_preview_container);
@@ -419,8 +445,8 @@
         return state;
     }
 
-    /** Get a new frame */
-    CarEvsBufferDescriptor getNewFrame() {
+    @Override
+    public CarEvsBufferDescriptor onBufferRequested() {
         synchronized (mLock) {
             if (mBufferQueue.isEmpty()) {
                 return null;
@@ -435,15 +461,15 @@
         }
     }
 
-    /** Request to return a buffer we're done with */
-    void returnBuffer(CarEvsBufferDescriptor buffer) {
+    @Override
+    public void onBufferProcessed(CarEvsBufferDescriptor buffer) {
         synchronized (mLock) {
-            returnBufferLocked(buffer);
+            doneWithBufferLocked(buffer);
         }
     }
 
     @GuardedBy("mLock")
-    private void returnBufferLocked(CarEvsBufferDescriptor buffer) {
+    private void doneWithBufferLocked(CarEvsBufferDescriptor buffer) {
         try {
             mEvsManager.returnFrameBuffer(buffer);
         } catch (Exception e) {
diff --git a/tests/CarTelemetryApp/Android.bp b/tests/CarTelemetryApp/Android.bp
index b75a8c7..eebb6a8 100644
--- a/tests/CarTelemetryApp/Android.bp
+++ b/tests/CarTelemetryApp/Android.bp
@@ -22,8 +22,15 @@
 
     srcs: [
         "src/**/*.java",
+        "src/**/*.aidl",
         ":cartelemetryservice-proto-srcs"
     ],
+    aidl: {
+        local_include_dirs: ["src"],
+        include_dirs: [
+            "frameworks/native/aidl/binder",
+        ],
+    },
     platform_apis: true,
     aaptflags: ["--auto-add-overlay"],
     privileged: true,
diff --git a/tests/CarTelemetryApp/AndroidManifest.xml b/tests/CarTelemetryApp/AndroidManifest.xml
index d827fa3..8006ad8 100644
--- a/tests/CarTelemetryApp/AndroidManifest.xml
+++ b/tests/CarTelemetryApp/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.car.cartelemetryapp">
     <uses-permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
 
     <application
         android:icon="@drawable/ic_launcher"
@@ -37,6 +38,7 @@
         </activity>
         <service
             android:name=".CarMetricsCollectorService"
-            android:exported="true"/>
+            android:exported="true"
+            android:singleUser="true" />
     </application>
 </manifest>
diff --git a/tests/CarTelemetryApp/res/layout/list_item.xml b/tests/CarTelemetryApp/res/layout/list_item.xml
index f975b3c..40a67f2 100644
--- a/tests/CarTelemetryApp/res/layout/list_item.xml
+++ b/tests/CarTelemetryApp/res/layout/list_item.xml
@@ -21,11 +21,30 @@
     android:layout_height="wrap_content"
     android:orientation="vertical">
   <Button
+      android:id="@+id/add_config_button"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/add_button"
+      app:layout_constraintHorizontal_bias="0"
+      app:layout_constraintStart_toStartOf="parent"
+      app:layout_constraintTop_toTopOf="@+id/barrier2" />
+  <Button
+      android:id="@+id/remove_config_button"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/remove_button"
+      app:layout_constraintHorizontal_bias="0"
+      app:layout_constraintEnd_toStartOf="@+id/guideline"
+      app:layout_constraintStart_toEndOf="@+id/add_config_button"
+      app:layout_constraintTop_toTopOf="@+id/barrier2" />
+  <Button
       android:id="@+id/show_info_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/history_button"
-      app:layout_constraintStart_toStartOf="parent"
+      app:layout_constraintHorizontal_bias="1"
+      app:layout_constraintStart_toEndOf="@+id/guideline"
+      app:layout_constraintEnd_toStartOf="@+id/clear_info_button"
       app:layout_constraintTop_toTopOf="@+id/barrier2" />
   <Button
       android:id="@+id/clear_info_button"
@@ -33,11 +52,13 @@
       android:layout_height="wrap_content"
       android:text="@string/clear_button"
       app:layout_constraintEnd_toEndOf="parent"
+      app:layout_constraintHorizontal_bias="1"
       app:layout_constraintTop_toTopOf="@+id/barrier2" />
   <CheckBox
       android:id="@+id/checkbox"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
+      android:enabled="false"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />
   <TextView
@@ -102,6 +123,8 @@
       android:background="@android:color/darker_gray"
       app:layout_constraintBottom_toBottomOf="@+id/errors_text"
       app:layout_constraintEnd_toStartOf="@+id/errors_text"
+      app:layout_constraintHorizontal_bias="1"
+      app:layout_constraintStart_toEndOf="@+id/sent_bytes_text"
       app:layout_constraintTop_toTopOf="@+id/barrier1" />
   <androidx.constraintlayout.widget.Barrier
       android:id="@+id/barrier1"
@@ -120,4 +143,10 @@
           "results_text,on_ready_times_text,divider,sent_bytes_text,error_count_text"
       tools:layout_editor_absoluteX="135dp"
       tools:layout_editor_absoluteY="85dp" />
+  <androidx.constraintlayout.widget.Guideline
+      android:id="@+id/guideline"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:orientation="vertical"
+      app:layout_constraintGuide_percent="0.5" />
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/tests/CarTelemetryApp/res/raw/conn_sessions.lua b/tests/CarTelemetryApp/res/raw/conn_sessions.lua
index 1cdf685..ad84a66 100644
--- a/tests/CarTelemetryApp/res/raw/conn_sessions.lua
+++ b/tests/CarTelemetryApp/res/raw/conn_sessions.lua
@@ -22,7 +22,7 @@
     if published_data['packages'] == nil then
         -- on_metrics_report(r) sends r as finished result table
         -- on_metrics_report(r, s) sends r as finished result table while also sending
-        -- s as intermediate result that will be sent received time as 'state' param
+        -- s as intermediate result that will be received next time as 'state' param
         log("packages is nil, only sessions data available.")
         on_metrics_report(res)
         do return end
diff --git a/tests/CarTelemetryApp/res/values/strings.xml b/tests/CarTelemetryApp/res/values/strings.xml
index 8f7258b..b213496 100644
--- a/tests/CarTelemetryApp/res/values/strings.xml
+++ b/tests/CarTelemetryApp/res/values/strings.xml
@@ -23,6 +23,8 @@
     <string name="log_hint" translatable="false">Logs displayed here.</string>
     <string name="clear_button" translatable="false">CLEAR</string>
     <string name="history_button" translatable="false">HISTORY</string>
+    <string name="add_button" translatable="false">ADD</string>
+    <string name="remove_button" translatable="false">REMOVE</string>
     <string name="results" translatable="false">Results:</string>
     <string name="errors" translatable="false">Errors:</string>
     <string name="showing_history" translatable="false">Showing History For:</string>
diff --git a/tests/CarTelemetryApp/res/xml/configs.xml b/tests/CarTelemetryApp/res/xml/configs.xml
index 00396dc..c4c10cd 100644
--- a/tests/CarTelemetryApp/res/xml/configs.xml
+++ b/tests/CarTelemetryApp/res/xml/configs.xml
@@ -53,22 +53,6 @@
     </subscribers>
   </config>
   <config
-      name="ethernet_with_session_metrics_config"
-      version="1"
-      script_name="conn_sessions">
-    <subscribers>
-      <subscriber
-          handler="onConnectivityDataWithSession"
-          priority="1">
-        <publisher
-            type="connectivity">
-          <transport>TRANSPORT_ETHERNET</transport>
-          <oem_type>OEM_NONE</oem_type>
-        </publisher>
-      </subscriber>
-    </subscribers>
-  </config>
-  <config
       name="cellular_with_session_metrics_config"
       version="1"
       script_name="conn_sessions">
@@ -84,4 +68,20 @@
       </subscriber>
     </subscribers>
   </config>
+  <config
+      name="ethernet_with_session_metrics_config"
+      version="1"
+      script_name="conn_sessions">
+    <subscribers>
+      <subscriber
+          handler="onConnectivityDataWithSession"
+          priority="1">
+        <publisher
+            type="connectivity">
+          <transport>TRANSPORT_ETHERNET</transport>
+          <oem_type>OEM_NONE</oem_type>
+        </publisher>
+      </subscriber>
+    </subscribers>
+  </config>
 </configs>
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
index e5c3087..53a300b 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
@@ -15,19 +15,27 @@
  */
 package com.android.car.cartelemetryapp;
 
-import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Service;
 import android.car.Car;
 import android.car.telemetry.CarTelemetryManager;
 import android.car.telemetry.CarTelemetryManager.AddMetricsConfigCallback;
 import android.car.telemetry.TelemetryProto.MetricsConfig;
+import android.car.telemetry.TelemetryProto.TelemetryError;
 import android.content.Intent;
-import android.os.Binder;
 import android.os.IBinder;
-import android.util.Log;
+import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
 
-import java.util.HashSet;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Executor;
@@ -37,15 +45,21 @@
  * Service to interface with CarTelemetryManager.
  */
 public class CarMetricsCollectorService extends Service {
-    private static final String TAG = CarMetricsCollectorService.class.getSimpleName();
     private static final String ASSETS_METRICS_CONFIG_FOLDER = "metricsconfigs";
+    private static final int HISTORY_SIZE = 10;
     private final Executor mExecutor = Executors.newSingleThreadExecutor();
-    private final IBinder mBinder = new ServiceBinder();
+    private final ReportListener mReportListener = new ReportListener();
+    private final ReportCallback mReportCallback = new ReportCallback();
     private Car mCar;
     private CarTelemetryManager mCarTelemetryManager;
-    private Set<String> mActiveConfigs = new HashSet<>();
     private ConfigParser mConfigParser;
     private Map<String, MetricsConfig> mConfigs;
+    private Map<String, IConfigData> mConfigData = new HashMap<>();
+    private Map<String, Deque<PersistableBundle>> mBundleHistory = new HashMap<>();
+    private Map<String, Deque<String>> mErrorHistory = new HashMap<>();
+    private IConfigStateListener mConfigStateListener;
+    private IResultListener mResultListener;
+    private AddMetricsConfigCallback mAddConfigCallback = new AddConfigCallback();
     private Car.CarServiceLifecycleListener mCarLifecycleListener = (car, ready) -> {
         if (ready) {
             mCarTelemetryManager =
@@ -53,6 +67,60 @@
         }
     };
 
+    private final ICarMetricsCollectorService.Stub mBinder =
+            new ICarMetricsCollectorService.Stub() {
+                @Override
+                public List<IConfigData> getConfigData() {
+                    return new ArrayList<>(mConfigData.values());
+                }
+
+                @Override
+                public void addConfig(String configName) {
+                    addMetricsConfig(configName);
+                }
+
+                @Override
+                public void removeConfig(String configName) {
+                    removeMetricsConfig(configName);
+                }
+
+                @Override
+                public void setConfigStateListener(IConfigStateListener listener) {
+                    mConfigStateListener = listener;
+                }
+
+                @Override
+                public void setResultListener(IResultListener listener) {
+                    mResultListener = listener;
+                    mCarTelemetryManager.setReportReadyListener(getMainExecutor(), mReportListener);
+                }
+
+                @Override
+                public List<PersistableBundle> getBundleHistory(String configName) {
+                    return new ArrayList(mBundleHistory.get(configName));
+                }
+
+                @Override
+                public List<String> getErrorHistory(String configName) {
+                    return new ArrayList(mErrorHistory.get(configName));
+                }
+
+                @Override
+                public void clearHistory(String configName) {
+                    mBundleHistory.get(configName).clear();
+                    mErrorHistory.get(configName).clear();
+                    IConfigData configData = mConfigData.get(configName);
+                    configData.onReadyTimes = 0;
+                    configData.sentBytes = 0;
+                    configData.errorCount = 0;
+                }
+
+                @Override
+                public String getLog() {
+                    return dumpLogs();
+                }
+            };
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -63,6 +131,7 @@
                 mCarLifecycleListener);
         mConfigParser = new ConfigParser(this.getApplicationContext());
         mConfigs = mConfigParser.getConfigs();
+        updateConfigData();
         addActiveConfigs();
     }
 
@@ -76,116 +145,158 @@
         return mBinder;
     }
 
-    public class ServiceBinder extends Binder {
-        CarMetricsCollectorService getService() {
-            return CarMetricsCollectorService.this;
-        }
-    }
-
     public String dumpLogs() {
         return mConfigParser.dumpLogs();
     }
 
-    /**
-     * Get all the config names that are in the assets folder.
-     *
-     * They are not necessarily active.
-     */
-    public String[] getAllConfigNames() {
-        return mConfigs.keySet().toArray(new String[0]);
-    }
-
-    /**
-     * Gets the finished report.
-     *
-     * @param configName the name of the {@link MetricsConfig} to get the report for.
-     * @param executor {@link Executor} to execute the callback in.
-     * @param callback function to be called with the finished report.
-     */
-    public void getFinishedReport(
-            @NonNull String configName,
-            @CallbackExecutor @NonNull Executor executor,
-            @NonNull CarTelemetryManager.MetricsReportCallback callback) {
-        mCarTelemetryManager.getFinishedReport(configName, executor, callback);
-    }
-
-    /**
-     * Sets listener for getting notified when a report is ready.
-     *
-     * @param executor {@link Executor} to execute the listener on.
-     * @param listener the callback to call when report is ready.
-     */
-    public void setReportReadyListener(
-            @CallbackExecutor @NonNull Executor executor,
-            @NonNull CarTelemetryManager.ReportReadyListener listener) {
-        mCarTelemetryManager.setReportReadyListener(executor, listener);
-    }
-
-    /**
-     * Adds {@link MetricsConfig} of a specific name.
-     *
-     * @param configName name of the {@link MetricsConfig} to add.
-     * @param executor {@link Executor} to execute the add operation on.
-     * @param callback the callback to call with the status of the add operation.
-     */
-    public void addMetricsConfig(
-            @NonNull String configName,
-            @CallbackExecutor @NonNull Executor executor,
-            @NonNull AddMetricsConfigCallback callback) {
+    private void addMetricsConfig(String configName) {
         if (!mConfigs.containsKey(configName)) {
             throw new IllegalArgumentException(
                     "Failed to add metrics config, name does not exist! " + configName);
         }
         mCarTelemetryManager.addMetricsConfig(
-                    configName, mConfigs.get(configName).toByteArray(), mExecutor, callback);
+                configName, mConfigs.get(configName).toByteArray(), mExecutor, mAddConfigCallback);
     }
 
-    /**
-     * Removes the named metrics config.
-     */
-    public void removeMetricsConfig(@NonNull String configName) {
+    private void removeMetricsConfig(String configName) {
         mCarTelemetryManager.removeMetricsConfig(configName);
-    }
-
-    /**
-     * Gets the active configs.
-     *
-     * @return activated configs.
-     */
-    public Set<String> getActiveConfigs() {
-        return mActiveConfigs;
-    }
-
-    private void onAddMetricsConfigStatus(String metricsConfigName, int statusCode) {
-        Log.i(TAG, "addMetricsConfig for " + metricsConfigName + " returned status code = "
-                + addConfigStatusToString(statusCode));
-        if (statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED
-                || statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS) {
-            mActiveConfigs.add(metricsConfigName);
-        }
+        mConfigData.get(configName).selected = false;
     }
 
     private void addActiveConfigs() {
-        // TODO(b/230664179): specific logic for what configs should be added
         for (String configName : mConfigs.keySet()) {
-            addMetricsConfig(configName, mExecutor, this::onAddMetricsConfigStatus);
+            if (mConfigData.get(configName).selected) {
+                addMetricsConfig(configName);
+            }
         }
     }
 
-    private String addConfigStatusToString(int statusCode) {
-        switch (statusCode) {
-            case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED:
-                return "SUCCESS";
-            case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS:
-                return "ERROR ALREADY_EXISTS";
-            case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD:
-                return "ERROR VERSION_TOO_OLD";
-            case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_PARSE_FAILED:
-                return "ERROR PARSE_FAILED";
-            case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SIGNATURE_VERIFICATION_FAILED:
-                return "ERROR SIGNATURE_VERIFICATION_FAILED";
-            default:
-                return "ERROR UNKNOWN";
+    /** Updates the config data mapping from the config list.
+     * If config list has newer version config, that config is either added or updated in the
+     * config data mapping and set selected.
+     */
+    private void updateConfigData() {
+        // Add new or updated config data
+        for (MetricsConfig config : mConfigs.values()) {
+            if (!mConfigData.containsKey(config.getName())
+                    || mConfigData.get(config.getName()).version < config.getVersion()) {
+                IConfigData configData = new IConfigData();
+                configData.name = config.getName();
+                configData.version = config.getVersion();
+                configData.selected = true;
+                mConfigData.put(config.getName(), configData);
+                mBundleHistory.put(config.getName(), new ArrayDeque<>());
+                mErrorHistory.put(config.getName(), new ArrayDeque<>());
+            }
+        }
+        // Remove config data for configs not in mConfigs
+        Set<String> keys = mConfigData.keySet();
+        for (String name : keys) {
+            if (!mConfigs.containsKey(name)) {
+                mConfigData.remove(name);
+                mBundleHistory.remove(name);
+                mErrorHistory.remove(name);
+            }
+        }
+    }
+
+    private String errorToString(TelemetryError error) {
+        StringBuilder sb = new StringBuilder()
+                .append(":\n")
+                .append("    Error type: ")
+                .append(error.getErrorType().name())
+                .append("\n")
+                .append("    Message: ")
+                .append(error.getMessage());
+        return sb.toString();
+    }
+
+    private int getPersistableBundleByteSize(@Nullable PersistableBundle bundle) {
+        if (bundle == null) {
+            return 0;
+        }
+        Parcel parcel = Parcel.obtain();
+        parcel.writePersistableBundle(bundle);
+        int size = parcel.dataSize();
+        parcel.recycle();
+        return size;
+    }
+
+    private class ReportListener implements CarTelemetryManager.ReportReadyListener {
+        @Override
+        public void onReady(@NonNull String metricsConfigName) {
+            mCarTelemetryManager.getFinishedReport(
+                    metricsConfigName, getMainExecutor(), mReportCallback);
+        }
+    }
+
+    private class ReportCallback implements CarTelemetryManager.MetricsReportCallback {
+        @Override
+        public void onResult(
+                @NonNull String metricsConfigName,
+                @Nullable PersistableBundle report,
+                @Nullable byte[] telemetryError,
+                int status) {
+            IConfigData configData = mConfigData.get(metricsConfigName);
+            String errorString = null;
+            if (report != null) {
+                if (!mBundleHistory.containsKey(metricsConfigName)) {
+                    mBundleHistory.put(metricsConfigName, new ArrayDeque<>());
+                }
+                Deque<PersistableBundle> reportHistory = mBundleHistory.get(metricsConfigName);
+                if (reportHistory.size() >= HISTORY_SIZE) {
+                    // Remove oldest element
+                    reportHistory.pollFirst();
+                }
+                reportHistory.addLast(report);
+                configData.sentBytes += getPersistableBundleByteSize(report);
+                configData.onReadyTimes += 1;
+            }
+            if (telemetryError != null) {
+                if (!mErrorHistory.containsKey(metricsConfigName)) {
+                    mErrorHistory.put(metricsConfigName, new ArrayDeque<>());
+                }
+                Deque<String> errorHistory = mErrorHistory.get(metricsConfigName);
+                if (errorHistory.size() >= HISTORY_SIZE) {
+                    // Remove oldest element
+                    errorHistory.pollFirst();
+                }
+                TelemetryError error;
+                try {
+                    error = TelemetryError.parseFrom(telemetryError);
+                } catch (InvalidProtocolBufferException e) {
+                    throw new IllegalStateException(
+                            "Failed to get error from bytes, invalid proto buffer.", e);
+                }
+                errorString = errorToString(error);
+                errorHistory.addLast(errorString);
+                configData.errorCount += 1;
+            }
+            try {
+                mResultListener.onResult(metricsConfigName, configData, report, errorString);
+            } catch (RemoteException e) {
+                throw new IllegalStateException(
+                        "Failed to call IResultListener.onResult.", e);
+            }
+        }
+    }
+
+    private class AddConfigCallback implements AddMetricsConfigCallback {
+        @Override
+        public void onAddMetricsConfigStatus(
+                @NonNull String metricsConfigName, int statusCode) {
+            if (statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED
+                    || statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS) {
+                mConfigData.get(metricsConfigName).selected = true;
+                if (mConfigStateListener != null) {
+                    try {
+                        mConfigStateListener.onConfigAdded(metricsConfigName);
+                    } catch (RemoteException e) {
+                        throw new IllegalStateException(
+                            "Failed to call IConfigStateListener.onConfigAdded.", e);
+                    }
+                }
+            }
         }
     }
 }
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java
index a388924..b23961a 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java
@@ -16,25 +16,15 @@
 
 package com.android.car.cartelemetryapp;
 
-import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS;
-import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.Activity;
-import android.car.telemetry.CarTelemetryManager.AddMetricsConfigCallback;
-import android.car.telemetry.CarTelemetryManager.MetricsReportCallback;
-import android.car.telemetry.CarTelemetryManager.ReportReadyListener;
-import android.car.telemetry.TelemetryProto.TelemetryError;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.Parcel;
 import android.os.PersistableBundle;
-import android.util.Log;
+import android.os.RemoteException;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -48,15 +38,6 @@
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.google.protobuf.InvalidProtocolBufferException;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InvalidClassException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
@@ -66,17 +47,10 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executor;
 
 public class CarTelemetryActivity extends Activity {
-    private static final String TAG = CarTelemetryActivity.class.getSimpleName();
     private static final int LOG_SIZE = 100;
-    private static final String APP_DATA_FILENAME = "appdata";
-    private CarMetricsCollectorService mService;
-    private ReportCallback mReportCallback = new ReportCallback();
-    private ReportListener mReportListener = new ReportListener();
-    private String[] mConfigNames;
+    private ICarMetricsCollectorService mService;
     private TextView mConfigNameView;
     private TextView mHistoryView;
     private TextView mLogView;
@@ -85,17 +59,17 @@
     private Button mPopupCloseButton;
     private Button mConfigButton;
     private ConfigListAdaptor mAdapter;
-    private List<ConfigData> mConfigList = new ArrayList<>();
+    private List<IConfigData> mConfigData = new ArrayList<>();
     private Map<String, Integer> mConfigNameIndex = new HashMap<>();
     private Deque<String> mLogs = new ArrayDeque<>();
+    private Map<String, List<PersistableBundle>> mBundleHistory = new HashMap<>();
+    private Map<String, List<String>> mErrorHistory = new HashMap<>();
     private boolean mDataRadioSelected = true;
-    private ConfigData mSelectedInfoConfig = new ConfigData("");
+    private IConfigData mSelectedInfoConfig = new IConfigData();
     private ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
-            CarMetricsCollectorService.ServiceBinder binder =
-                    (CarMetricsCollectorService.ServiceBinder) service;
-            mService = binder.getService();
+            mService = ICarMetricsCollectorService.Stub.asInterface(service);
             onServiceBound();
         }
 
@@ -115,19 +89,19 @@
         RadioButton dataRadio = findViewById(R.id.data_radio);
         dataRadio.setOnClickListener(v -> {
             mDataRadioSelected = true;
-            mHistoryView.setText(mSelectedInfoConfig.getBundleHistoryString());
+            mHistoryView.setText(getBundleHistoryString(mSelectedInfoConfig.name));
         });
 
         RadioButton errorRadio = findViewById(R.id.error_radio);
         errorRadio.setOnClickListener(v -> {
             mDataRadioSelected = false;
-            mHistoryView.setText(mSelectedInfoConfig.getErrorHistoryString());
+            mHistoryView.setText(getErrorHistoryString(mSelectedInfoConfig.name));
         });
 
         ViewGroup parent = findViewById(R.id.mainLayout);
         View configsView = this.getLayoutInflater().inflate(R.layout.config_popup, parent, false);
         mConfigPopup = new PopupWindow(
-                configsView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+                configsView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
         mConfigButton = findViewById(R.id.config_button);
         mConfigButton.setOnClickListener(v -> {
             mConfigPopup.showAtLocation(configsView, Gravity.CENTER, 0, 0);
@@ -155,221 +129,232 @@
     }
 
     private void onServiceBound() {
-        mConfigNames = mService.getAllConfigNames();
-        addToLog(mService.dumpLogs());
-        Set<String> mActiveConfigs = mService.getActiveConfigs();
-        for (int i = 0; i < mConfigNames.length; i++) {
-            mConfigNameIndex.put(mConfigNames[i], i);
+        try {
+            printLog(mService.getLog());
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to call ICarMetricsCollectorService.getLog.", e);
         }
-        Map<String, ConfigData> pastConfigMap = readAppData();
-        for (String name : mConfigNames) {
-            ConfigData config;
-            if (pastConfigMap != null && pastConfigMap.containsKey(name)) {
-                // Preserve previous state for old config
-                config = pastConfigMap.get(name);
-            } else {
-                // New config
-                config = new ConfigData(name);
+        IConfigStateListener configStateListener = new IConfigStateListener.Stub() {
+            @Override
+            public void onConfigAdded(String configName) {
+                // Set config to checked
+                mConfigData.get(mConfigNameIndex.get(configName)).selected = true;
+                getMainExecutor().execute(() -> {
+                    mAdapter.notifyItemChanged(mConfigNameIndex.get(configName));
+                });
+                printLog("Added config " + configName);
             }
-            config.selected = mActiveConfigs.contains(name);
-            mConfigList.add(config);
+        };
+        try {
+            mService.setConfigStateListener(configStateListener);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to call ICarMetricsCollectorService.setConfigStateListener.", e);
         }
-        if (mConfigList.size() != 0) {
-            mSelectedInfoConfig = mConfigList.get(0);  // Default to display first config data
+        IResultListener resultListener = new IResultListener.Stub() {
+            @Override
+            public void onResult(
+                    String metricsConfigName,
+                    IConfigData configData,
+                    PersistableBundle report,
+                    String telemetryError) {
+                lazyInitHistories(metricsConfigName);
+                mConfigData.set(mConfigNameIndex.get(metricsConfigName), configData);
+                // Add to bundle and error histories
+                if (report != null) {
+                    if (!mBundleHistory.containsKey(metricsConfigName)) {
+                        mBundleHistory.put(metricsConfigName, new ArrayList<PersistableBundle>());
+                    }
+                    mBundleHistory.get(metricsConfigName).add(report);
+                    printLog("Received report for " + metricsConfigName);
+                } else {
+                    if (!mErrorHistory.containsKey(metricsConfigName)) {
+                        mErrorHistory.put(metricsConfigName, new ArrayList<String>());
+                    }
+                    mErrorHistory.get(metricsConfigName).add(telemetryError);
+                    printLog("Received error for " + metricsConfigName);
+                }
+                if (metricsConfigName.equals(mSelectedInfoConfig.name)) {
+                    refreshHistory();
+                }
+            }
+        };
+        try {
+            mService.setResultListener(resultListener);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to call ICarMetricsCollectorService.setResultListener.", e);
+        }
+
+        try {
+            mConfigData = mService.getConfigData();
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to call ICarMetricsCollectorService.getConfigData.", e);
+        }
+
+        for (int i = 0; i < mConfigData.size(); i++) {
+            mConfigNameIndex.put(mConfigData.get(i).name, i);
+        }
+        if (mConfigData.size() != 0) {
+            mSelectedInfoConfig = mConfigData.get(0);  // Default to display first config data
             refreshHistory();
         }
 
         mAdapter = new ConfigListAdaptor(
-                mConfigList, new AdaptorCallback());
+                mConfigData, new AdaptorCallback());
         mRecyclerView.setAdapter(mAdapter);
-
-        mService.setReportReadyListener(getMainExecutor(), mReportListener);
     }
 
-    /** Calculates the PersistableBundle byte size. */
-    private int getPersistableBundleByteSize(@Nullable PersistableBundle bundle) {
-        if (bundle == null) {
-            return 0;
+    /** Converts bundle to string. */
+    private String bundleToString(PersistableBundle bundle) {
+        StringBuilder sb = new StringBuilder();
+        for (String key : bundle.keySet()) {
+            sb.append("--")
+                .append(key)
+                .append(": ")
+                .append(bundle.get(key).toString())
+                .append("\n");
         }
-        Parcel parcel = Parcel.obtain();
-        parcel.writePersistableBundle(bundle);
-        int size = parcel.dataSize();
-        parcel.recycle();
-        return size;
+        return sb.toString();
     }
 
-    /** Parses byte array to TelemetryError. */
-    @Nullable
-    private TelemetryError getErrorFromBytes(byte[] bytes) {
-        TelemetryError error = null;
+    /** Converts bundle history to string. */
+    private String getBundleHistoryString(String configName) {
+        StringBuilder sb = new StringBuilder();
+        if (!mBundleHistory.containsKey(configName)) {
+            return "";
+        }
+        for (PersistableBundle bundle : mBundleHistory.get(configName)) {
+            sb.append(bundleToString(bundle)).append("\n");
+        }
+        return sb.toString();
+    }
+
+    /** Converts error history to string. */
+    private String getErrorHistoryString(String configName) {
+        StringBuilder sb = new StringBuilder();
+        if (!mErrorHistory.containsKey(configName)) {
+            return "";
+        }
+        for (String error : mErrorHistory.get(configName)) {
+            sb.append(error).append("\n");
+        }
+        return sb.toString();
+    }
+
+    /** Refreshes the history view with the currently selected config's data. */
+    private void refreshHistory() {
+        getMainExecutor().execute(() -> {
+            mConfigNameView.setText(mSelectedInfoConfig.name);
+            if (mDataRadioSelected) {
+                mHistoryView.setText(getBundleHistoryString(mSelectedInfoConfig.name));
+            } else {
+                mHistoryView.setText(getErrorHistoryString(mSelectedInfoConfig.name));
+            }
+        });
+    }
+
+    /** Clears the config data and histories. Cleared on server side too. */
+    private void clearConfigData(IConfigData configData) {
+        configData.onReadyTimes = 0;
+        configData.sentBytes = 0;
+        configData.errorCount = 0;
+        if (mBundleHistory.containsKey(configData.name)) {
+            mBundleHistory.get(configData.name).clear();
+        }
+        if (mErrorHistory.containsKey(configData.name)) {
+            mErrorHistory.get(configData.name).clear();
+        }
         try {
-            error = TelemetryError.parseFrom(bytes);
-        } catch (InvalidProtocolBufferException e) {
+            mService.clearHistory(configData.name);
+        } catch (RemoteException e) {
             throw new IllegalStateException(
-                    "Failed to get error from bytes, invalid proto buffer.", e);
-        }
-        return error;
-    }
-
-    private void writeAppData() {
-        Map<String, ConfigData> configMap = new HashMap<>();
-        for (ConfigData config : mConfigList) {
-            configMap.put(config.getName(), config);
-        }
-        try (FileOutputStream fos =
-                this.openFileOutput(APP_DATA_FILENAME, Context.MODE_PRIVATE);
-                ObjectOutputStream oos = new ObjectOutputStream(fos)) {
-            oos.writeObject(configMap);
-        } catch (IOException e) {
-            throw new IllegalStateException("Failed to write app data to file.", e);
+                    "Failed to ICarMetricsCollectorService.clearHistory.", e);
         }
     }
 
-    private Map<String, ConfigData> readAppData() {
-        try (FileInputStream fis = this.openFileInput(APP_DATA_FILENAME);
-                ObjectInputStream ois = new ObjectInputStream(fis)) {
-            return (HashMap<String, ConfigData>) ois.readObject();
-        } catch (FileNotFoundException | InvalidClassException e) {
-            // File might not have been created yet or object definition changed
-            Log.w(TAG, "Could not read app data. Does not exist or format changed.", e);
-            return null;
-        } catch (IOException | ClassNotFoundException e) {
-            throw new IllegalStateException("Failed to read app data from file.", e);
+    /** Retrieves histories from service if not already present. */
+    private void lazyInitHistories(String configName) {
+        if (!mBundleHistory.containsKey(configName)) {
+            try {
+                mBundleHistory.put(configName, mService.getBundleHistory(configName));
+            } catch (RemoteException e) {
+                throw new IllegalStateException(
+                        "Failed to call ICarMetricsCollectorService.getBundleHistory.", e);
+            }
+        }
+        if (!mErrorHistory.containsKey(configName)) {
+            try {
+                mErrorHistory.put(configName, mService.getErrorHistory(configName));
+            } catch (RemoteException e) {
+                throw new IllegalStateException(
+                        "Failed to call ICarMetricsCollectorService.getErrorHistory.", e);
+            }
         }
     }
 
-    private void addToLog(String log) {
-        // Add to logs, only a set number is kept
+    /** Prints to log view the log with prefixed timestamp. */
+    private void printLog(String log) {
+        String text = LocalDateTime.now(ZoneId.systemDefault())
+                .format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")) + ": " + log;
         if (mLogs.size() >= LOG_SIZE) {
-            // Remove the oldest
+            // Remove oldest element
             mLogs.pollLast();
         }
-        mLogs.addFirst(log);
-        // Display log
-        mLogView.setText(String.join("\n", mLogs));
-    }
-
-    private void refreshHistory() {
-        mConfigNameView.setText(mSelectedInfoConfig.getName());
-        if (mDataRadioSelected) {
-            mHistoryView.setText(mSelectedInfoConfig.getBundleHistoryString());
-        } else {
-            mHistoryView.setText(mSelectedInfoConfig.getErrorHistoryString());
-        }
-    }
-
-    /** Listener for getting notified of ready reports. */
-    private class ReportListener implements ReportReadyListener {
-        @Override
-        public void onReady(@NonNull String metricsConfigName) {
-            mService.getFinishedReport(metricsConfigName, getMainExecutor(), mReportCallback);
-        }
-    }
-
-    /** Callback when report is retrieved. */
-    private class ReportCallback implements MetricsReportCallback {
-        @Override
-        public void onResult(
-                @NonNull String metricsConfigName,
-                @Nullable PersistableBundle report,
-                @Nullable byte[] telemetryError,
-                int status) {
-            int index = mConfigNameIndex.get(metricsConfigName);
-            ConfigData config = mConfigList.get(index);
-            StringBuilder sb = new StringBuilder();
-            sb.append(LocalDateTime.now(ZoneId.systemDefault())
-                    .format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")))
-                .append(": ");
-            if (report != null) {
-                sb.append("Received Report - ");
-                config.onReadyTimes += 1;
-                config.sentBytes += getPersistableBundleByteSize(report);
-                if (report != null) {
-                    // Add to bundle history
-                    config.addBundle(LocalDateTime.now(ZoneId.systemDefault()), report);
-                }
-            } else if (telemetryError != null) {
-                sb.append("Received Error - ");
-                config.errorCount += 1;
-                TelemetryError error = getErrorFromBytes(telemetryError);
-                if (error != null) {
-                    // Add to error history
-                    config.addError(LocalDateTime.now(ZoneId.systemDefault()), error);
-                }
-            }
-            sb.append(metricsConfigName);
-            mAdapter.notifyItemChanged(index);
-            addToLog(sb.toString());
-            writeAppData();
-            refreshHistory();
-        }
+        mLogs.addFirst(text);
+        getMainExecutor().execute(() -> {
+            mLogView.setText(String.join("\n", mLogs));
+        });
     }
 
     private class AdaptorCallback implements ConfigListAdaptor.Callback {
         @Override
-        public void onCheckedChanged(ConfigData config, boolean isChecked) {
-            int index = mConfigNameIndex.get(config.getName());
-            if (isChecked) {
-                mService.addMetricsConfig(
-                        config.getName(),
-                        getMainExecutor(),
-                        new AddConfigCallback(config, mAdapter, index, getMainExecutor()));
-            } else {
-                mService.removeMetricsConfig(config.getName());
-                config.selected = false;
-                getMainExecutor().execute(() -> {
-                    mAdapter.notifyItemChanged(index);
-                    writeAppData();
-                });
+        public void onAddButtonClicked(IConfigData configData) {
+            try {
+                mService.addConfig(configData.name);
+            } catch (RemoteException e) {
+                throw new IllegalStateException(
+                        "Failed to ICarMetricsCollectorService.addConfig.", e);
             }
         }
 
         @Override
-        public void onInfoButtonClicked(ConfigData config) {
-            mSelectedInfoConfig = config;
-            mConfigNameView.setText(config.getName());
-            if (mDataRadioSelected) {
-                mHistoryView.setText(config.getBundleHistoryString());
-            } else {
-                mHistoryView.setText(config.getErrorHistoryString());
+        public void onRemoveButtonClicked(IConfigData configData) {
+            try {
+                mService.removeConfig(configData.name);
+            } catch (RemoteException e) {
+                throw new IllegalStateException(
+                        "Failed to ICarMetricsCollectorService.removeConfig.", e);
             }
-        }
-
-        @Override
-        public void onClearButtonClicked(ConfigData config) {
-            int index = mConfigNameIndex.get(config.getName());
-            config.clearHistory();
+            configData.selected = false;
             getMainExecutor().execute(() -> {
-                mAdapter.notifyItemChanged(index);
-                writeAppData();
+                mAdapter.notifyItemChanged(mConfigNameIndex.get(configData.name));
+            });
+            printLog("Removed config " + configData.name);
+        }
+
+        @Override
+        public void onInfoButtonClicked(IConfigData configData) {
+            mSelectedInfoConfig = configData;
+            mConfigNameView.setText(configData.name);
+            lazyInitHistories(configData.name);
+            getMainExecutor().execute(() -> {
+                if (mDataRadioSelected) {
+                    mHistoryView.setText(getBundleHistoryString(configData.name));
+                } else {
+                    mHistoryView.setText(getErrorHistoryString(configData.name));
+                }
             });
         }
-    }
 
-    private class AddConfigCallback implements AddMetricsConfigCallback {
-        private ConfigData mConfig;
-        private ConfigListAdaptor mAdaptor;
-        private int mIndex;
-        private Executor mExecutor;
-        AddConfigCallback(
-                ConfigData config, ConfigListAdaptor adaptor, int index, Executor executor) {
-            mConfig = config;
-            mAdaptor = adaptor;
-            mIndex = index;
-            mExecutor = executor;
-        }
         @Override
-        public void onAddMetricsConfigStatus(
-                @NonNull String metricsConfigName, int statusCode) {
-            if (statusCode == STATUS_ADD_METRICS_CONFIG_SUCCEEDED
-                    || statusCode == STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS) {
-                mConfig.selected = true;
-            } else {
-                mConfig.selected = false;
-            }
-            mExecutor.execute(() -> {
-                mAdaptor.notifyItemChanged(mIndex);
-                writeAppData();
+        public void onClearButtonClicked(IConfigData configData) {
+            int index = mConfigNameIndex.get(configData.name);
+            clearConfigData(configData);
+            getMainExecutor().execute(() -> {
+                mAdapter.notifyItemChanged(index);
             });
         }
     }
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigData.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigData.java
deleted file mode 100644
index c9c27b3..0000000
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigData.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.cartelemetryapp;
-
-import android.car.telemetry.TelemetryProto.TelemetryError;
-import android.os.PersistableBundle;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayDeque;
-import java.util.Deque;
-
-/** Class for keeping config data. */
-public class ConfigData implements Serializable {
-    public boolean selected = true;
-    public int onReadyTimes = 0;
-    public int sentBytes = 0;
-    public int errorCount = 0;
-    private String mName;
-    private Deque<BundleHistory> mBundleHistory = new ArrayDeque<>();
-    private Deque<ErrorHistory> mErrorHistory = new ArrayDeque<>();
-    private static final int HISTORY_SIZE = 10;
-
-    ConfigData(String name) {
-        mName = name;
-    }
-
-    /*
-    * Gets the config name.
-    */
-    public String getName() {
-        return mName;
-    }
-
-    /*
-    * Adds a bundle to the bundles history deque.
-    *
-    * Newest entry is added to the front while oldest are a the end.
-    * Only a limited number of entries are kept.
-    *
-    * @param time timestamp of the bundle.
-    * @param bundle the {@link PersistableBundle} to be saved as history.
-    */
-    public void addBundle(LocalDateTime time, PersistableBundle bundle) {
-        if (mBundleHistory.size() >= HISTORY_SIZE) {
-            // Remove oldest element
-            mBundleHistory.pollLast();
-        }
-        mBundleHistory.addFirst(new BundleHistory(time, bundle));
-    }
-
-    /**
-     * Clears all of configs history.
-     */
-    public void clearHistory() {
-        onReadyTimes = 0;
-        sentBytes = 0;
-        errorCount = 0;
-        mBundleHistory.clear();
-        mErrorHistory.clear();
-    }
-
-    /*
-    * Adds an error data to the bundles errors deque.
-    *
-    * Newest entry is added to the front while oldest are a the end.
-    * Only a limited number of entries are kept.
-    *
-    * @param time timestamp of the error.
-    * @param error the {@link TelemetryError} to be saved as history.
-    */
-    public void addError(LocalDateTime time, TelemetryError error) {
-        if (mErrorHistory.size() >= HISTORY_SIZE) {
-            // Remove oldest element
-            mErrorHistory.pollLast();
-        }
-        mErrorHistory.addFirst(new ErrorHistory(time, error));
-    }
-
-    /*
-    * Gets the string representation of the bundle history.
-    *
-    * @return string of the saved bundles history.
-    */
-    public String getBundleHistoryString() {
-        StringBuilder sb = new StringBuilder();
-        for (BundleHistory bh : mBundleHistory) {
-            sb.append(bh.getString()).append("\n");
-        }
-        return sb.toString();
-    }
-
-    /*
-    * Gets the string representation of the error history.
-    *
-    * @return string of the saved error history.
-    */
-    public String getErrorHistoryString() {
-        StringBuilder sb = new StringBuilder();
-        for (ErrorHistory eh : mErrorHistory) {
-            sb.append(eh.getString()).append("\n");
-        }
-        return sb.toString();
-    }
-
-    private static class BundleHistory implements Serializable {
-        private LocalDateTime mTime;
-        private transient PersistableBundle mBundle;
-
-        BundleHistory(LocalDateTime t, PersistableBundle b) {
-            mTime = t;
-            mBundle = b;
-        }
-
-        LocalDateTime getTime() {
-            return mTime;
-        }
-
-        PersistableBundle getBundle() {
-            return mBundle;
-        }
-
-        String getString() {
-            StringBuilder sb = new StringBuilder()
-                    .append(mTime.format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")))
-                    .append(":\n");
-            for (String key : mBundle.keySet()) {
-                sb.append("    ")
-                    .append(key)
-                    .append(": ")
-                    .append(mBundle.get(key).toString())
-                    .append("\n");
-            }
-            return sb.toString();
-        }
-
-        private void writeObject(ObjectOutputStream oos) throws IOException {
-            oos.defaultWriteObject();
-            mBundle.writeToStream(oos);
-        }
-
-        private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
-            ois.defaultReadObject();
-            mBundle = PersistableBundle.readFromStream(ois);
-        }
-    }
-
-    private static class ErrorHistory implements Serializable {
-        private LocalDateTime mTime;
-        private transient TelemetryError mError;
-
-        ErrorHistory(LocalDateTime t, TelemetryError e) {
-            mTime = t;
-            mError = e;
-        }
-
-        LocalDateTime getTime() {
-            return mTime;
-        }
-
-        TelemetryError getError() {
-            return mError;
-        }
-
-        String getString() {
-            StringBuilder sb = new StringBuilder()
-                    .append(mTime.format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")))
-                    .append(":\n")
-                    .append("    Error type: ")
-                    .append(mError.getErrorType().name())
-                    .append("\n")
-                    .append("    Message: ")
-                    .append(mError.getMessage());
-            return sb.toString();
-        }
-
-        private void writeObject(ObjectOutputStream oos) throws IOException {
-            oos.defaultWriteObject();
-            mError.writeTo(oos);
-        }
-
-        private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
-            ois.defaultReadObject();
-            mError = TelemetryError.parseFrom(ois);
-        }
-    }
-}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java
index 8a90a69..b43db7e 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java
@@ -29,66 +29,43 @@
 import java.util.List;
 
 public class ConfigListAdaptor extends RecyclerView.Adapter<ConfigListAdaptor.ViewHolder> {
-    private List<ConfigData> mConfigs;
+    private List<IConfigData> mConfigs;
     private Callback mCallback;
 
     public interface Callback {
-        void onCheckedChanged(ConfigData config, boolean isChecked);
-        void onInfoButtonClicked(ConfigData config);
-        void onClearButtonClicked(ConfigData config);
+        void onAddButtonClicked(IConfigData config);
+        void onRemoveButtonClicked(IConfigData config);
+        void onInfoButtonClicked(IConfigData config);
+        void onClearButtonClicked(IConfigData config);
     }
 
     public static class ViewHolder extends RecyclerView.ViewHolder {
-        private final CheckBox mCheckBox;
-        private final TextView mConfigText;
-        private final TextView mOnReadyText;
-        private final TextView mSentBytesText;
-        private final TextView mErrorsCountText;
-        private final Button mInfoButton;
-        private final Button mClearButton;
+        public final CheckBox checkBox;
+        public final TextView configText;
+        public final TextView onReadyText;
+        public final TextView sentBytesText;
+        public final TextView errorsCountText;
+        public final Button addConfigButton;
+        public final Button removeConfigButton;
+        public final Button infoButton;
+        public final Button clearButton;
 
         public ViewHolder(View view) {
             super(view);
-            mCheckBox = view.findViewById(R.id.checkbox);
-            mConfigText = view.findViewById(R.id.config_name_text);
-            mOnReadyText = view.findViewById(R.id.on_ready_times_text);
-            mSentBytesText = view.findViewById(R.id.sent_bytes_text);
-            mErrorsCountText = view.findViewById(R.id.error_count_text);
-            mInfoButton = view.findViewById(R.id.show_info_button);
-            mClearButton = view.findViewById(R.id.clear_info_button);
-        }
-
-        public CheckBox getCheckBox() {
-            return mCheckBox;
-        }
-
-        public TextView getConfigText() {
-            return mConfigText;
-        }
-
-        public TextView getOnReadyText() {
-            return mOnReadyText;
-        }
-
-        public TextView getSentBytesText() {
-            return mSentBytesText;
-        }
-
-        public TextView getErrorsCountText() {
-            return mErrorsCountText;
-        }
-
-        public Button getInfoButton() {
-            return mInfoButton;
-        }
-
-        public Button getClearButton() {
-            return mClearButton;
+            checkBox = view.findViewById(R.id.checkbox);
+            configText = view.findViewById(R.id.config_name_text);
+            onReadyText = view.findViewById(R.id.on_ready_times_text);
+            sentBytesText = view.findViewById(R.id.sent_bytes_text);
+            errorsCountText = view.findViewById(R.id.error_count_text);
+            addConfigButton = view.findViewById(R.id.add_config_button);
+            removeConfigButton = view.findViewById(R.id.remove_config_button);
+            infoButton = view.findViewById(R.id.show_info_button);
+            clearButton = view.findViewById(R.id.clear_info_button);
         }
     }
 
     public ConfigListAdaptor(
-            List<ConfigData> configs,
+            List<IConfigData> configs,
             Callback callback) {
         mConfigs = configs;
         mCallback = callback;
@@ -105,20 +82,23 @@
     @Override
     public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
         int pos = holder.getAbsoluteAdapterPosition();
-        ConfigData config = mConfigs.get(pos);
-        holder.getConfigText().setText(config.getName());
-        holder.getCheckBox().setOnCheckedChangeListener((buttonView, isChecked) -> {
-            mCallback.onCheckedChanged(config, isChecked);
-        });
-        holder.getCheckBox().setChecked(config.selected);
-        holder.getOnReadyText().setText(String.valueOf(config.onReadyTimes));
+        IConfigData config = mConfigs.get(pos);
+        holder.checkBox.setChecked(config.selected);
+        holder.configText.setText(config.name);
+        holder.onReadyText.setText(String.valueOf(config.onReadyTimes));
         String bytesSentStr = String.valueOf(config.sentBytes) + " B";
-        holder.getSentBytesText().setText(bytesSentStr);
-        holder.getErrorsCountText().setText(String.valueOf(config.errorCount));
-        holder.getInfoButton().setOnClickListener(v -> {
+        holder.sentBytesText.setText(bytesSentStr);
+        holder.errorsCountText.setText(String.valueOf(config.errorCount));
+        holder.addConfigButton.setOnClickListener(v -> {
+            mCallback.onAddButtonClicked(config);
+        });
+        holder.removeConfigButton.setOnClickListener(v -> {
+            mCallback.onRemoveButtonClicked(config);
+        });
+        holder.infoButton.setOnClickListener(v -> {
             mCallback.onInfoButtonClicked(config);
         });
-        holder.getClearButton().setOnClickListener(v -> {
+        holder.clearButton.setOnClickListener(v -> {
             mCallback.onClearButtonClicked(config);
         });
     }
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java
index cd97210..870b7b0 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java
@@ -118,6 +118,7 @@
             log("Error parsing XML file! " + parser.getPositionDescription()
                     + " Error: " + e.getMessage());
         }
+        log("Finished parsing configs: " + configs.size());
         return configs;
     }
 
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ICarMetricsCollectorService.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ICarMetricsCollectorService.aidl
new file mode 100644
index 0000000..9cd2aba
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ICarMetricsCollectorService.aidl
@@ -0,0 +1,20 @@
+package com.android.car.cartelemetryapp;
+
+import android.os.PersistableBundle;
+import com.android.car.cartelemetryapp.IConfigData;
+import com.android.car.cartelemetryapp.IConfigStateListener;
+import com.android.car.cartelemetryapp.IResultListener;
+
+import java.util.List;
+
+interface ICarMetricsCollectorService {
+    List<IConfigData> getConfigData();
+    void addConfig(in String configName);
+    void removeConfig(in String configName);
+    void setConfigStateListener(in IConfigStateListener listener);
+    void setResultListener(in IResultListener listener);
+    List<PersistableBundle> getBundleHistory(in String configName);
+    List<String> getErrorHistory(in String configName);
+    void clearHistory(in String configName);
+    String getLog();
+}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigData.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigData.aidl
new file mode 100644
index 0000000..db3dbf6
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigData.aidl
@@ -0,0 +1,10 @@
+package com.android.car.cartelemetryapp;
+
+parcelable IConfigData {
+    boolean selected;
+    int onReadyTimes;
+    int sentBytes;
+    int errorCount;
+    int version;
+    String name;
+}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigStateListener.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigStateListener.aidl
new file mode 100644
index 0000000..b3172d9
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigStateListener.aidl
@@ -0,0 +1,5 @@
+package com.android.car.cartelemetryapp;
+
+interface IConfigStateListener {
+    void onConfigAdded(in String configName);
+}
\ No newline at end of file
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IResultListener.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IResultListener.aidl
new file mode 100644
index 0000000..7725e4a
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IResultListener.aidl
@@ -0,0 +1,12 @@
+package com.android.car.cartelemetryapp;
+
+import android.os.PersistableBundle;
+import com.android.car.cartelemetryapp.IConfigData;
+
+interface IResultListener {
+    void onResult(
+            in String metricsConfigName,
+            in IConfigData configData,
+            in PersistableBundle report,
+            in String telemetryError);
+}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/values-en-rCA/strings.xml b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
index 4833f5f..bd4ccb9 100644
--- a/tests/DiagnosticTools/res/values-en-rCA/strings.xml
+++ b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display Freeze Frame Info"</string>
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
 </resources>
diff --git a/tests/DiagnosticTools/res/values-ro/strings.xml b/tests/DiagnosticTools/res/values-ro/strings.xml
index 014f068..d06e299 100644
--- a/tests/DiagnosticTools/res/values-ro/strings.xml
+++ b/tests/DiagnosticTools/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișează informații despre cadrul blocat"</string>
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișați informații despre cadrul blocat"</string>
 </resources>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
index 2a5d05f..8340a55 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
@@ -364,6 +364,31 @@
                     android:layout_height="wrap_content"
                     android:text="@string/get_report"/>
             </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/process_memory_snapshot_config"/>
+                <Button
+                    android:id="@+id/send_on_process_memory_snapshot_config"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/add_metrics_config"/>
+                <Button
+                    android:id="@+id/remove_on_process_memory_snapshot_config"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/remove_metrics_config"/>
+                <Button
+                    android:id="@+id/get_on_process_memory_snapshot_report"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/get_report"/>
+            </LinearLayout>
         </LinearLayout> <!-- @+id/metrics_config_buttons -->
 
         <TextView
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 841e2ff..054a784 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -387,7 +387,7 @@
 
     <!-- CarTelemetryService Test -->
     <string name="gear_change_config" translatable="false">on_gear_change:</string>
-    <string name="process_memory_config" translatable="false">process_memory:</string>
+    <string name="process_memory_config" translatable="false">process_memory_state:</string>
     <string name="app_start_memory_state_captured_config" translatable="false">app_start_memory_state_captured:</string>
     <string name="activity_foreground_state_changed_config" translatable="false">activity_foreground_state_changed:</string>
     <string name="process_cpu_time_config" translatable="false">process_cpu_time:</string>
@@ -397,6 +397,7 @@
     <string name="wifi_netstats_config" translatable="false">wifi_netstats_top_consumers:</string>
     <string name="stats_and_connectivity_config" translatable="false">stats and connectivity:</string>
     <string name="memory_config" translatable="false">memory:</string>
+    <string name="process_memory_snapshot_config" translatable="false">process_memory_snapshot:</string>
     <string name="add_metrics_config" translatable="false">Add MetricsConfig</string>
     <string name="remove_metrics_config" translatable="false">Remove MetricsConfig</string>
     <string name="download_data" translatable="false">Download Data</string>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
index 15a9513..40a965f 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
@@ -21,6 +21,7 @@
 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_CRASH_OCCURRED;
 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_START_MEMORY_STATE_CAPTURED;
 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_CPU_TIME;
+import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_SNAPSHOT;
 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_STATE;
 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.WTF_OCCURRED;
 
@@ -69,8 +70,12 @@
     /** Vehicle property via gear change section. */
     private static final String LUA_SCRIPT_ON_GEAR_CHANGE =
             "function onGearChange(published_data, state)\n"
-                    + "    result = {data = \"Hello World!\"}\n"
-                    + "    on_script_finished(result)\n"
+                    + "    t = {}\n"
+                    + "    for k, v in ipairs(published_data) do\n"
+                    + "        t['#' .. k] = 'Gear: ' .. v['intVal'] \n"
+                    + "        log(v[\"intVal\"])\n"
+                    + "    end\n"
+                    + "    on_metrics_report(t)\n"
                     + "end\n";
 
     private static final TelemetryProto.Publisher VEHICLE_PROPERTY_PUBLISHER =
@@ -90,7 +95,7 @@
                             TelemetryProto.Subscriber.newBuilder()
                                     .setHandler("onGearChange")
                                     .setPublisher(VEHICLE_PROPERTY_PUBLISHER)
-                                    .setPriority(SCRIPT_EXECUTION_PRIORITY_LOW))
+                                    .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
                     .build();
     private static final String ON_GEAR_CHANGE_CONFIG_NAME =
             METRICS_CONFIG_ON_GEAR_CHANGE_V1.getName();
@@ -98,8 +103,8 @@
     /** ProcessMemoryState section. */
     private static final String LUA_SCRIPT_ON_PROCESS_MEMORY_STATE = new StringBuilder()
             .append("function calculateAverage(tbl)\n")
-            .append("    sum = 0\n")
-            .append("    size = 0\n")
+            .append("    local sum = 0\n")
+            .append("    local size = 0\n")
             .append("    for _, value in ipairs(tbl) do\n")
             .append("        sum = sum + value\n")
             .append("        size = size + 1\n")
@@ -107,7 +112,7 @@
             .append("    return sum/size\n")
             .append("end\n")
             .append("function onProcessMemory(published_data, state)\n")
-            .append("    result = {}\n")
+            .append("    local result = {}\n")
             .append("    result.page_fault_avg = calculateAverage(published_data.page_fault)\n")
             .append("    result.major_page_fault_avg = calculateAverage("
                     + "published_data.page_major_fault)\n")
@@ -145,8 +150,8 @@
     /** AppStartMemoryStateCaptured section. */
     private static final String LUA_SCRIPT_ON_APP_START_MEMORY_STATE_CAPTURED = new StringBuilder()
             .append("function calculateAverage(tbl)\n")
-            .append("    sum = 0\n")
-            .append("    size = 0\n")
+            .append("    local sum = 0\n")
+            .append("    local size = 0\n")
             .append("    for _, value in ipairs(tbl) do\n")
             .append("        sum = sum + value\n")
             .append("        size = size + 1\n")
@@ -154,7 +159,7 @@
             .append("    return sum/size\n")
             .append("end\n")
             .append("function onAppStartMemoryStateCaptured(published_data, state)\n")
-            .append("    result = {}\n")
+            .append("    local result = {}\n")
             .append("    result.uid = published_data.uid\n")
             .append("    result.page_fault_avg = calculateAverage(published_data.page_fault)\n")
             .append("    result.major_page_fault_avg = calculateAverage("
@@ -192,8 +197,8 @@
     private static final String LUA_SCRIPT_ON_ACTIVITY_FOREGROUND_STATE_CHANGED =
             new StringBuilder()
                     .append("function onActivityForegroundStateChanged(published_data, state)\n")
-                    .append("    result = {}\n")
-                    .append("    n = 0\n")
+                    .append("    local result = {}\n")
+                    .append("    local n = 0\n")
                     .append("    for k, v in pairs(published_data) do\n")
                     .append("        result[k] = v[1]\n")
                     .append("        n = n + 1\n")
@@ -227,8 +232,8 @@
     private static final String LUA_SCRIPT_ON_PROCESS_CPU_TIME =
             new StringBuilder()
                     .append("function onProcessCpuTime(published_data, state)\n")
-                    .append("    result = {}\n")
-                    .append("    n = 0\n")
+                    .append("    local result = {}\n")
+                    .append("    local n = 0\n")
                     .append("    for k, v in pairs(published_data) do\n")
                     .append("        result[k] = v[1]\n")
                     .append("        n = n + 1\n")
@@ -262,7 +267,7 @@
     private static final String LUA_SCRIPT_ON_APP_CRASH_OCCURRED =
             new StringBuilder()
                     .append("function onAppCrashOccurred(published_data, state)\n")
-                    .append("    result = {}\n")
+                    .append("    local result = {}\n")
                     .append("    for k, v in pairs(published_data) do\n")
                     .append("        result[k] = v[1]\n")
                     .append("    end\n")
@@ -294,7 +299,7 @@
     private static final String LUA_SCRIPT_ON_ANR_OCCURRED =
             new StringBuilder()
                     .append("function onAnrOccurred(published_data, state)\n")
-                    .append("    result = {}\n")
+                    .append("    local result = {}\n")
                     .append("    for k, v in pairs(published_data) do\n")
                     .append("        result[k] = v[1]\n")
                     .append("    end\n")
@@ -325,7 +330,7 @@
     private static final String LUA_SCRIPT_ON_WTF_OCCURRED =
             new StringBuilder()
                     .append("function onWtfOccurred(published_data, state)\n")
-                    .append("    result = {}\n")
+                    .append("    local result = {}\n")
                     .append("    for k, v in pairs(published_data) do\n")
                     .append("        result[k] = v[1]\n")
                     .append("    end\n")
@@ -427,15 +432,13 @@
                     .append("        iterations = 0\n")
                     .append("    end\n")
                     .append("    state['iterations'] = iterations + 1\n")
-                    .append("    report = {}\n")
-                    .append("    local ts_key = 'timestamp_' .. iterations\n")
-                    .append("    report[ts_key] = published_data['timestamp']\n")
                     .append("    local meminfo = published_data['meminfo']\n")
                     .append("    local available_memory = string.match(meminfo, "
                             + "'.*MemAvailable:%s*(%d+).*')\n")
                     .append("    local mem_key = 'available_memory_' .. iterations\n")
-                    .append("    report[mem_key] = available_memory\n")
-                    .append("    on_metrics_report(report, state)\n")
+                    .append("    published_data[mem_key] = available_memory\n")
+                    .append("    published_data['meminfo'] = nil\n")
+                    .append("    on_metrics_report(published_data, state)\n")
                     .append("end\n")
                     .toString();
     private static final TelemetryProto.Publisher MEMORY_PUBLISHER =
@@ -445,6 +448,8 @@
                                     .setReadIntervalSec(3)
                                     .setMaxSnapshots(3)
                                     .setMaxPendingTasks(10)
+                                    .addPackageNames("com.android.car")
+                                    .addPackageNames("com.android.car.scriptexecutor")
                                     .build())
                     .build();
     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_MEMORY_V1 =
@@ -461,6 +466,32 @@
     private static final String MEMORY_CONFIG_NAME =
             METRICS_CONFIG_MEMORY_V1.getName();
 
+    /** ProcessMemorySnapshot section. */
+    private static final String LUA_SCRIPT_ON_PROCESS_MEMORY_SNAPSHOT = new StringBuilder()
+            .append("function onProcessMemorySnapshot(published_data, state)\n")
+            .append("    on_script_finished(published_data)\n")
+            .append("end\n")
+            .toString();
+    private static final TelemetryProto.Publisher PROCESS_MEMORY_SNAPSHOT_PUBLISHER =
+            TelemetryProto.Publisher.newBuilder()
+                    .setStats(
+                            TelemetryProto.StatsPublisher.newBuilder()
+                                    .setSystemMetric(PROCESS_MEMORY_SNAPSHOT))
+                    .build();
+    private static final TelemetryProto.MetricsConfig METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1 =
+            TelemetryProto.MetricsConfig.newBuilder()
+                    .setName("process_memory_snapshot_metrics_config")
+                    .setVersion(1)
+                    .setScript(LUA_SCRIPT_ON_PROCESS_MEMORY_SNAPSHOT)
+                    .addSubscribers(
+                            TelemetryProto.Subscriber.newBuilder()
+                                    .setHandler("onProcessMemorySnapshot")
+                                    .setPublisher(PROCESS_MEMORY_SNAPSHOT_PUBLISHER)
+                                    .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
+                    .build();
+    private static final String PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME =
+            METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1.getName();
+
     private final Executor mExecutor = Executors.newSingleThreadExecutor();
 
     private boolean mReceiveReportNotification = false;
@@ -588,6 +619,13 @@
                 .setOnClickListener(this::onRemoveMemoryConfigBtnClick);
         view.findViewById(R.id.get_memory_report)
                 .setOnClickListener(this::onGetMemoryReportBtnClick);
+        /** StatsPublisher process_memory_snapshot */
+        view.findViewById(R.id.send_on_process_memory_snapshot_config)
+                .setOnClickListener(this::onSendProcessMemorySnapshotConfigBtnClick);
+        view.findViewById(R.id.remove_on_process_memory_snapshot_config)
+                .setOnClickListener(this::onRemoveProcessMemorySnapshotConfigBtnClick);
+        view.findViewById(R.id.get_on_process_memory_snapshot_report)
+                .setOnClickListener(this::onGetProcessMemorySnapshotReportBtnClick);
         /** Print mem info button */
         view.findViewById(R.id.print_mem_info_btn).setOnClickListener(this::onPrintMemInfoBtnClick);
         return view;
@@ -978,6 +1016,24 @@
         mCarTelemetryManager.getFinishedReport(MEMORY_CONFIG_NAME, mExecutor, mListener);
     }
 
+    private void onSendProcessMemorySnapshotConfigBtnClick(View view) {
+        mCarTelemetryManager.addMetricsConfig(
+                PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME,
+                METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1.toByteArray(),
+                mExecutor,
+                mAddMetricsConfigCallback);
+    }
+
+    private void onRemoveProcessMemorySnapshotConfigBtnClick(View view) {
+        showOutput("Removing MetricsConfig that listens for PROCESS_MEMORY_SNAPSHOT...");
+        mCarTelemetryManager.removeMetricsConfig(PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME);
+    }
+
+    private void onGetProcessMemorySnapshotReportBtnClick(View view) {
+        mCarTelemetryManager.getFinishedReport(
+                PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME, mExecutor, mListener);
+    }
+
     /** Gets a MemoryInfo object for the device's current memory status. */
     private ActivityManager.MemoryInfo getAvailableMemory() {
         ActivityManager activityManager = getActivity().getSystemService(ActivityManager.class);
diff --git a/tests/OemCarServiceTestApp/Android.bp b/tests/OemCarServiceTestApp/Android.bp
new file mode 100644
index 0000000..002f401
--- /dev/null
+++ b/tests/OemCarServiceTestApp/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "OemCarServiceTestApp",
+    srcs: ["src/**/*.java"],
+    min_sdk_version: "33",
+    privileged: true,
+    certificate: "platform",
+    platform_apis: true,
+    libs: ["android.car-system-stubs"],
+}
diff --git a/tests/OemCarServiceTestApp/AndroidManifest.xml b/tests/OemCarServiceTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..9851015
--- /dev/null
+++ b/tests/OemCarServiceTestApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.oemcarservice.testapp">
+
+    <application>
+        <service android:name="com.android.car.oemcarservice.testapp.OemCarServiceImpl"
+                 android:directBootAware="true"
+                 android:permission="android.car.permission.BIND_OEM_CAR_SERVICE"
+                 android:exported="true">
+        </service>
+    </application>
+</manifest>
diff --git a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java
new file mode 100644
index 0000000..b6ab216
--- /dev/null
+++ b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.oemcarservice.testapp;
+
+import android.car.oem.OemCarAudioFocusService;
+import android.media.AudioFocusInfo;
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+public final class OemCarAudioFocusServiceImpl implements OemCarAudioFocusService {
+
+    private static final String TAG = OemCarAudioFocusServiceImpl.class.getSimpleName();
+
+    public OemCarAudioFocusServiceImpl() {
+        Log.d(TAG, "constructor");
+    }
+
+    @Override
+    public void init() {
+        Log.d(TAG, "init");
+
+    }
+
+    @Override
+    public void release() {
+        Log.d(TAG, "release");
+    }
+
+    @Override
+    public void onCarServiceReady() {
+        Log.d(TAG, "onCarServiceReady");
+        // Do any CarService calls
+    }
+
+    @Override
+    public void dump(PrintWriter writer, String[] args) {
+        Log.d(TAG, "dump");
+        writer.println("Dump OemCarAudioFocusServiceImpl");
+    }
+
+    @Override
+    public void audioFocusChanged(List<AudioFocusInfo> currentFocusHolders,
+            List<AudioFocusInfo> currentFocusLosers, int zoneId) {
+        Log.d(TAG, "OemCarAudioFocusServiceImpl audioFocusChanged called");
+    }
+
+}
diff --git a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java
new file mode 100644
index 0000000..4aec93c
--- /dev/null
+++ b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.oemcarservice.testapp;
+
+import android.car.CarVersion;
+import android.car.oem.OemCarAudioFocusService;
+import android.car.oem.OemCarService;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public final class OemCarServiceImpl extends OemCarService {
+
+    private static final String TAG = OemCarServiceImpl.class.getSimpleName();
+    private static final CarVersion SUPPORTED_CAR_VERSION =
+            CarVersion.VERSION_CODES.TIRAMISU_2;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private OemCarAudioFocusServiceImpl mOemCarAudioFocusServiceImpl;
+
+    @Override
+    public void onCreate() {
+        Log.d(TAG, "onCreate");
+
+        // Initialize all subcomponents.
+        synchronized (mLock) {
+            mOemCarAudioFocusServiceImpl = new OemCarAudioFocusServiceImpl();
+        }
+        super.onCreate();
+    }
+
+
+    @Override
+    public void onDestroy() {
+        Log.d(TAG, "onDestroy");
+        // Releases resource from subcomponents.
+        synchronized (mLock) {
+            mOemCarAudioFocusServiceImpl = null;
+        }
+        super.onDestroy();
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        Log.d(TAG, "dump");
+        writer.println("Dump OemCarServiceImpl");
+        writer.println("SUPPORTED_CAR_VERSION:" + SUPPORTED_CAR_VERSION);
+
+    }
+
+    @Override
+    public OemCarAudioFocusService getOemAudioFocusService() {
+        synchronized (mLock) {
+            Log.d(TAG, "getOemAudioFocusService returned " + mOemCarAudioFocusServiceImpl);
+            return mOemCarAudioFocusServiceImpl;
+        }
+    }
+
+    @Override
+    public void onCarServiceReady() {
+        Log.d(TAG, "onCarServiceReady");
+    }
+
+    @Override
+    public CarVersion getSupportedCarVersion() {
+        Log.d(TAG, "OemCarServiceImpl getSupportedCarVersion called");
+        return SUPPORTED_CAR_VERSION;
+    }
+
+}
diff --git a/tests/carservice_unit_test/res/raw/car_api_classes.txt b/tests/carservice_unit_test/res/raw/car_api_classes.txt
index 11fc354..bbcfc78 100644
--- a/tests/carservice_unit_test/res/raw/car_api_classes.txt
+++ b/tests/carservice_unit_test/res/raw/car_api_classes.txt
@@ -172,6 +172,9 @@
 android.car.occupantawareness.OccupantAwarenessManager$ChangeCallback
 android.car.occupantawareness.Point3D
 android.car.occupantawareness.SystemStatusEvent
+android.car.oem.OemCarAudioFocusService
+android.car.oem.OemCarService
+android.car.oem.OemCarServiceComponent
 android.car.os.CarPerformanceManager
 android.car.os.CarPerformanceManager$SetSchedulerFailedException
 android.car.os.CarPerformanceManager$CpuAvailabilityChangeListener
diff --git a/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml b/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
new file mode 100644
index 0000000..b9dd072
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="someGroup">
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="expected_to_be_registered"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_incorrect_id">
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml b/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml
new file mode 100644
index 0000000..76cc501
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="mixed_policy_group">
+        <policyGroup id="basic_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <defaultPolicy state="On" id="policy_id_other_untouched"/>
+        </policyGroup>
+        <policyGroup id="no_default_policy_group">
+            <noDefaultPolicy state="WaitForVHAL"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+        <policy id="policy_id_other_off">
+            <otherComponents behavior="off"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_DISPLAY">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_untouched">
+            <otherComponents behavior="untouched"/>
+            <component id="POWER_COMPONENT_AUDIO">on</component>
+            <component id="POWER_COMPONENT_DISPLAY">on</component>
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">on</component>
+        </policy>
+        <policy id="policy_id_other_on">
+            <otherComponents behavior="on"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_none">
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_no_user_interaction">
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java b/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java
new file mode 100644
index 0000000..2c60199
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.CarVersion;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.pm.PackageManager;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Test;
+import org.mockito.Mock;
+
+public final class OemCarServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private final CarVersion mCarVersionForTesting = CarVersion.VERSION_CODES.TIRAMISU_2;
+
+    private TestOemCarService mTestOemCarService = new TestOemCarService();
+    private IOemCarService mOemCarService = IOemCarService.Stub
+            .asInterface(mTestOemCarService.onBind(null));
+
+    @Mock
+    private IOemCarServiceCallback mIOemCarServiceCallback;
+
+    @Mock
+    private OemCarAudioFocusService mOemCarAudioFocusService;
+
+    @Test
+    public void testPermissionCheckForAll() throws Exception {
+        // Without correct permission, SecurityException will be thrown.
+        assertThrows(SecurityException.class,
+                () -> mOemCarService.getSupportedCarVersion());
+        assertThrows(SecurityException.class,
+                () -> mOemCarService.getOemAudioFocusService());
+        assertThrows(SecurityException.class,
+                () -> mOemCarService.onCarServiceReady(mIOemCarServiceCallback));
+    }
+
+    @Test
+    public void testGetSupportedCarVersion() throws Exception {
+        mockCallerPemission();
+
+        assertThat(mOemCarService.getSupportedCarVersion()).isEqualTo(mCarVersionForTesting);
+    }
+
+    @Test
+    public void testGetOemAudioFocusService_notNull() throws Exception {
+        TestOemCarService testOemCarService = new TestOemCarService();
+        testOemCarService.mockCheckCallingPermission();
+        testOemCarService.mockOemAudioFocusService();
+        testOemCarService.onCreate();
+        IOemCarService oemCarService = IOemCarService.Stub
+                .asInterface(testOemCarService.onBind(null));
+
+        assertThat(oemCarService.getOemAudioFocusService()).isNotNull();
+    }
+
+    @Test
+    public void testGetOemAudioFocusService_null() throws Exception {
+        mockCallerPemission();
+
+        assertThat(mOemCarService.getOemAudioFocusService()).isNull();
+    }
+
+    private void mockCallerPemission() {
+        mTestOemCarService.mockCheckCallingPermission();
+    }
+
+    private final class TestOemCarService extends OemCarService {
+
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private boolean mMockAudioFocusService;
+        @GuardedBy("mLock")
+        private boolean mAllowCallingPermission;
+
+        @Override
+        public CarVersion getSupportedCarVersion() {
+            return mCarVersionForTesting;
+        }
+
+        @Override
+        public OemCarAudioFocusService getOemAudioFocusService() {
+            synchronized (mLock) {
+                if (mMockAudioFocusService) {
+                    return mOemCarAudioFocusService;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public int checkCallingPermission(String permission) {
+            synchronized (mLock) {
+                return mAllowCallingPermission ? PackageManager.PERMISSION_GRANTED
+                        : PackageManager.PERMISSION_DENIED;
+            }
+        }
+
+        void mockCheckCallingPermission() {
+            synchronized (mLock) {
+                mAllowCallingPermission = true;
+            }
+        }
+
+        void mockOemAudioFocusService() {
+            synchronized (mLock) {
+                mMockAudioFocusService = true;
+            }
+        }
+
+        @Override
+        public void onCarServiceReady() {
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
index 621c9fc..3c80203 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
@@ -22,7 +22,6 @@
 
 import static com.android.car.admin.NotificationHelper.CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
 import static com.android.car.admin.NotificationHelper.CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS;
-import static com.android.car.admin.NotificationHelper.CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP;
 import static com.android.car.admin.NotificationHelper.CHANNEL_ID_DEFAULT;
 import static com.android.car.admin.NotificationHelper.INTENT_EXTRA_NOTIFICATION_ID;
 import static com.android.car.admin.NotificationHelper.NEW_USER_DISCLAIMER_NOTIFICATION_ID;
@@ -188,23 +187,19 @@
 
         SparseArray<Notification> expectedNotificationsById = new SparseArray<>();
         expectedNotificationsById.put(169, constructNotification(userHandle, "system_package.A",
-                /* notificationId= */ 169, NotificationManager.IMPORTANCE_HIGH,
-                /* isBundledApp= */ true));
+                /* notificationId= */ 169, NotificationManager.IMPORTANCE_HIGH));
         expectedNotificationsById.put(150, constructNotification(userHandle, "vendor_package.A",
-                /* notificationId= */ 150, NotificationManager.IMPORTANCE_HIGH,
-                /* isBundledApp= */ true));
+                /* notificationId= */ 150, NotificationManager.IMPORTANCE_HIGH));
         expectedNotificationsById.put(151, constructNotification(userHandle,
                 "third_party_package.A", /* notificationId= */ 151,
-                NotificationManager.IMPORTANCE_HIGH, /* isBundledApp= */ false));
+                NotificationManager.IMPORTANCE_HIGH));
         expectedNotificationsById.put(152, constructNotification(userHandle, "system_package.B",
-                /* notificationId= */ 152, NotificationManager.IMPORTANCE_DEFAULT,
-                /* isBundledApp= */ true));
+                /* notificationId= */ 152, NotificationManager.IMPORTANCE_DEFAULT));
         expectedNotificationsById.put(153, constructNotification(userHandle, "vendor_package.B",
-                /* notificationId= */ 153, NotificationManager.IMPORTANCE_DEFAULT,
-                /* isBundledApp= */ true));
+                /* notificationId= */ 153, NotificationManager.IMPORTANCE_DEFAULT));
         expectedNotificationsById.put(154, constructNotification(userHandle,
                 "third_party_package.B", /* notificationId= */ 154,
-                NotificationManager.IMPORTANCE_DEFAULT, /* isBundledApp= */ false));
+                NotificationManager.IMPORTANCE_DEFAULT));
 
         captureAndVerifyUserNotifications(expectedNotificationsById, userHandle);
     }
@@ -246,50 +241,36 @@
     }
 
     private Notification constructNotification(UserHandle userHandle, String packageName,
-            int notificationId, int importance, boolean isBundledApp) {
+            int notificationId, int importance) {
         CharSequence title = TextUtils.expandTemplate(
                 mSpiedContext.getText(R.string.resource_overuse_notification_title),
                 packageName + APP_SUFFIX);
         String actionTitlePrioritizeApp = mSpiedContext.getString(
                 R.string.resource_overuse_notification_button_prioritize_app);
+        String contextText =
+                mSpiedContext.getString(R.string.resource_overuse_notification_text_disabled_app);
+        String negativeActionText = mSpiedContext.getString(
+                R.string.resource_overuse_notification_button_close_app);
+
         PendingIntent positiveActionPendingIntent =
                 NotificationHelper.getPendingIntent(mSpiedContext,
                         CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS, userHandle, packageName,
                         notificationId);
-        PendingIntent deletePendingIntent = NotificationHelper.getPendingIntent(mSpiedContext,
+        PendingIntent negativeActionPendingIntent = NotificationHelper.getPendingIntent(
+                mSpiedContext,
                 CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION, userHandle, packageName,
                 notificationId);
 
-        String text;
-        String negativeActionText;
-        PendingIntent negativeActionPendingIntent;
-        if (isBundledApp) {
-            text = mSpiedContext.getString(R.string.resource_overuse_notification_text_disable_app);
-            negativeActionText = mSpiedContext.getString(
-                    R.string.resource_overuse_notification_button_disable_app);
-            negativeActionPendingIntent = NotificationHelper.getPendingIntent(mSpiedContext,
-                    CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP, userHandle,
-                    packageName, notificationId);
-        } else {
-            text = mSpiedContext.getString(
-                    R.string.resource_overuse_notification_text_uninstall_app);
-            negativeActionText = mSpiedContext.getString(
-                    R.string.resource_overuse_notification_button_uninstall_app);
-            negativeActionPendingIntent = positiveActionPendingIntent;
-        }
-        text += " " + mSpiedContext.getString(
-                R.string.resource_overuse_notification_text_prioritize_app);
-
         return NotificationHelper.newNotificationBuilder(mSpiedContext, importance)
                 .setSmallIcon(R.drawable.car_ic_warning)
                 .setContentTitle(title)
-                .setContentText(text)
+                .setContentText(contextText)
                 .setCategory(Notification.CATEGORY_CAR_WARNING)
                 .addAction(new Notification.Action.Builder(/* icon= */ null,
-                        actionTitlePrioritizeApp, positiveActionPendingIntent).build())
-                .addAction(new Notification.Action.Builder(/* icon= */ null,
                         negativeActionText, negativeActionPendingIntent).build())
-                .setDeleteIntent(deletePendingIntent)
+                .addAction(new Notification.Action.Builder(/* icon= */ null,
+                        actionTitlePrioritizeApp, positiveActionPendingIntent).build())
+                .setDeleteIntent(negativeActionPendingIntent)
                 .build();
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
index c6f56cf..0b522d7 100644
--- a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
@@ -74,6 +74,7 @@
 import com.android.car.systeminterface.SystemStateInterface;
 import com.android.car.test.utils.TemporaryFile;
 import com.android.car.user.CarUserService;
+import com.android.compatibility.common.util.PollingCheck;
 import com.android.internal.annotations.GuardedBy;
 
 import org.junit.After;
@@ -315,6 +316,11 @@
     @Test
     public void testAddPowerPolicyListener() throws Exception {
         grantPowerPolicyPermission();
+
+        // Prepare for test
+        applyInitialPolicyForTest(/* policyName= */ "audio_off", /* enabledComponents= */
+                new String[]{}, /* disabledComponents= */ new String[]{"AUDIO"});
+
         String policyId = "audio_on_wifi_off";
         mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"});
         MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
@@ -332,8 +338,10 @@
         mCarPowerManager.addPowerPolicyListener(mExecutor, filterLocation, listenerLocation);
         mCarPowerManager.applyPowerPolicy(policyId);
 
-        assertThat(listenerAudio.getCurrentPolicyId()).isEqualTo(policyId);
-        assertThat(listenerWifi.getCurrentPolicyId()).isEqualTo(policyId);
+        assertPowerPolicyId(listenerAudio, policyId, "Current policy ID of listenerAudio is not "
+                + policyId);
+        assertPowerPolicyId(listenerWifi, policyId, "Current policy ID of listenerWifi is not "
+                + policyId);
         assertThat(listenerLocation.getCurrentPolicyId()).isNull();
     }
 
@@ -372,6 +380,11 @@
     @Test
     public void testRemovePowerPolicyListener() throws Exception {
         grantPowerPolicyPermission();
+
+        String initialPolicyId = "audio_off";
+        applyInitialPolicyForTest(initialPolicyId, /* enabledComponents= */
+                new String[]{}, /* disabledComponents= */ new String[]{"AUDIO"});
+
         String policyId = "audio_on_wifi_off";
         mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"});
         MockedPowerPolicyListener listenerOne = new MockedPowerPolicyListener();
@@ -384,8 +397,18 @@
         mCarPowerManager.removePowerPolicyListener(listenerOne);
         mCarPowerManager.applyPowerPolicy(policyId);
 
-        assertThat(listenerOne.getCurrentPolicyId()).isNull();
-        assertThat(listenerTwo.getCurrentPolicyId()).isEqualTo(policyId);
+        String receivedPolicyId = listenerOne.getCurrentPolicyId();
+        assertWithMessage("Policy ID received after removing listeners")
+                .that(receivedPolicyId == null || receivedPolicyId.equals(initialPolicyId))
+                .isTrue();
+        assertPowerPolicyId(listenerTwo, policyId, "Current policy ID of listenerTwo is not "
+                + policyId);
+    }
+
+    private void applyInitialPolicyForTest(String policyName, String[] enabledComponents,
+            String[] disabledComponents) {
+        mService.definePowerPolicy(policyName, enabledComponents, disabledComponents);
+        mCarPowerManager.applyPowerPolicy(policyName);
     }
 
     @Test
@@ -486,6 +509,12 @@
                 referenceStates).inOrder();
     }
 
+    private static void assertPowerPolicyId(MockedPowerPolicyListener listener, String policyId,
+            String errorMsg) throws Exception {
+        PollingCheck.check(errorMsg, WAIT_TIMEOUT_MS,
+                () -> policyId.equals(listener.getCurrentPolicyId()));
+    }
+
     private static boolean isCompletionAllowed(@CarPowerManager.CarPowerState int state) {
         switch (state) {
             case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE:
diff --git a/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
index 3661834..fdcec3b 100644
--- a/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
@@ -31,6 +31,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -290,6 +291,21 @@
 
         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
                 .isEqualTo(MEDIA_COMPONENT2);
+        verify(mContext, times(2)).startForegroundService(any());
+    }
+
+    @Test
+    public void testActiveSessionListener_StatePlayingNonMediaAppDoesntChangesSource() {
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+        // setup media source info only for MEDIA Component
+        // second one will stay null
+        initMediaService(MEDIA_CLASS);
+
+        // New Media source should be null
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)).isNull();
+        // service start should happen on init but not on media source change
+        verify(mContext, times(1)).startForegroundService(any());
     }
 
     @Test
@@ -303,6 +319,7 @@
                 .isEqualTo(MEDIA_COMPONENT2);
         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
                 .isEqualTo(MEDIA_COMPONENT);
+        verify(mContext, times(2)).startForegroundService(any());
     }
 
     @Test
@@ -316,6 +333,7 @@
                 .isEqualTo(MEDIA_COMPONENT2);
         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
                 .isEqualTo(MEDIA_COMPONENT2);
+        verify(mContext, times(2)).startForegroundService(any());
     }
 
     @Test
@@ -326,6 +344,7 @@
 
         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
                 .isEqualTo(MEDIA_COMPONENT);
+        verify(mContext, times(1)).startForegroundService(any());
     }
 
     private void initMediaService(String... classesToResolve) {
diff --git a/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceHelperTest.java b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceHelperTest.java
new file mode 100644
index 0000000..e71c4cd
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceHelperTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.oem;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Process;
+import android.os.RemoteException;
+
+import com.android.car.R;
+import com.android.car.oem.CarOemProxyServiceHelper.CallbackForDelayedResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeoutException;
+
+public final class CarOemProxyServiceHelperTest extends AbstractExtendedMockitoTestCase {
+    private static final String CALLER_TAG = "test";
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private Resources mResources;
+
+    private CarOemProxyServiceHelper mCarOemProxyServiceHelper;
+
+    @Before
+    public void setUp() throws Exception {
+        when(mContext.getResources()).thenReturn(mResources);
+        mockCallTimeout(/* timeoutMs= */ 5000);
+        mCarOemProxyServiceHelper = new CarOemProxyServiceHelper(mContext);
+    }
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(Process.class);
+    }
+
+    @Test
+    public void testDoBinderTimedCallWithDefault_returnCalculatedValue() throws Exception {
+        assertThat(mCarOemProxyServiceHelper.doBinderTimedCallWithDefaultValue(CALLER_TAG,
+                () -> "value", /* defaultValue= */ "default")).isEqualTo("value");
+    }
+
+    @Test
+    public void testDoBinderTimedCallWithDefault_returnDefaultValue() throws Exception {
+        mockCallTimeout(/* timeoutMs= */ 10);
+        CarOemProxyServiceHelper carOemProxyServiceHelper = new CarOemProxyServiceHelper(mContext);
+
+        assertThat(carOemProxyServiceHelper.doBinderTimedCallWithDefaultValue(CALLER_TAG, () -> {
+            Thread.sleep(1000); // test will not wait for this timeout
+            return "value";
+        }, /* defaultValue= */ "default")).isEqualTo("default");
+
+    }
+
+    @Test
+    public void testDoBinderTimedCall_timeoutException() throws Exception {
+        assertThrows(TimeoutException.class, () -> {
+            mCarOemProxyServiceHelper.doBinderTimedCallWithTimeout(CALLER_TAG, () -> {
+                Thread.sleep(1000); // test will not wait for this timeout
+                return 42;
+            }, /* timeout= */ 10);
+        });
+    }
+
+    @Test
+    public void testDoBinderTimedCall_returnCalculatedValue() throws Exception {
+        assertThat(mCarOemProxyServiceHelper.doBinderTimedCallWithTimeout(CALLER_TAG, () -> 42,
+                /* timeout= */ 1000)).isEqualTo(42);
+    }
+
+    @Test
+    public void testDoBinderCallTimeoutCrash_returnCalculatedValue() throws Exception {
+        assertThat(
+                mCarOemProxyServiceHelper.doBinderCallWithTimeoutCrash(CALLER_TAG, () -> 42).get())
+                        .isEqualTo(42);
+    }
+
+    @Test
+    public void testDoBinderCallTimeoutCrash_withCrash() throws Exception {
+        doAnswer(inv -> {
+            throw new IllegalStateException();
+        }).when(() -> Process.killProcess(anyInt()));
+
+        mockCallTimeout(/* timeoutMs= */ 10);
+        CarOemProxyServiceHelper carOemProxyServiceHelper = new CarOemProxyServiceHelper(mContext);
+
+        assertThrows(IllegalStateException.class, () -> {
+            carOemProxyServiceHelper.doBinderCallWithTimeoutCrash(CALLER_TAG, () -> {
+                Thread.sleep(1000); // test will not wait for this timeout
+                return 42;
+            });
+        });
+    }
+
+    @Test
+    public void testDoBinderCallTimeoutCrash_withExecutionException() throws Exception {
+        assertThat(mCarOemProxyServiceHelper.doBinderCallWithTimeoutCrash(CALLER_TAG, () -> {
+            if (true) {
+                throw new RemoteException();
+            }
+            return 42;
+        }).isEmpty()).isTrue();
+    }
+
+    @Test
+    public void testDoBinderCallWithDefaultValueAndDelayedWaitAndCrash() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        int delayFromOemCallMs  = 100;
+        CallbackForDelayedResult<String> callback = (result) -> latch.countDown();
+
+        Optional<String> result = mCarOemProxyServiceHelper
+                .doBinderCallWithDefaultValueAndDelayedWaitAndCrash(
+                        CALLER_TAG,
+                        () -> {
+                            Thread.sleep(delayFromOemCallMs);
+                            return "result";
+                        },
+                        /* defaultTimeoutMs= */ 10,
+                        callback);
+        assertThat(result.isEmpty()).isTrue();
+        JavaMockitoHelper.await(latch, 1000); //latch would be waiting at max delayFromOemCallMs
+        assertThat(latch.getCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void testCrashCarService() {
+        doAnswer(inv -> {
+            throw new IllegalStateException();
+        }).when(() -> Process.killProcess(anyInt()));
+
+        assertThrows(IllegalStateException.class,
+                () -> mCarOemProxyServiceHelper.crashCarService(""));
+    }
+
+    private void mockCallTimeout(int timeoutMs) {
+        when(mResources.getInteger(R.integer.config_oemCarService_regularCall_timeout_ms))
+                .thenReturn(timeoutMs);
+        when(mResources.getInteger(R.integer.config_oemCarService_crashCall_timeout_ms))
+                .thenReturn(timeoutMs);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceTest.java b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceTest.java
new file mode 100644
index 0000000..5a352a6
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.oem;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.CarVersion;
+import android.car.builtin.content.pm.PackageManagerHelper;
+import android.car.oem.IOemCarAudioFocusService;
+import android.car.oem.IOemCarService;
+import android.car.oem.IOemCarServiceCallback;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+
+import com.android.car.R;
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.concurrent.CountDownLatch;
+
+public final class CarOemProxyServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String COMPONENT_NAME = "android.car.test/unittest";
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private Resources mResources;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private CarOemProxyServiceHelper mCarOemProxyServiceHelper;
+    @Captor
+    ArgumentCaptor<String> mReasonCapture;
+    @Captor
+    ArgumentCaptor<ServiceConnection> mConnectionCapture;
+
+    private final TestOemCarService mTestOemCarService = new TestOemCarService();
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(PackageManagerHelper.class);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        mockCallTimeout(/* timeoutMs= */ 5000);
+    }
+
+    @Test
+    public void testFeatureDisabled() throws Exception {
+        CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+
+        assertThat(carOemProxyService.isOemServiceEnabled()).isFalse();
+    }
+
+    @Test
+    public void testFeatureEnabled() throws Exception {
+        mockOemCarServiceComponent();
+        CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+
+        assertThat(carOemProxyService.isOemServiceEnabled()).isTrue();
+        assertThat(carOemProxyService.getOemServiceName()).isEqualTo(COMPONENT_NAME);
+    }
+
+    @Test
+    public void testOemServiceCalledPriorToInit() throws Exception {
+        mockOemCarServiceComponent();
+        CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+        mockServiceConnection();
+
+        assertThrows(IllegalStateException.class,
+                () -> carOemProxyService.getCarOemAudioFocusService());
+    }
+
+    @Test
+    public void testCarServiceCrash_oemNotConnected() throws Exception {
+        mockCallTimeout(/* timeoutMs= */ 100);
+        mockOemCarServiceComponent();
+        CarOemProxyService carOemProxyService = new CarOemProxyService(mContext,
+                mCarOemProxyServiceHelper, mHandler);
+
+        //call will wait for OEM service connected
+        carOemProxyService.onInitComplete();
+        waitForHandlerThreadToFinish();
+
+        // First it will call crash with "OEM Service not connected", as it is mocked, it would
+        // continue with other calls.
+        verify(mCarOemProxyServiceHelper, times(2)).crashCarService(mReasonCapture.capture());
+        assertThat(mReasonCapture.getAllValues()).containsExactly("OEM Service not connected",
+                "OEM Service not ready");
+    }
+
+    @Test
+    public void testCarServiceCrash_oemNotReady() throws Exception {
+        mockCallTimeout(/* timeoutMs= */ 100);
+        mockOemCarServiceComponent();
+        CarOemProxyService carOemProxyService = new CarOemProxyService(mContext,
+                mCarOemProxyServiceHelper, mHandler);
+        mockServiceConnection();
+
+        //call will wait for OEM service ready
+        carOemProxyService.onInitComplete();
+        waitForHandlerThreadToFinish();
+
+        verify(mCarOemProxyServiceHelper).crashCarService("OEM Service not ready");
+    }
+
+    @Test
+    public void testOemServiceIsReady() throws Exception {
+        mockOemCarServiceComponent();
+        CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+        mockServiceConnection();
+        mockServiceReady();
+        carOemProxyService.onInitComplete();
+
+        eventually(() -> assertWithMessage("Oem Service not ready.")
+                .that(carOemProxyService.isOemServiceReady()).isTrue());
+
+        assertThat(carOemProxyService.getCarOemAudioFocusService()).isNull();
+    }
+
+    @Test
+    public void testCallbackWhenOemServiceIsReady() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        mockOemCarServiceComponent();
+        CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+        mockServiceConnection();
+        mockServiceReady();
+
+        carOemProxyService.registerCallback(() -> latch.countDown());
+        carOemProxyService.onInitComplete();
+
+        JavaMockitoHelper.await(latch, 5000);
+    }
+
+    private void waitForHandlerThreadToFinish() {
+        int timeoutMs = 2000;
+        assertWithMessage("handler not idle in %sms", timeoutMs)
+                .that(mHandler.runWithScissors(() -> {}, timeoutMs)).isTrue();
+    }
+
+    private void mockServiceConnection() {
+        verify(mContext).bindServiceAsUser(any(), mConnectionCapture.capture(), anyInt(), any());
+        ServiceConnection connection = mConnectionCapture.getValue();
+        connection.onServiceConnected(ComponentName.unflattenFromString(COMPONENT_NAME),
+                mTestOemCarService);
+    }
+
+    private void mockOemCarServiceComponent() throws Exception {
+        when(mResources.getString(R.string.config_oemCarService)).thenReturn(COMPONENT_NAME);
+        // make it a valid component.
+        String packageName = ComponentName.unflattenFromString(COMPONENT_NAME).getPackageName();
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        when(mPackageManager.getPackageInfo(packageName, 0)).thenReturn(packageInfo);
+        doReturn(true).when(() -> PackageManagerHelper.isSystemApp(any()));
+        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
+    }
+
+    private void mockCallTimeout(int timeoutMs) {
+        when(mResources.getInteger(R.integer.config_oemCarService_connection_timeout_ms))
+                .thenReturn(timeoutMs);
+        when(mResources.getInteger(R.integer.config_oemCarService_serviceReady_timeout_ms))
+                .thenReturn(timeoutMs);
+    }
+
+    private void mockServiceReady() throws Exception {
+        mTestOemCarService.mockServiceReady();
+    }
+
+    private final class TestOemCarService extends IOemCarService.Stub {
+
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private boolean mMockedServiceReady;
+
+        public void mockServiceReady() {
+            synchronized (mLock) {
+                mMockedServiceReady = true;
+            }
+        }
+
+        @Override
+        public IOemCarAudioFocusService getOemAudioFocusService() {
+            return null;
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        }
+
+        @Override
+        public CarVersion getSupportedCarVersion() {
+            return CarVersion.VERSION_CODES.TIRAMISU_2;
+        }
+
+        @Override
+        public void onCarServiceReady(IOemCarServiceCallback callback) throws RemoteException {
+            boolean mockedServiceReady;
+            synchronized (mLock) {
+                mockedServiceReady = mMockedServiceReady;
+            }
+            if (mockedServiceReady) {
+                callback.sendOemCarServiceReady();
+            }
+        }
+
+        @Override
+        public String getAllStackTraces() {
+            return "";
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
index 8ee9bc0..67a55ed 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.car.Car;
 import android.car.ICarResultReceiver;
@@ -90,7 +91,6 @@
 import java.io.StringWriter;
 import java.time.Duration;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
@@ -109,6 +109,7 @@
     public static final String SYSTEM_POWER_POLICY_ALL_ON = "system_power_policy_all_on";
     public static final String SYSTEM_POWER_POLICY_NO_USER_INTERACTION =
             "system_power_policy_no_user_interaction";
+    public static final String SYSTEM_POWER_POLICY_INITIAL_ON = "system_power_policy_initial_on";
 
     private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface();
     private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface();
@@ -187,6 +188,8 @@
         doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class);
         when(mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs))
                 .thenReturn(900);
+        when(mResources.getInteger(R.integer.config_maxSuspendWaitDuration))
+                .thenReturn(WAKE_UP_DELAY);
         doReturn(true).when(() -> VoiceInteractionHelper.isAvailable());
         doAnswer(invocation -> {
             mVoiceInteractionEnabled = (boolean) invocation.getArguments()[0];
@@ -214,20 +217,12 @@
         assertStateReceived(MockedPowerHalService.SET_WAIT_FOR_VHAL, 0);
     }
 
-    @Test
-    public void testDisplayOn() throws Exception {
-        // start with display off
-        mSystemInterface.setDisplayState(false);
-        mDisplayInterface.waitForDisplayOff(WAIT_TIMEOUT_MS);
-        // Transition to ON state
-        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
 
-        // display should be turned on as it started with off state.
-        mDisplayInterface.waitForDisplayOn(WAIT_TIMEOUT_MS);
-    }
 
     @Test
     public void testShutdown() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
         // Transition to ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -247,6 +242,9 @@
 
     @Test
     public void testCanHibernate() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_ENTRY);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_EXIT);
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
 
@@ -267,6 +265,9 @@
 
     @Test
     public void testHibernateImmediately() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_ENTRY);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_EXIT);
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
 
@@ -287,6 +288,8 @@
 
     @Test
     public void testShutdownImmediately() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
         // Transition to ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -308,6 +311,7 @@
 
     @Test
     public void testSuspend() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
         // Start in the ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -323,6 +327,8 @@
 
     @Test
     public void testShutdownOnSuspend() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
         // Start in the ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -354,6 +360,7 @@
 
     @Test
     public void testShutdownCancel() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
         // Start in the ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -376,6 +383,9 @@
 
     @Test
     public void testSleepImmediately() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
         // Transition to ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -397,6 +407,7 @@
 
     @Test
     public void testShutdownWithProcessing() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 0));
         assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
         mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
@@ -407,6 +418,8 @@
 
     @Test
     public void testSleepEntryAndWakeup() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                 VehicleApPowerStateShutdownParam.CAN_SLEEP));
         assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
@@ -420,6 +433,10 @@
 
     @Test
     public void testShutdownPostponeAfterSuspend() throws Exception {
+        grantPowerPolicyPermission();
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
         // Start in the ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -437,7 +454,9 @@
         mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
         mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
         // Second processing after wakeup
-        assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
+        assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
+        assertThat(mService.getCurrentPowerPolicy().getPolicyId())
+                .isEqualTo(SYSTEM_POWER_POLICY_INITIAL_ON);
 
         mService.setStateForWakeUp();
 
@@ -469,6 +488,8 @@
     @Test
     public void testRegisterListenerWithCompletion() throws Exception {
         grantAdjustShutdownProcessPermission();
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
         SparseBooleanArray stateMapToCompletion = new SparseBooleanArray();
         ICarPowerStateListener listenerRegistered = new ICarPowerStateListener.Stub() {
             @Override
@@ -508,6 +529,8 @@
     @Test
     public void testUnregisterListenerWithCompletion() throws Exception {
         grantAdjustShutdownProcessPermission();
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
         ICarPowerStateListener listenerUnregistered = new ICarPowerStateListener.Stub() {
             @Override
             public void onStateChanged(int state, long expirationTimeMs) {
@@ -531,6 +554,8 @@
     @Test
     public void testShutdownPrepareWithCompletion_timeout() throws Exception {
         grantAdjustShutdownProcessPermission();
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
         // Shortens the timeout for listen completion
         when(mResources.getInteger(R.integer.config_preShutdownPrepareTimeout))
                 .thenReturn(10);
@@ -588,8 +613,9 @@
     @Test
     public void testApplyPowerPolicy() throws Exception {
         grantPowerPolicyPermission();
-        String policyId = "policy_id_audio_on";
-        mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[0]);
+
+        String policyId = "policy_id_audio_off";
+        mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO"});
         MockedPowerPolicyListener listenerToWait = new MockedPowerPolicyListener();
         CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
                 .setComponents(PowerComponent.AUDIO).build();
@@ -597,11 +623,10 @@
 
         mService.applyPowerPolicy(policyId);
 
-        CarPowerPolicy policy = mService.getCurrentPowerPolicy();
-        assertThat(policy).isNotNull();
-        assertThat(policy.getPolicyId()).isEqualTo(policyId);
+        waitForPowerPolicy(policyId);
         assertThat(mPowerComponentHandler.getAccumulatedPolicy().getPolicyId()).isEqualTo(policyId);
-        assertThat(listenerToWait.getCurrentPowerPolicy()).isNotNull();
+        PollingCheck.check("Current power policy of listener is null", WAIT_TIMEOUT_LONG_MS,
+                () -> listenerToWait.getCurrentPowerPolicy() != null);
         assertThat(mPowerPolicyDaemon.getLastNotifiedPolicyId()).isEqualTo(policyId);
     }
 
@@ -678,11 +703,12 @@
     @Test
     public void testAddPowerPolicyListener() throws Exception {
         grantPowerPolicyPermission();
-        String policyId = "policy_id_enable_audio_wifi";
-        mService.definePowerPolicy(policyId, new String[]{"AUDIO", "WIFI"}, new String[]{});
+
+        String policyIdEnableAudioWifi = "policy_id_enable_audio_wifi";
         MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
         MockedPowerPolicyListener listenerWifi = new MockedPowerPolicyListener();
         MockedPowerPolicyListener listenerLocation = new MockedPowerPolicyListener();
+
         CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
                 .setComponents(PowerComponent.AUDIO).build();
         CarPowerPolicyFilter filterWifi = new CarPowerPolicyFilter.Builder()
@@ -692,28 +718,53 @@
 
         mService.addPowerPolicyListener(filterAudio, listenerAudio);
         mService.addPowerPolicyListener(filterWifi, listenerWifi);
-        mService.applyPowerPolicy(policyId);
 
-        assertThat(listenerAudio.getCurrentPowerPolicy()).isNotNull();
-        assertThat(listenerAudio.getCurrentPowerPolicy().getPolicyId()).isEqualTo(policyId);
-        assertThat(listenerWifi.getCurrentPowerPolicy()).isNotNull();
-        assertThat(listenerWifi.getCurrentPowerPolicy().getPolicyId()).isEqualTo(policyId);
+        String policyIdAllOff = "all_off";
+        mService.definePowerPolicy(policyIdAllOff, new String[]{},
+                new String[]{"AUDIO", "WIFI", "DISPLAY"});
+        mService.applyPowerPolicy(policyIdAllOff);
+        waitForPowerPolicy(policyIdAllOff);
+
+        assertThat(mService.getCurrentPowerPolicy().isComponentEnabled(
+                PowerComponent.AUDIO)).isFalse();
+        assertThat(
+                mService.getCurrentPowerPolicy().isComponentEnabled(PowerComponent.WIFI)).isFalse();
+        assertThat(mService.getCurrentPowerPolicy().isComponentEnabled(
+                PowerComponent.DISPLAY)).isFalse();
+
+        mService.definePowerPolicy(policyIdEnableAudioWifi, new String[]{"AUDIO", "WIFI"},
+                new String[]{});
+        mService.applyPowerPolicy(policyIdEnableAudioWifi);
+
+        waitForPolicyId(listenerAudio, policyIdEnableAudioWifi,
+                "Current power policy of listenerAudio is not " + policyIdEnableAudioWifi);
+        assertThat(
+                mService.getCurrentPowerPolicy().isComponentEnabled(PowerComponent.AUDIO)).isTrue();
+
+        waitForPolicyId(listenerWifi, policyIdEnableAudioWifi,
+                "Current power policy of listenerWifi is not " + policyIdEnableAudioWifi);
         assertThat(listenerLocation.getCurrentPowerPolicy()).isNull();
     }
 
     @Test
     public void testRemovePowerPolicyListener() throws Exception {
         grantPowerPolicyPermission();
-        String policyId = "policy_id_enable_audio_disable_wifi";
-        mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"});
+
+        String policyId = "policy_id_disable_audio";
+        mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO", "WIFI"});
         MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
+        MockedPowerPolicyListener referenceListenerAudio = new MockedPowerPolicyListener();
+
         CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
                 .setComponents(PowerComponent.AUDIO).build();
 
         mService.addPowerPolicyListener(filterAudio, listenerAudio);
+        mService.addPowerPolicyListener(filterAudio, referenceListenerAudio);
         mService.removePowerPolicyListener(listenerAudio);
         mService.applyPowerPolicy(policyId);
 
+        waitForPolicyId(referenceListenerAudio, policyId,
+                "Current power policy of referenceListenerAudio is not " + policyId);
         assertThat(listenerAudio.getCurrentPowerPolicy()).isNull();
     }
 
@@ -744,6 +795,10 @@
     @Test
     public void testPowerPolicyAfterShutdownCancel() throws Exception {
         grantPowerPolicyPermission();
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
+        assertThat(mService.getCurrentPowerPolicy().getPolicyId())
+                .isEqualTo(SYSTEM_POWER_POLICY_INITIAL_ON);
         mPowerHal.setCurrentPowerState(
                 new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                         VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
@@ -754,22 +809,44 @@
                 new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, /* param= */ 0));
         assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_CANCELLED);
 
-        mPowerSignalListener.waitFor(PowerHalService.SET_WAIT_FOR_VHAL, WAIT_TIMEOUT_MS);
+        waitForPowerPolicy(SYSTEM_POWER_POLICY_INITIAL_ON);
 
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, /* param= */ 0));
         assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_ON);
 
         mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
 
-        assertThat(mService.getCurrentPowerPolicy().getPolicyId())
-                .isEqualTo(SYSTEM_POWER_POLICY_ALL_ON);
+        waitForPowerPolicy(SYSTEM_POWER_POLICY_ALL_ON);
+    }
+
+    @Test
+    public void testSuspendFailure() throws Exception {
+        suspendWithFailure(/* nextPowerState= */ null);
+        mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
+    }
+
+    @Test
+    public void testSuspendFailureWithForbiddenTransition() throws Exception {
+        suspendWithFailure(/* nextPowerState= */ VehicleApPowerStateReq.ON);
+        mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
+    }
+
+    @Test
+    public void testSuspendFailureWithAllowedTransition() throws Exception {
+        mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_CANCELLED);
+        suspendWithFailure(/* nextPowerState= */ VehicleApPowerStateReq.CANCEL_SHUTDOWN);
+        mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_CANCELLED, WAIT_TIMEOUT_MS);
     }
 
     @Test
     public void testPowerPolicyOnSilentBoot() throws Exception {
         grantPowerPolicyPermission();
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
         mService.setSilentMode(SilentModeHandler.SILENT_MODE_FORCED_SILENT);
 
+        assertThat(mService.getCurrentPowerPolicy().getPolicyId())
+                .isEqualTo(SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
+
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, /* param= */ 0));
         assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_ON);
 
@@ -784,7 +861,35 @@
                 .isEqualTo(SYSTEM_POWER_POLICY_ALL_ON);
     }
 
+    private void suspendWithFailure(Integer nextPowerState) throws Exception {
+        mSystemStateInterface.setSleepEntryResult(false);
+        mSystemStateInterface.setSimulateSleep(false);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+
+        // Transition to ON state
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+        mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
+
+        mPowerHal.setCurrentPowerState(
+                new PowerState(
+                        VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                        VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY));
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+        assertThat(mService.garageModeShouldExitImmediately()).isTrue();
+
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
+
+        mSystemStateInterface.waitForDeepSleepEntry(WAIT_TIMEOUT_MS);
+
+        if (nextPowerState != null) {
+            mPowerHal.setCurrentPowerState(new PowerState(nextPowerState, 0));
+        }
+    }
+
     private void suspendAndResume() throws Exception {
+        grantPowerPolicyPermission();
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+        mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
         Log.d(TAG, "suspend()");
         mVoiceInteractionEnabled = true;
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
@@ -803,8 +908,11 @@
         assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
         mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
         mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
+
         // second processing after wakeup
-        assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
+        assertThat(mService.getCurrentPowerPolicy().getPolicyId()).isEqualTo(
+                SYSTEM_POWER_POLICY_INITIAL_ON);
+        assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
 
         mFileHwStateMonitoring.write(NONSILENT_STRING); // Wake non-silently
         mService.setStateForWakeUp();
@@ -830,7 +938,7 @@
         mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
         // Since we just woke up from shutdown, wake up time will be 0
         assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
-        assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
+        assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
     }
 
     private void assertStateReceived(int expectedState, int expectedParam) throws Exception {
@@ -880,6 +988,23 @@
                 });
     }
 
+    private void waitForPowerPolicy(String policyId) throws Exception {
+        PollingCheck.check("Policy id is not " + policyId, WAIT_TIMEOUT_LONG_MS,
+                () -> {
+                    CarPowerPolicy policy = mService.getCurrentPowerPolicy();
+                    return policy != null && policyId.equals(policy.getPolicyId());
+                });
+    }
+
+    private static void waitForPolicyId(MockedPowerPolicyListener listener, String policyId,
+            String errorMsg) throws Exception {
+        PollingCheck.check(errorMsg, WAIT_TIMEOUT_LONG_MS,
+                () -> {
+                    CarPowerPolicy policy = listener.getCurrentPowerPolicy();
+                    return policy != null && policyId.equals(policy.getPolicyId());
+                });
+    }
+
     private static void waitForSemaphore(Semaphore semaphore, long timeoutMs)
             throws InterruptedException {
         if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
@@ -975,6 +1100,10 @@
         private final Semaphore mShutdownWait = new Semaphore(0);
         private final Semaphore mSleepWait = new Semaphore(0);
         private final Semaphore mSleepExitWait = new Semaphore(0);
+
+        private boolean mSleepEntryResult = true;
+        private boolean mSimulateSleep = true;
+
         private boolean mWakeupCausedByTimer = false;
 
         @Override
@@ -988,7 +1117,12 @@
 
         @Override
         public boolean enterDeepSleep() {
-            return simulateSleep();
+            if (mSimulateSleep) {
+                return simulateSleep();
+            }
+
+            mSleepWait.release();
+            return mSleepEntryResult;
         }
 
         @Override
@@ -999,10 +1133,10 @@
         private boolean simulateSleep() {
             mSleepWait.release();
             try {
-                mSleepExitWait.acquire();
+                mSleepExitWait.tryAcquire(WAIT_TIMEOUT_MS , TimeUnit.MILLISECONDS);
             } catch (InterruptedException e) {
             }
-            return true;
+            return mSleepEntryResult;
         }
 
         public void waitForSleepEntryAndWakeup(long timeoutMs) throws Exception {
@@ -1032,6 +1166,18 @@
         public boolean isSystemSupportingHibernation() {
             return true;
         }
+
+        public void setSleepEntryResult(boolean sleepEntryResult) {
+            mSleepEntryResult = sleepEntryResult;
+        }
+
+        public void setSimulateSleep(boolean simulateSleep) {
+            mSimulateSleep = simulateSleep;
+        }
+
+        public void waitForDeepSleepEntry(long waitTimeoutMs) throws InterruptedException {
+            waitForSemaphore(mSleepWait, waitTimeoutMs);
+        }
     }
 
     private static final class MockWakeLockInterface implements WakeLockInterface {
@@ -1078,16 +1224,16 @@
 
         private PowerSignalListener() {
             mSemaphores = new SparseArray<>();
-            mSemaphores.put(PowerHalService.SET_ON, new Semaphore(0));
-            mSemaphores.put(PowerHalService.SET_SHUTDOWN_START, new Semaphore(0));
-            mSemaphores.put(PowerHalService.SET_DEEP_SLEEP_ENTRY, new Semaphore(0));
-            mSemaphores.put(PowerHalService.SET_DEEP_SLEEP_EXIT, new Semaphore(0));
+        }
+
+        public void addEventListener(int eventId) {
+            mSemaphores.put(eventId, new Semaphore(0));
         }
 
         public void waitFor(int signal, long timeoutMs) throws Exception {
             Semaphore semaphore = mSemaphores.get(signal);
             if (semaphore == null) {
-                return;
+                throw new IllegalArgumentException("no semaphore registered for event = " + signal);
             }
             waitForSemaphore(semaphore, timeoutMs);
         }
@@ -1103,7 +1249,7 @@
     }
 
     static final class FakeCarPowerPolicyDaemon extends ICarPowerPolicySystemNotification.Stub {
-        private String mLastNofitiedPolicyId;
+        private String mLastNotifiedPolicyId;
         private String mLastDefinedPolicyId;
 
         @Override
@@ -1114,7 +1260,7 @@
 
         @Override
         public void notifyPowerPolicyChange(String policyId, boolean force) {
-            mLastNofitiedPolicyId = policyId;
+            mLastNotifiedPolicyId = policyId;
         }
 
         @Override
@@ -1124,7 +1270,7 @@
         }
 
         public String getLastNotifiedPolicyId() {
-            return mLastNofitiedPolicyId;
+            return mLastNotifiedPolicyId;
         }
 
         public String getLastDefinedPolicyId() {
@@ -1143,24 +1289,22 @@
     }
 
     private final class MockedPowerPolicyListener extends ICarPowerPolicyListener.Stub {
-        private static final int NOTIFICATION_TIMEOUT_SEC = 5;
-
-        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private final Object mLock = new Object();
         private CarPowerPolicy mCurrentPowerPolicy;
 
         @Override
         public void onPolicyChanged(CarPowerPolicy appliedPolicy,
                 CarPowerPolicy accumulatedPolicy) {
-            mCurrentPowerPolicy = accumulatedPolicy;
-            mLatch.countDown();
+            synchronized (mLock) {
+                mCurrentPowerPolicy = accumulatedPolicy;
+            }
         }
 
+        @Nullable
         public CarPowerPolicy getCurrentPowerPolicy() throws Exception {
-            if (mLatch.await(NOTIFICATION_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            synchronized (mLock) {
                 return mCurrentPowerPolicy;
             }
-
-            return null;
         }
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
index 1a4a9a4..f3b23cc 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
@@ -210,6 +210,21 @@
     }
 
     @Test
+    public void testValidXmlWithDefaultPolicyGroup() throws Exception {
+        try (InputStream inputStream = mResources.openRawResource(
+                R.raw.valid_power_policy_default_policy_group)) {
+            mPolicyReader.readPowerPolicyFromXml(inputStream);
+        }
+
+        assertThat(mPolicyReader.getDefaultPowerPolicyGroup()).isEqualTo("mixed_policy_group");
+    }
+
+    @Test
+    public void testInvalidXml_wrongDefaultPolicyGroupId() throws Exception {
+        assertInvalidXml(R.raw.invalid_system_power_policy_incorrect_default_power_policy_group_id);
+    }
+
+    @Test
     public void testDefaultPolicies() throws Exception {
         assertDefaultPolicies();
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
index 69f62160..c898575 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
@@ -51,6 +51,7 @@
 import com.android.car.telemetry.ResultStore;
 import com.android.car.telemetry.publisher.AbstractPublisher;
 import com.android.car.telemetry.publisher.PublisherFactory;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
 
@@ -67,8 +68,10 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.PriorityBlockingQueue;
@@ -458,6 +461,24 @@
     }
 
     @Test
+    public void testScheduleNextTask_withBundleList_shouldPassData() throws Exception {
+        List<PersistableBundle> bundles = new ArrayList<>();
+        bundles.add(new PersistableBundle());
+        bundles.add(new PersistableBundle());
+        ScriptExecutionTask highPriorityTask = new ScriptExecutionTask(
+                new DataSubscriber(mDataBroker, METRICS_CONFIG_FOO, SUBSCRIBER_FOO),
+                bundles,
+                SystemClock.elapsedRealtime(),
+                TelemetryProto.Publisher.PublisherCase.STATS.getNumber());
+        mDataBroker.getTaskQueue().add(highPriorityTask);
+
+        mDataBroker.scheduleNextTask();
+
+        waitForTelemetryThreadToFinish();
+        assertThat(mFakeScriptExecutor.getInvokeScriptForBundleListCount()).isEqualTo(1);
+    }
+
+    @Test
     public void testScheduleNextTask_bindScriptExecutorFailedOnce_shouldRebind()
             throws Exception {
         Mockito.reset(mMockContext);
@@ -698,6 +719,7 @@
         private IScriptExecutorListener mListener;
         private int mInvokeScriptCount = 0;
         private int mInvokeScriptForLargeInputCount = 0;
+        private int mInvokeScriptForBundleListCount = 0;
         private int mFailApi = 0;
         private PersistableBundle mSavedState = null;
 
@@ -745,6 +767,19 @@
         }
 
         @Override
+        public void invokeScriptForBundleList(String scriptBody, String functionName,
+                BundleList bundleList, PersistableBundle savedState,
+                IScriptExecutorListener listener) throws RemoteException {
+            mInvokeScriptForBundleListCount++;
+            mSavedState = savedState;
+            mListener = listener;
+            if (mFailApi > 0) {
+                mFailApi--;
+                throw new RemoteException("Simulated failure");
+            }
+        }
+
+        @Override
         public IBinder asBinder() {
             return null;
         }
@@ -800,6 +835,11 @@
             return mInvokeScriptForLargeInputCount;
         }
 
+        /** Returns number of times invokeScriptForBundleList() was called. */
+        public int getInvokeScriptForBundleListCount() {
+            return mInvokeScriptForBundleListCount;
+        }
+
         /** Returns the interim data passed in invokeScript(). */
         public PersistableBundle getSavedState() {
             return mSavedState;
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
index 503cbea..cadfbb4 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
@@ -76,11 +76,11 @@
     private static final SessionAnnotation SESSION_ANNOTATION_BEGIN_1 =
             new SessionAnnotation(1, SessionController.STATE_ENTER_DRIVING_SESSION, 0, 0, "");
     private static final String[] SESSION_ANNOTATION_KEYS =
-            {SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID,
-                    SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON,
-                    SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_STATE,
-                    SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS,
-                    SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS};
+            {Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID,
+                    Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON,
+                    Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE,
+                    Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS,
+                    Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS};
 
     private final FakeHandlerWrapper mFakeHandlerWrapper =
             new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.IMMEDIATE);
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
index 99e42a8..e10dd1a 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
@@ -195,8 +195,8 @@
             return false;
         }
 
-        return savedResult.containsKey(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)
-                && savedResult.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)
+        return savedResult.containsKey(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)
+                && savedResult.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)
                 == expectedSessionId;
     }
 
@@ -296,13 +296,20 @@
         assertThat(mDataSubscriberCell.mPushedData).hasSize(1);
         PersistableBundle result = mDataSubscriberCell.get(0);
         // Matches only "UID_1/TAG_1" and "UID_1/TAG_NONE" above.
-        assertThat(result.getLong("startMillis")).isLessThan(mNow);
-        assertThat(result.getLong("endMillis")).isGreaterThan(result.getLong("startMillis"));
-        assertThat(result.getInt("size")).isEqualTo(2);
-        assertThat(result.getIntArray("uid")).asList().containsExactly(UID_1, UID_1);
-        assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1, TAG_NONE);
-        assertThat(result.getLongArray("rxBytes")).asList().containsExactly(2500L, 2502L);
-        assertThat(result.getLongArray("txBytes")).asList().containsExactly(3500L, 3502L);
+        assertThat(result.getLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS))
+                .isLessThan(mNow);
+        assertThat(result.getLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS))
+                .isGreaterThan(result.getLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS));
+        assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+                .isEqualTo(2);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID)).asList()
+                .containsExactly(UID_1, UID_1);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG)).asList()
+                .containsExactly(TAG_1, TAG_NONE);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES)).asList()
+                .containsExactly(2500L, 2502L);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES)).asList()
+                .containsExactly(3500L, 3502L);
     }
 
     @Test
@@ -327,12 +334,18 @@
         assertThat(mDataSubscriberWifiOemManaged.mPushedData).hasSize(1);
         PersistableBundle result = mDataSubscriberWifiOemManaged.get(0);
 
-        assertThat(result.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(1);
-        assertThat(result.getInt("size")).isEqualTo(2);
-        assertThat(result.getIntArray("uid")).asList().containsExactly(UID_2, UID_3);
-        assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_NONE, TAG_2);
-        assertThat(result.getLongArray("rxBytes")).asList().containsExactly(100L, 6L);
-        assertThat(result.getLongArray("txBytes")).asList().containsExactly(200L, 7L);
+        assertThat(result.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID))
+                .isEqualTo(1);
+        assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+                .isEqualTo(2);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+                .asList().containsExactly(UID_2, UID_3);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+                .asList().containsExactly(TAG_NONE, TAG_2);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+                .asList().containsExactly(100L, 6L);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+                .asList().containsExactly(200L, 7L);
     }
 
     @Test
@@ -356,13 +369,18 @@
 
         assertThat(mDataSubscriberWifi.mPushedData).hasSize(1);
         PersistableBundle result = mDataSubscriberWifi.get(0);
-        assertThat(result.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(1);
+        assertThat(result.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(1);
         // Matches only UID_1.
-        assertThat(result.getInt("size")).isEqualTo(1);
-        assertThat(result.getIntArray("uid")).asList().containsExactly(UID_1);
-        assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
-        assertThat(result.getLongArray("txBytes")).asList().containsExactly(30L);
-        assertThat(result.getLongArray("rxBytes")).asList().containsExactly(30L);
+        assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+                .isEqualTo(1);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+                .asList().containsExactly(UID_1);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+                .asList().containsExactly(TAG_1);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+                .asList().containsExactly(30L);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+                .asList().containsExactly(30L);
     }
 
     @Test
@@ -392,11 +410,16 @@
         PersistableBundle result = mDataSubscriberWifi.get(0);
         // Only UID_1 and UID_2 are fetched, because other stats are outside
         // of the time range.
-        assertThat(result.getInt("size")).isEqualTo(2);
-        assertThat(result.getIntArray("uid")).asList().containsExactly(UID_1, UID_2);
-        assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1, TAG_1);
-        assertThat(result.getLongArray("txBytes")).asList().containsExactly(10L, 10L);
-        assertThat(result.getLongArray("rxBytes")).asList().containsExactly(10L, 10L);
+        assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+                .isEqualTo(2);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+                .asList().containsExactly(UID_1, UID_2);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+                .asList().containsExactly(TAG_1, TAG_1);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+                .asList().containsExactly(10L, 10L);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+                .asList().containsExactly(10L, 10L);
     }
 
     @Test
@@ -441,11 +464,16 @@
 
         assertThat(mDataSubscriberWifi.mPushedData).hasSize(1);
         PersistableBundle result = mDataSubscriberWifi.get(0);
-        assertThat(result.getInt("size")).isEqualTo(1);
-        assertThat(result.getIntArray("uid")).asList().containsExactly(UID_4);
-        assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
-        assertThat(result.getLongArray("txBytes")).asList().containsExactly(100L - 12L);
-        assertThat(result.getLongArray("rxBytes")).asList().containsExactly(100L - 12L);
+        assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+                .isEqualTo(1);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+                .asList().containsExactly(UID_4);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+                .asList().containsExactly(TAG_1);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+                .asList().containsExactly(100L - 12L);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+                .asList().containsExactly(100L - 12L);
     }
 
     @Test
@@ -467,11 +495,15 @@
 
         assertThat(mDataSubscriberWifi.mPushedData).hasSize(1);
         PersistableBundle result = mDataSubscriberWifi.get(0);
-        assertThat(result.getInt("size")).isEqualTo(1);
-        assertThat(result.getIntArray("uid")).asList().containsExactly(UID_4);
-        assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
+        assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+                .isEqualTo(1);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+                .asList().containsExactly(UID_4);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+                .asList().containsExactly(TAG_1);
         // It's 200, because it subtracts previous pull 12 from (200 + 12).
-        assertThat(result.getLongArray("txBytes")).asList().containsExactly(200L);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+                .asList().containsExactly(200L);
 
         // ==== 2nd pull.
         mFakeManager.addWifiStats(UID_4, TAG_1, 1000, 1000, OEM_MANAGED_NO, mNow);
@@ -484,11 +516,30 @@
 
         assertThat(mDataSubscriberWifi.mPushedData).hasSize(2);
         result = mDataSubscriberWifi.get(1);
-        assertThat(result.getInt("size")).isEqualTo(1);
-        assertThat(result.getIntArray("uid")).asList().containsExactly(UID_4);
-        assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
+        assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+                .isEqualTo(1);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+                .asList().containsExactly(UID_4);
+        assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+                .asList().containsExactly(TAG_1);
         // It's 1000, because it subtracts previous pull (200 + 12) from (200 + 12 + 1000).
-        assertThat(result.getLongArray("txBytes")).asList().containsExactly(1000L);
+        assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+                .asList().containsExactly(1000L);
+    }
+
+    @Test
+    public void testWhenQueryThrowsNullPointerExceptionIsCaught() {
+        mFakeManager.setSimulateFailedQuery(true);
+        mSessionControllerCallbackArgumentCaptor.getValue().onSessionStateChanged(
+                SESSION_ANNOTATION_BEGIN_1);
+
+        // querySummary gets called for each QueryParam combination, but throws
+        // NullPointerException each time, which is caught
+        assertThat(mFakeManager.getMethodCallCount("querySummary"))
+                .isEqualTo(BASELINE_PULL_COUNT);
+        // queryTaggedSummary not reached because of previous NullPointerException in querySummary
+        assertThat(mFakeManager.getMethodCallCount("queryTaggedSummary"))
+                .isEqualTo(0);
     }
 
     private static class FakeDataSubscriber extends DataSubscriber {
@@ -533,6 +584,8 @@
         private final ArrayList<FakeNetworkStats.CustomBucket> mBuckets = new ArrayList<>();
         private final HashMap<String, Integer> mMethodCallCount = new HashMap<>();
 
+        private boolean mSimulateFailedQuery = false;
+
         private FakeNetworkStatsManager() {
             super(/* networkStatsManager= */ null);
         }
@@ -587,10 +640,17 @@
             return mMethodCallCount.getOrDefault(name, 0);
         }
 
+        public void setSimulateFailedQuery(boolean simulateFailedQuery) {
+            mSimulateFailedQuery = simulateFailedQuery;
+        }
+
         @Override
         @NonNull
         public NetworkStatsWrapper querySummary(NetworkTemplate template, long start, long end) {
             increaseMethodCall("querySummary", 1);
+            if (mSimulateFailedQuery) {
+                throw new NullPointerException();
+            }
             return commonQuerySummary(false, template, start, end);
         }
 
@@ -599,6 +659,9 @@
         public NetworkStatsWrapper queryTaggedSummary(
                 NetworkTemplate template, long start, long end) {
             increaseMethodCall("queryTaggedSummary", 1);
+            if (mSimulateFailedQuery) {
+                throw new NullPointerException();
+            }
             return commonQuerySummary(true, template, start, end);
         }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
index 9d26b58..0ccb99c 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
@@ -18,7 +18,6 @@
 
 import static com.android.car.telemetry.publisher.MemoryPublisher.BUNDLE_KEY_COLLECT_INDEFINITELY;
 import static com.android.car.telemetry.publisher.MemoryPublisher.BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH;
-import static com.android.car.telemetry.publisher.MemoryPublisher.DATA_BUNDLE_KEY_MEMINFO;
 import static com.android.car.telemetry.publisher.MemoryPublisher.THROTTLE_MILLIS;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -32,20 +31,27 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.ActivityManager;
 import android.car.telemetry.TelemetryProto;
+import android.content.Context;
+import android.os.Debug;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
 
 import com.android.car.telemetry.ResultStore;
 import com.android.car.telemetry.databroker.DataSubscriber;
 import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
 import com.android.car.telemetry.sessioncontroller.SessionController;
 import com.android.car.test.FakeHandlerWrapper;
+import com.android.internal.util.test.FakeSettingsProvider;
 
 import com.google.common.collect.Range;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -60,6 +66,9 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
 
 @RunWith(MockitoJUnitRunner.class)
 public class MemoryPublisherTest {
@@ -70,13 +79,20 @@
             .append("MemAvailable:    5312884 kB\n")
             .append("Buffers:          224380 kB\n")
             .toString();
+    private static final TelemetryProto.MemoryPublisher BASE_MEMORY_PUBLISHER =
+            TelemetryProto.MemoryPublisher.newBuilder()
+                    .setReadIntervalSec(TEN_SECONDS)
+                    .setMaxSnapshots(2)
+                    .setMaxPendingTasks(10)
+                    .build();
     private static final TelemetryProto.Publisher MEMORY_PUBLISHER_TEN_SEC =
             TelemetryProto.Publisher.newBuilder()
+                    .setMemory(BASE_MEMORY_PUBLISHER)
+                    .build();
+    private static final TelemetryProto.Publisher MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC =
+            TelemetryProto.Publisher.newBuilder()
                     .setMemory(
-                            TelemetryProto.MemoryPublisher.newBuilder()
-                                    .setReadIntervalSec(TEN_SECONDS)
-                                    .setMaxSnapshots(2)
-                                    .setMaxPendingTasks(10))
+                            BASE_MEMORY_PUBLISHER.toBuilder().addPackageNames("com.android.car"))
                     .build();
     private static final TelemetryProto.Subscriber SUBSCRIBER_TEN_SEC =
             TelemetryProto.Subscriber.newBuilder()
@@ -102,6 +118,10 @@
     @Captor
     private ArgumentCaptor<SessionController.SessionControllerCallback> mSessionCallbackCaptor;
     @Mock
+    private ActivityManager mMockActivityManager;
+    @Mock
+    private Context mMockContext;
+    @Mock
     private DataSubscriber mMockDataSubscriber;
     @Mock
     private ResultStore mMockResultStore;
@@ -119,18 +139,41 @@
         when(mMockDataSubscriber.getSubscriber()).thenReturn(SUBSCRIBER_TEN_SEC);
         when(mMockDataSubscriber.getMetricsConfig()).thenReturn(METRICS_CONFIG);
         when(mMockDataSubscriber.getPublisherParam()).thenReturn(SUBSCRIBER_TEN_SEC.getPublisher());
+        // set up mocks for reading process meminfo
+        when(mMockContext.getSystemService(ActivityManager.class)).thenReturn(mMockActivityManager);
+        when(mMockActivityManager.getRunningAppProcesses()).thenReturn(List.of(
+                new ActivityManager.RunningAppProcessInfo(
+                        "com.android.car", 123, null),
+                new ActivityManager.RunningAppProcessInfo(
+                        "com.android.car.scriptexecutor", 456, null)));
+        when(mMockActivityManager.getProcessMemoryInfo(any())).thenAnswer(i -> {
+            int length = ((int[]) i.getArguments()[0]).length;
+            Debug.MemoryInfo[] mis = new Debug.MemoryInfo[length];
+            Debug.MemoryInfo mi = new Debug.MemoryInfo();
+            Arrays.fill(mis, mi);
+            return mis;
+        });
+        MockContentResolver mockContentResolver = new MockContentResolver();
+        mockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        when(mMockContext.getContentResolver()).thenReturn(mockContentResolver);
 
         // create MemoryPublisher
         mPublisher = createPublisher(mTempFile.toPath());
         verify(mMockSessionController).registerCallback(mSessionCallbackCaptor.capture());
     }
 
+    @After
+    public void tearDown() {
+        mPublisher.removeAllDataSubscribers();
+    }
+
     /**
      * Emulates a restart by creating a new MemoryPublisher. StatsManager and PersistableBundle
      * stays the same.
      */
     private MemoryPublisher createPublisher(Path meminfoPath) {
         return new MemoryPublisher(
+                mMockContext,
                 mFakePublisherListener,
                 mFakeHandlerWrapper.getMockHandler(),
                 mMockResultStore,
@@ -139,16 +182,141 @@
     }
 
     @Test
-    public void testAddDataSubscriber_pullsMeminfo() {
+    public void testAddDataSubscriber_whenNoPackageName_pullsDeviceMeminfo() {
         mPublisher.addDataSubscriber(mMockDataSubscriber);
 
         assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
-        verify(mMockDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getString(DATA_BUNDLE_KEY_MEMINFO))
+        verify(mMockDataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+        assertThat(mBundleCaptor.getValue().keySet().stream().collect(Collectors.toList()))
+                .containsExactly(
+                        Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+                        Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
+        assertThat(mBundleCaptor.getValue().getString(Constants.MEMORY_BUNDLE_KEY_MEMINFO))
                 .isEqualTo(FAKE_MEMINFO);
     }
 
     @Test
+    public void testAddDataSubscriber_whenMatchingPackageName_pullsDeviceAndProcessMeminfo() {
+        DataSubscriber dataSubscriber = mock(DataSubscriber.class);
+        when(dataSubscriber.getSubscriber()).thenReturn(
+                SUBSCRIBER_TEN_SEC.toBuilder()
+                        .setPublisher(MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC).build());
+        when(dataSubscriber.getPublisherParam()).thenReturn(
+                MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC);
+
+        mPublisher.addDataSubscriber(dataSubscriber);
+
+        assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
+        verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+        PersistableBundle bundle = mBundleCaptor.getValue();
+        assertThat(bundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+                Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+                Constants.MEMORY_BUNDLE_KEY_TIMESTAMP,
+                "com.android.car:0:com.android.car");
+        PersistableBundle processBundle = bundle.getPersistableBundle(
+                "com.android.car:0:com.android.car");
+        assertThat(processBundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+                "mem.summary.java-heap",
+                "mem.summary.total-pss",
+                "mem.summary.private-other",
+                "mem.summary.native-heap",
+                "mem.summary.stack",
+                "mem.summary.system",
+                "mem.summary.code",
+                "mem.summary.graphics",
+                "mem.summary.total-swap");
+    }
+
+    @Test
+    public void testAddDataSubscriber_multipleMatchingPackageName_pullsDeviceAndProcessMeminfo() {
+        // setup processes
+        ActivityManager.RunningAppProcessInfo process1 = new ActivityManager.RunningAppProcessInfo(
+                "com.android.car", 111, null);
+        process1.uid = 12345;
+        ActivityManager.RunningAppProcessInfo process2 = new ActivityManager.RunningAppProcessInfo(
+                "com.android.car", 222, null);
+        process2.uid = 67890;
+        when(mMockActivityManager.getRunningAppProcesses()).thenReturn(List.of(process1, process2));
+        // set up subscribers that listen for process memory
+        DataSubscriber dataSubscriber = mock(DataSubscriber.class);
+        when(dataSubscriber.getSubscriber()).thenReturn(
+                SUBSCRIBER_TEN_SEC.toBuilder()
+                        .setPublisher(MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC).build());
+        when(dataSubscriber.getPublisherParam()).thenReturn(
+                MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC);
+
+        mPublisher.addDataSubscriber(dataSubscriber);
+
+        assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
+        verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+        PersistableBundle bundle = mBundleCaptor.getValue();
+        assertThat(bundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+                Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+                Constants.MEMORY_BUNDLE_KEY_TIMESTAMP,
+                "com.android.car:12345:com.android.car",
+                "com.android.car:67890:com.android.car");
+        PersistableBundle processBundle1 = bundle.getPersistableBundle(
+                "com.android.car:12345:com.android.car");
+        PersistableBundle processBundle2 = bundle.getPersistableBundle(
+                "com.android.car:67890:com.android.car");
+        assertThat(processBundle1.keySet().stream().collect(Collectors.toList())).containsExactly(
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+                "mem.summary.java-heap",
+                "mem.summary.total-pss",
+                "mem.summary.private-other",
+                "mem.summary.native-heap",
+                "mem.summary.stack",
+                "mem.summary.system",
+                "mem.summary.code",
+                "mem.summary.graphics",
+                "mem.summary.total-swap");
+        assertThat(processBundle2.keySet().stream().collect(Collectors.toList())).containsExactly(
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+                Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+                "mem.summary.java-heap",
+                "mem.summary.total-pss",
+                "mem.summary.private-other",
+                "mem.summary.native-heap",
+                "mem.summary.stack",
+                "mem.summary.system",
+                "mem.summary.code",
+                "mem.summary.graphics",
+                "mem.summary.total-swap");
+    }
+
+    @Test
+    public void testAddDataSubscriber_whenPackageNameNotFound_doesNotPullProcessMeminfo() {
+        String packageName = "com.example.does.not.exist";
+        DataSubscriber dataSubscriber = mock(DataSubscriber.class);
+        TelemetryProto.Publisher publisher = TelemetryProto.Publisher.newBuilder().setMemory(
+                BASE_MEMORY_PUBLISHER.toBuilder().addPackageNames(packageName)).build();
+        when(dataSubscriber.getSubscriber()).thenReturn(
+                SUBSCRIBER_TEN_SEC.toBuilder().setPublisher(publisher).build());
+        when(dataSubscriber.getPublisherParam()).thenReturn(publisher);
+
+        mPublisher.addDataSubscriber(dataSubscriber);
+
+        assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
+        verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+        assertThat(mBundleCaptor.getValue().keySet().stream().collect(Collectors.toList()))
+                .containsExactly(
+                        Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+                        Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
+    }
+
+    @Test
     public void testAddDataSubscriber_annotatesWithDrivingSessionData() {
         SessionAnnotation sessionAnnotation = new SessionAnnotation(
                 2, SessionController.STATE_ENTER_DRIVING_SESSION, 123, 1234, "reboot");
@@ -156,11 +324,10 @@
         mSessionCallbackCaptor.getValue().onSessionStateChanged(sessionAnnotation);
         mPublisher.addDataSubscriber(mMockDataSubscriber);
 
-        verify(mMockDataSubscriber).push(mBundleCaptor.capture());
+        verify(mMockDataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
         PersistableBundle report = mBundleCaptor.getValue();
-        assertThat(report.getString(DATA_BUNDLE_KEY_MEMINFO)).isEqualTo(FAKE_MEMINFO);
-        assertThat(report.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(2);
-        assertThat(report.getString(SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON))
+        assertThat(report.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(2);
+        assertThat(report.getString(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON))
                 .isEqualTo("reboot");
     }
 
@@ -213,7 +380,7 @@
         // verify the MetricsConfig is removed
         assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(0);
         assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
-        verify(mMockDataSubscriber, times(2)).push(any());
+        verify(mMockDataSubscriber, times(2)).push(any(), anyBoolean());
         assertThat(mFakePublisherListener.mFinishedConfig).isEqualTo(METRICS_CONFIG);
     }
 
@@ -264,24 +431,6 @@
     }
 
     @Test
-    public void testReadMeminfo_whenPreviousStateExists_shouldContinueFromPrevious() {
-        PersistableBundle publisherState = new PersistableBundle();
-        publisherState.putInt(BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH, 1);
-        publisherState.putBoolean(BUNDLE_KEY_COLLECT_INDEFINITELY, false);
-        when(mMockResultStore.getPublisherData(any(), anyBoolean())).thenReturn(publisherState);
-        mPublisher = createPublisher(mTempFile.toPath());
-
-        // since there is 1 snapshot left, this is the last read and the subscriber will be removed
-        mPublisher.addDataSubscriber(mMockDataSubscriber);
-        mFakeHandlerWrapper.dispatchQueuedMessages();
-
-        assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
-        assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(0);
-        verify(mMockResultStore).removePublisherData(eq(MemoryPublisher.class.getSimpleName()));
-        assertThat(mFakePublisherListener.mFinishedConfig).isEqualTo(METRICS_CONFIG);
-    }
-
-    @Test
     public void testRemoveDataSubscriber_ifDoesNotMatch_keepsSubscriber() {
         mPublisher.addDataSubscriber(mMockDataSubscriber);
         DataSubscriber differentSubscriber = Mockito.mock(DataSubscriber.class);
@@ -305,7 +454,7 @@
     @Test
     public void testReadMeminfo_shouldThrottlePublisher() {
         // 100 MemoryPublisher-related tasks pending script execution > the throttle limit
-        when(mMockDataSubscriber.push(any())).thenReturn(100);
+        when(mMockDataSubscriber.push(any(), anyBoolean())).thenReturn(100);
 
         mPublisher.addDataSubscriber(mMockDataSubscriber);
 
@@ -315,6 +464,24 @@
         assertThatMessageIsScheduledWithGivenDelay(message, THROTTLE_MILLIS);
     }
 
+    @Test
+    public void testReadMeminfo_whenPreviousStateExists_shouldContinueFromPrevious() {
+        PersistableBundle publisherState = new PersistableBundle();
+        publisherState.putInt(BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH, 1);
+        publisherState.putBoolean(BUNDLE_KEY_COLLECT_INDEFINITELY, false);
+        when(mMockResultStore.getPublisherData(any(), anyBoolean())).thenReturn(publisherState);
+        mPublisher = createPublisher(mTempFile.toPath());
+
+        // since there is 1 snapshot left, this is the last read and the subscriber will be removed
+        mPublisher.addDataSubscriber(mMockDataSubscriber);
+        mFakeHandlerWrapper.dispatchQueuedMessages();
+
+        assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+        assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(0);
+        verify(mMockResultStore).removePublisherData(eq(MemoryPublisher.class.getSimpleName()));
+        assertThat(mFakePublisherListener.mFinishedConfig).isEqualTo(METRICS_CONFIG);
+    }
+
     private static void assertThatMessageIsScheduledWithGivenDelay(Message msg, long delayMillis) {
         long expectedTimeMillis = SystemClock.uptimeMillis() + delayMillis;
         long deltaMillis = 1000;  // +/- 1 seconds is good enough for testing
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
index f8f5f6d..d3858e4 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
@@ -387,8 +387,7 @@
 
         assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(1);
         Message msg = mFakeHandlerWrapper.getQueuedMessages().get(0);
-        long expectedPullPeriodMillis = 10 * 60 * 1000;  // 10 minutes
-        assertThatMessageIsScheduledWithGivenDelay(msg, expectedPullPeriodMillis);
+        assertThatMessageIsScheduledWithGivenDelay(msg, 0);
     }
 
     @Test
@@ -454,17 +453,17 @@
 
         verify(subscriber1).push(mBundleCaptor.capture(), anyBoolean());
         PersistableBundle bundle1 = mBundleCaptor.getValue();
-        assertThat(bundle1.getLongArray("elapsed_timestamp_nanos"))
+        assertThat(bundle1.getLongArray("stats.elapsed_timestamp_nanos"))
             .asList().containsExactly(99999999L);
-        assertThat(bundle1.getIntArray("uid")).asList().containsExactly(1000);
-        assertThat(Arrays.asList(bundle1.getStringArray("activity_name")))
+        assertThat(bundle1.getIntArray("stats.uid")).asList().containsExactly(1000);
+        assertThat(Arrays.asList(bundle1.getStringArray("stats.activity_name")))
             .containsExactly("activityName");
-        assertThat(bundle1.getLongArray("rss_in_bytes")).asList().containsExactly(1234L);
+        assertThat(bundle1.getLongArray("stats.rss_in_bytes")).asList().containsExactly(1234L);
         verify(subscriber2).push(mBundleCaptor.capture(), anyBoolean());
         PersistableBundle bundle2 = mBundleCaptor.getValue();
-        assertThat(bundle2.getIntArray("uid")).asList().containsExactly(234);
-        assertThat(bundle2.getLongArray("rss_in_bytes")).asList().containsExactly(4567L);
-        assertThat(bundle2.getLongArray("elapsed_timestamp_nanos"))
+        assertThat(bundle2.getIntArray("stats.uid")).asList().containsExactly(234);
+        assertThat(bundle2.getLongArray("stats.rss_in_bytes")).asList().containsExactly(4567L);
+        assertThat(bundle2.getLongArray("stats.elapsed_timestamp_nanos"))
             .asList().containsExactly(445678901L);
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
index 2536327..2905dc4 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
@@ -18,16 +18,6 @@
 
 import static android.car.hardware.property.CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE;
 
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_BOOLEAN_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_BYTE_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_FLOAT_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_FLOAT_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_INT_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_INT_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_LONG_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_LONG_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_STRING_KEY;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
@@ -81,6 +71,7 @@
     private static final int PROP_BYTES_ID = 0x00700000;
     private static final int PROP_MIXED_ID = 0x00e00000;
     private static final int AREA_ID = 20;
+    private static final int STATUS = 0;
     private static final float PROP_READ_RATE = 0.0f;
     private static final CarPropertyEvent PROP_STRING_EVENT =
             new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
@@ -234,7 +225,7 @@
                     CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE).build();
 
     private final FakeHandlerWrapper mFakeHandlerWrapper =
-            new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.IMMEDIATE);
+            new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.QUEUEING);
     private final FakePublisherListener mFakePublisherListener = new FakePublisherListener();
 
     @Mock
@@ -264,6 +255,8 @@
     private ArgumentCaptor<ICarPropertyEventListener> mCarPropertyCallbackCaptor;
     @Captor
     private ArgumentCaptor<PersistableBundle> mBundleCaptor;
+    @Captor
+    private ArgumentCaptor<List<PersistableBundle>> mBundleListCaptor;
 
     private VehiclePropertyPublisher mVehiclePropertyPublisher;
 
@@ -384,18 +377,24 @@
     public void testOnNewCarPropertyEvent_pushesValueToDataSubscriber() throws Exception {
         doNothing().when(mMockCarPropertyService).registerListener(
                 anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
+        mVehiclePropertyPublisher.setBatchIntervalMillis(0L);
         mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
 
         mCarPropertyCallbackCaptor.getValue().onEvent(Collections.singletonList(PROP_INT_EVENT));
+        mFakeHandlerWrapper.dispatchQueuedMessages();  // Dispatch immediately posted messages
+        mFakeHandlerWrapper.dispatchQueuedMessages();  // Dispatch delay posted messages
 
-        verify(mMockIntDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
+        verify(mMockIntDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().size()).isEqualTo(1);
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT)).isEqualTo(1);
     }
 
     @Test
     public void testOnNewCarPropertyEvent_parsesValueCorrectly() throws Exception {
         doNothing().when(mMockCarPropertyService).registerListener(
                 anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
+        mVehiclePropertyPublisher.setBatchIntervalMillis(1L);
         mVehiclePropertyPublisher.addDataSubscriber(mMockStringDataSubscriber);
         mVehiclePropertyPublisher.addDataSubscriber(mMockBoolDataSubscriber);
         mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
@@ -407,6 +406,7 @@
         mVehiclePropertyPublisher.addDataSubscriber(mMockBytesDataSubscriber);
         mVehiclePropertyPublisher.addDataSubscriber(mMockMixedDataSubscriber);
         ICarPropertyEventListener eventListener = mCarPropertyCallbackCaptor.getValue();
+
         eventListener.onEvent(Collections.singletonList(PROP_STRING_EVENT));
         eventListener.onEvent(Collections.singletonList(PROP_BOOLEAN_EVENT));
         eventListener.onEvent(Collections.singletonList(PROP_INT_EVENT));
@@ -417,51 +417,107 @@
         eventListener.onEvent(Collections.singletonList(PROP_FLOAT_VEC_EVENT));
         eventListener.onEvent(Collections.singletonList(PROP_BYTES_EVENT));
         eventListener.onEvent(Collections.singletonList(PROP_MIXED_EVENT));
+        mFakeHandlerWrapper.dispatchQueuedMessages();  // Dispatch immediately posted messages
+        mFakeHandlerWrapper.dispatchQueuedMessages();  // Dispatch delay posted messages
 
-        verify(mMockStringDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getString(BUNDLE_STRING_KEY)).isEqualTo("hi");
+        verify(mMockStringDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+            .isEqualTo("hi");
 
-        verify(mMockBoolDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getBoolean(BUNDLE_BOOLEAN_KEY)).isTrue();
+        verify(mMockBoolDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN)).isTrue();
 
-        verify(mMockIntDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
+        verify(mMockIntDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT)).isEqualTo(1);
 
-        verify(mMockIntVecDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getIntArray(BUNDLE_INT_ARRAY_KEY))
+        verify(mMockIntVecDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY))
             .isEqualTo(new int[] {1, 2});
 
-        verify(mMockLongDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getLong(BUNDLE_LONG_KEY)).isEqualTo(10L);
+        verify(mMockLongDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG)).isEqualTo(10L);
 
-        verify(mMockLongVecDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getLongArray(BUNDLE_LONG_ARRAY_KEY))
+        verify(mMockLongVecDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY))
             .isEqualTo(new long[] {10L, 20L});
 
-        verify(mMockFloatDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getDouble(BUNDLE_FLOAT_KEY)).isEqualTo(1d);
+        verify(mMockFloatDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT)).isEqualTo(1d);
 
-        verify(mMockFloatVecDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getDoubleArray(BUNDLE_FLOAT_ARRAY_KEY))
+        verify(mMockFloatVecDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY))
             .isEqualTo(new double[] {1d, 2d});
 
-        verify(mMockBytesDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getString(BUNDLE_BYTE_ARRAY_KEY))
+        verify(mMockBytesDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY))
             .isEqualTo(new String(new byte[] {(byte) 1, (byte) 2}, StandardCharsets.UTF_8));
 
-        verify(mMockMixedDataSubscriber).push(mBundleCaptor.capture());
-        assertThat(mBundleCaptor.getValue().getString(BUNDLE_STRING_KEY)).isEqualTo("test");
-        assertThat(mBundleCaptor.getValue().getBoolean(BUNDLE_BOOLEAN_KEY)).isTrue();
-        assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
-        assertThat(mBundleCaptor.getValue().getIntArray(BUNDLE_INT_ARRAY_KEY))
+        verify(mMockMixedDataSubscriber).push(mBundleListCaptor.capture());
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+            .isEqualTo("test");
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN)).isTrue();
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT)).isEqualTo(1);
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY))
             .isEqualTo(new int[] {2, 3, 4});
-        assertThat(mBundleCaptor.getValue().getLong(BUNDLE_LONG_KEY)).isEqualTo(2L);
-        assertThat(mBundleCaptor.getValue().getLongArray(BUNDLE_LONG_ARRAY_KEY))
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG)).isEqualTo(2L);
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY))
             .isEqualTo(new long[] {5L, 6L});
-        assertThat(mBundleCaptor.getValue().getDouble(BUNDLE_FLOAT_KEY)).isEqualTo(3d);
-        assertThat(mBundleCaptor.getValue().getDoubleArray(BUNDLE_FLOAT_ARRAY_KEY))
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT)).isEqualTo(3d);
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY))
             .isEqualTo(new double[] {7d, 8d});
-        assertThat(mBundleCaptor.getValue().getString(BUNDLE_BYTE_ARRAY_KEY))
+        assertThat(mBundleListCaptor.getValue().get(0)
+                .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY))
             .isEqualTo(new String(new byte[] {(byte) 5, (byte) 6}, StandardCharsets.UTF_8));
     }
+
+    @Test
+    public void testOnNewCarPropertyEvents_batchIsPushedAfterDelay() throws Exception {
+        doNothing().when(mMockCarPropertyService).registerListener(
+                anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
+        mVehiclePropertyPublisher.setBatchIntervalMillis(10L);  // Batch interval 10 milliseconds
+        mVehiclePropertyPublisher.addDataSubscriber(mMockStringDataSubscriber);
+        ICarPropertyEventListener eventListener = mCarPropertyCallbackCaptor.getValue();
+        CarPropertyEvent propEvent1 = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+                new CarPropertyValue<>(PROP_STRING_ID, AREA_ID, STATUS, /* timestamp= */ 0L,
+                        "first"));
+        CarPropertyEvent propEvent2 = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+                new CarPropertyValue<>(PROP_STRING_ID, AREA_ID, STATUS, /* timestamp= */ 5L,
+                        "second"));
+        CarPropertyEvent propEvent3 = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+                new CarPropertyValue<>(PROP_STRING_ID, AREA_ID, STATUS, /* timestamp= */ 7L,
+                        "third"));
+
+        eventListener.onEvent(Collections.singletonList(propEvent1));
+        eventListener.onEvent(Collections.singletonList(propEvent2));
+        eventListener.onEvent(Collections.singletonList(propEvent3));
+        mFakeHandlerWrapper.dispatchQueuedMessages();  // Dispatch immediately posted messages
+        mFakeHandlerWrapper.dispatchQueuedMessages();  // Dispatch delay posted messages
+
+        verify(mMockStringDataSubscriber).push(mBundleListCaptor.capture());
+        List<PersistableBundle> bundleList = mBundleListCaptor.getValue();
+        assertThat(bundleList.size()).isEqualTo(3);
+        assertThat(bundleList.get(0).getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+            .isEqualTo("first");
+        assertThat(bundleList.get(1).getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+            .isEqualTo("second");
+        assertThat(bundleList.get(2).getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+            .isEqualTo("third");
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java
index ced410b..1f2e2f6 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java
@@ -28,6 +28,7 @@
 import android.os.PersistableBundle;
 
 import com.android.car.telemetry.UidPackageMapper;
+import com.android.car.telemetry.publisher.Constants;
 import com.android.internal.util.FastXmlSerializer;
 
 import org.junit.Before;
@@ -79,14 +80,15 @@
         PersistableBundle result = mRefinedStats.toPersistableBundle(mMockUidMapper);
 
         PersistableBundle expected = new PersistableBundle();
-        expected.putLong("startMillis", 10_000);
-        expected.putLong("endMillis", 20_000);
-        expected.putInt("size", 2);
-        expected.putIntArray("uid", new int[] {UID_0, UID_1});
-        expected.putStringArray("packages", new String[] {"pkg1,pkg2", "pkg1,pkg2"});
-        expected.putIntArray("tag", new int[] {TAG_1, TAG_NONE});
-        expected.putLongArray("rxBytes", new long[] {14096, 4095});
-        expected.putLongArray("txBytes", new long[] {12048, 2047});
+        expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS, 10_000);
+        expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS, 20_000);
+        expected.putInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE, 2);
+        expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID, new int[] {UID_0, UID_1});
+        expected.putStringArray(Constants.CONNECTIVITY_BUNDLE_KEY_PACKAGES,
+                new String[] {"pkg1,pkg2", "pkg1,pkg2"});
+        expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG, new int[] {TAG_1, TAG_NONE});
+        expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES, new long[] {14096, 4095});
+        expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES, new long[] {12048, 2047});
         assertThat(bundleToXml(result)).isEqualTo(bundleToXml(expected));
     }
 
@@ -122,15 +124,21 @@
         RefinedStats diff = RefinedStats.subtract(mRefinedStats, other);
 
         PersistableBundle expected = new PersistableBundle();
-        expected.putLong("startMillis", 10_000);
-        expected.putLong("endMillis", 20_000);
-        expected.putInt("size", 3); // the same size as "mRefinedStats"
-        expected.putIntArray("uid", new int[] {UID_1, UID_1, UID_2});
-        expected.putStringArray("packages", new String[] {"pkg1,pkg2", "pkg1,pkg2", "pkg1,pkg2"});
-        expected.putIntArray("tag", new int[] {TAG_NONE, TAG_1, TAG_NONE});
+        expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS, 10_000);
+        expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS, 20_000);
+        // the same size as "mRefinedStats"
+        expected.putInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE, 3);
+        expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID,
+                new int[] {UID_1, UID_1, UID_2});
+        expected.putStringArray(Constants.CONNECTIVITY_BUNDLE_KEY_PACKAGES,
+                new String[] {"pkg1,pkg2", "pkg1,pkg2", "pkg1,pkg2"});
+        expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG,
+                new int[] {TAG_NONE, TAG_1, TAG_NONE});
         // Handles negative values too (hence 0).
-        expected.putLongArray("rxBytes", new long[] {4090, 0, 4096});
-        expected.putLongArray("txBytes", new long[] {2040, 0, 2048});
+        expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES,
+                new long[] {4090, 0, 4096});
+        expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES,
+                new long[] {2040, 0, 2048});
         assertThat(bundleToXml(diff.toPersistableBundle(mMockUidMapper)))
                 .isEqualTo(bundleToXml(expected));
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java
index 8efaf1b..5a9ddd7 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java
@@ -20,6 +20,7 @@
 import static com.android.car.telemetry.AtomsProto.ActivityForegroundStateChanged.PKG_NAME_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ActivityForegroundStateChanged.STATE_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ActivityForegroundStateChanged.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -105,15 +106,18 @@
                 dimensionsValuesList, HASH_STR_MAP);
 
         assertThat(bundle.size()).isEqualTo(4);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000, 2000).inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(PKG_NAME_FIELD_NUMBER).getFieldName())))
+        assertThat(Arrays.asList(bundle.getStringArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PKG_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("package.name.1", "package.name.2").inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(CLASS_NAME_FIELD_NUMBER).getFieldName())))
+        assertThat(Arrays.asList(bundle.getStringArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        CLASS_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("className1", "className2").inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(STATE_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(STATE_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(0, 1).inOrder();  // States background=0 and foreground=1
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java
index f776da9..9cfa917 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java
@@ -20,6 +20,7 @@
 import static com.android.car.telemetry.AtomsProto.ANROccurred.PACKAGE_NAME_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ANROccurred.REASON_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ANROccurred.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -78,14 +79,19 @@
         PersistableBundle bundle = mConverter.convert(atomsList, null, null, null);
 
         assertThat(bundle.size()).isEqualTo(4);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
                 .asList().containsExactly(1000, 2000).inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(PACKAGE_NAME_FIELD_NUMBER).getFieldName())))
+        assertThat(Arrays.asList(bundle.getStringArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                            PACKAGE_NAME_FIELD_NUMBER).getFieldName())))
                 .containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
-        assertThat(bundle.getStringArray(accessorMap.get(REASON_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getStringArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(REASON_FIELD_NUMBER).getFieldName()))
                 .asList().containsExactly("test1", "test2").inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ERROR_SOURCE_FIELD_NUMBER)
+                            .getFieldName()))
                 .asList().containsExactly(1, 2).inOrder();  // DATA_APP=1, SYSTEM_APP=2
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java
index 9ceef70..b925af0 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java
@@ -20,6 +20,7 @@
 import static com.android.car.telemetry.AtomsProto.AppCrashOccurred.PACKAGE_NAME_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.AppCrashOccurred.PID_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.AppCrashOccurred.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -77,13 +78,19 @@
         PersistableBundle bundle = mConverter.convert(atomsList, null, null, null);
 
         assertThat(bundle.size()).isEqualTo(4);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
                 .asList().containsExactly(1000, 2000).inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(PID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PID_FIELD_NUMBER).getFieldName()))
                 .asList().containsExactly(12345, 67890).inOrder();
-        assertThat(bundle.getStringArray(accessorMap.get(PACKAGE_NAME_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getStringArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PACKAGE_NAME_FIELD_NUMBER)
+                            .getFieldName()))
                 .asList().containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ERROR_SOURCE_FIELD_NUMBER)
+                            .getFieldName()))
                 .asList().containsExactly(1, 2).inOrder();  // DATA_APP=1, SYSTEM_APP=2
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java
index c2346a1..30b5f21 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java
@@ -24,6 +24,7 @@
 import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.SWAP_IN_BYTES_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -119,24 +120,36 @@
                 dimensionsValuesList, HASH_STR_MAP);
 
         assertThat(bundle.size()).isEqualTo(8);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000, 2000).inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+        assertThat(Arrays.asList(bundle.getStringArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PROCESS_NAME_FIELD_NUMBER)
+                            .getFieldName())))
             .containsExactly("process.name.1", "process.name.2").inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
+        assertThat(Arrays.asList(bundle.getStringArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER)
+                            .getFieldName())))
             .containsExactly("activityName1", "activityName2").inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER)
+                            .getFieldName()))
             .asList().containsExactly(59L, 99L).inOrder();
         assertThat(bundle.getLongArray(
-                        accessorMap.get(PAGE_MAJOR_FAULT_FIELD_NUMBER).getFieldName()))
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_MAJOR_FAULT_FIELD_NUMBER)
+                            .getFieldName()))
             .asList().containsExactly(34L, 55L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER)
+                            .getFieldName()))
             .asList().containsExactly(1234L, 2345L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(CACHE_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(CACHE_IN_BYTES_FIELD_NUMBER)
+                            .getFieldName()))
             .asList().containsExactly(234L, 345L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER)
+                            .getFieldName()))
             .asList().containsExactly(111L, 222L).inOrder();
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java
index 752cd36..51dd912 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java
@@ -16,6 +16,8 @@
 
 package com.android.car.telemetry.publisher.statsconverters;
 
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.PersistableBundle;
@@ -60,15 +62,17 @@
 
         assertThat(bundle.size()).isEqualTo(3);
         assertThat(bundle.getIntArray(
-                accessorMap.get(AppStartMemoryStateCaptured.UID_FIELD_NUMBER).getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        AppStartMemoryStateCaptured.UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000, 1100).inOrder();
         assertThat(Arrays.asList(bundle.getStringArray(
-                accessorMap.get(AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER)
-                .getFieldName())))
+                    STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                            AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER)
+                            .getFieldName())))
             .containsExactly("activityName1", "activityName2").inOrder();
         assertThat(bundle.getLongArray(
-                accessorMap.get(AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER)
-                .getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L, 2345L).inOrder();
     }
 
@@ -96,13 +100,16 @@
 
         assertThat(bundle.size()).isEqualTo(3);
         assertThat(bundle.getIntArray(
-                accessorMap.get(ProcessMemoryState.UID_FIELD_NUMBER).getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ProcessMemoryState.UID_FIELD_NUMBER)
+                        .getFieldName()))
             .asList().containsExactly(1000, 1100).inOrder();
         assertThat(Arrays.asList(bundle.getStringArray(
-                accessorMap.get(ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("processName1", "processName2").inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(
-                ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L, 2345L).inOrder();
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java
index da486d8..cd7da4b 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java
@@ -16,6 +16,9 @@
 
 package com.android.car.telemetry.publisher.statsconverters;
 
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.PersistableBundle;
@@ -101,33 +104,34 @@
 
         assertThat(new ArrayList<Long>(map.keySet())).containsExactly(12345L, 23456L);
         PersistableBundle eventBundle = map.get(12345L);
-        assertThat(eventBundle.getLongArray(EventMetricDataConverter.ELAPSED_TIME_NANOS))
+        assertThat(eventBundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
             .asList().containsExactly(99999999L);
         assertThat(eventBundle.getIntArray(
-                appMemAccessorMap.get(AppStartMemoryStateCaptured.UID_FIELD_NUMBER)
-                .getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + appMemAccessorMap.get(
+                        AppStartMemoryStateCaptured.UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000);
         assertThat(Arrays.asList(eventBundle.getStringArray(
-                appMemAccessorMap.get(AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER)
-                .getFieldName())))
+                STATS_BUNDLE_KEY_PREFIX + appMemAccessorMap.get(
+                        AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("activityName");
         assertThat(eventBundle.getLongArray(
-                appMemAccessorMap.get(AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER)
-                .getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + appMemAccessorMap.get(
+                        AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L);
         PersistableBundle gaugeBundle = map.get(23456L);
         assertThat(gaugeBundle.getIntArray(
-                procMemAccessorMap.get(ProcessMemoryState.UID_FIELD_NUMBER).getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + procMemAccessorMap.get(
+                        ProcessMemoryState.UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(234);
         assertThat(Arrays.asList(gaugeBundle.getStringArray(
-                procMemAccessorMap.get(ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER)
-                .getFieldName())))
+                STATS_BUNDLE_KEY_PREFIX + procMemAccessorMap.get(
+                        ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("process.name");
         assertThat(gaugeBundle.getLongArray(
-                procMemAccessorMap.get(ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER)
-                .getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + procMemAccessorMap.get(
+                        ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(4567L);
-        assertThat(gaugeBundle.getLongArray(GaugeMetricDataConverter.ELAPSED_TIME_NANOS))
+        assertThat(gaugeBundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
             .asList().containsExactly(445678901L);
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java
index 5cb41c0..2b4ee7b 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java
@@ -19,6 +19,8 @@
 import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -68,14 +70,18 @@
         PersistableBundle bundle = EventMetricDataConverter.convertEventDataList(eventDataList);
 
         assertThat(bundle.size()).isEqualTo(4);
-        assertThat(bundle.getLongArray(EventMetricDataConverter.ELAPSED_TIME_NANOS))
+        assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
             .asList().containsExactly(12345678L, 23456789L).inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000, 1100).inOrder();
         assertThat(Arrays.asList(bundle.getStringArray(
-                accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("activityName1", "activityName2").inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L, 2345L).inOrder();
     }
 
@@ -112,14 +118,18 @@
         PersistableBundle bundle = EventMetricDataConverter.convertEventDataList(eventDataList);
 
         assertThat(bundle.size()).isEqualTo(4);
-        assertThat(bundle.getLongArray(EventMetricDataConverter.ELAPSED_TIME_NANOS))
+        assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
             .asList().containsExactly(12345678L, 12345679L, 23456789L).inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000, 1000, 1100).inOrder();
         assertThat(Arrays.asList(bundle.getStringArray(
-                accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("activityName1", "activityName1", "activityName2").inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L, 1234L, 2345L).inOrder();
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java
index 4053135..e80a29d 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java
@@ -21,6 +21,8 @@
 import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.SWAP_IN_BYTES_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -105,19 +107,26 @@
         // For each atom 2 fields were set, additionally 3 fields were encoded in dimension values,
         // and 1 elapsed time array, so 6 arrays are expected in the bundle.
         assertThat(bundle.size()).isEqualTo(6);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(123, 123, 123, 234).inOrder();
         assertThat(Arrays.asList(bundle.getStringArray(
-                accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        PROCESS_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("process.name.1", "process.name.1",
                         "process.name.1", "process.name.2").inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000L, 1100L, 1200L, 1300L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L, 2345L, 3456L, 4567L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(11111111L, 11111111L, 11111111L, 22222222L).inOrder();
-        assertThat(bundle.getLongArray(GaugeMetricDataConverter.ELAPSED_TIME_NANOS))
+        assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
             .asList().containsExactly(12345678L, 23456789L, 34567890L, 445678901L).inOrder();
     }
 
@@ -190,20 +199,27 @@
         // For each atom 2 fields were set, additionally 3 fields were encoded in dimension values,
         // and 1 elapsed time array, so 6 arrays are expected in the bundle.
         assertThat(bundle.size()).isEqualTo(6);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(123, 123, 123, 123, 123, 234).inOrder();
         assertThat(Arrays.asList(bundle.getStringArray(
-                accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        PROCESS_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("process.name.1", "process.name.1", "process.name.1",
                     "process.name.1", "process.name.1", "process.name.2").inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000L, 1000L, 1100L, 1200L, 1200L, 1300L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L, 1234L, 2345L, 3456L, 3456L, 4567L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(
                     11111111L, 11111111L, 11111111L, 11111111L, 11111111L, 22222222L).inOrder();
-        assertThat(bundle.getLongArray(GaugeMetricDataConverter.ELAPSED_TIME_NANOS))
+        assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
             .asList().containsExactly(
                     12345678L, 12345679L, 23456789L, 34567890L, 34567899L, 445678901L).inOrder();
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java
index 75c1bf6..a0faf78 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java
@@ -20,6 +20,7 @@
 import static com.android.car.telemetry.AtomsProto.ProcessCpuTime.SYSTEM_TIME_MILLIS_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ProcessCpuTime.UID_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ProcessCpuTime.USER_TIME_MILLIS_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -102,16 +103,20 @@
                 dimensionsValuesList, HASH_STR_MAP);
 
         assertThat(bundle.size()).isEqualTo(4);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000, 2000).inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+        assertThat(Arrays.asList(bundle.getStringArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        PROCESS_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("process.name.1", "process.name.2").inOrder();
         assertThat(bundle.getLongArray(
-                accessorMap.get(USER_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        USER_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(234L, 345L).inOrder();
         assertThat(bundle.getLongArray(
-                accessorMap.get(SYSTEM_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        SYSTEM_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(111L, 222L).inOrder();
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverterTest.java
new file mode 100644
index 0000000..715830e
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverterTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry.publisher.statsconverters;
+
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.ANON_RSS_AND_SWAP_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.ANON_RSS_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.GPU_MEMORY_KB_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.HAS_FOREGROUND_SERVICES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.OOM_SCORE_ADJ_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.PID_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.PROCESS_NAME_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.RSS_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.SWAP_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.os.PersistableBundle;
+import android.util.SparseArray;
+
+import com.android.car.telemetry.AtomsProto.Atom;
+import com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot;
+import com.android.car.telemetry.StatsLogProto.DimensionsValue;
+import com.android.car.telemetry.publisher.HashUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class ProcessMemorySnapshotConverterTest {
+    private static final Atom ATOM_A =
+            Atom.newBuilder()
+                    .setProcessMemorySnapshot(ProcessMemorySnapshot.newBuilder()
+                            .setPid(88)
+                            .setOomScoreAdj(100)
+                            .setRssInKilobytes(1234)
+                            .setAnonRssInKilobytes(99)
+                            .setSwapInKilobytes(101)
+                            .setAnonRssAndSwapInKilobytes(200)
+                            .setGpuMemoryKb(0)
+                            .setHasForegroundServices(true))
+                    .build();
+
+    private static final Atom ATOM_B =
+            Atom.newBuilder()
+                    .setProcessMemorySnapshot(ProcessMemorySnapshot.newBuilder()
+                            .setPid(99)
+                            .setOomScoreAdj(200)
+                            .setRssInKilobytes(6666)
+                            .setAnonRssInKilobytes(100)
+                            .setSwapInKilobytes(100)
+                            .setAnonRssAndSwapInKilobytes(200)
+                            .setGpuMemoryKb(1)
+                            .setHasForegroundServices(false))
+                    .build();
+
+    private static final Atom ATOM_MISMATCH =
+            Atom.newBuilder()
+                    .setProcessMemorySnapshot(ProcessMemorySnapshot.newBuilder()
+                            // Some fields are not set, creating mismatch with above atoms
+                            .setSwapInKilobytes(333))
+                    .build();
+
+    private static final List<Integer> DIM_FIELDS_IDS = Arrays.asList(1, 2);
+    private static final Long HASH_1 = HashUtils.murmur2Hash64("process.name.1");
+    private static final Long HASH_2 = HashUtils.murmur2Hash64("process.name.2");
+    private static final Map<Long, String> HASH_STR_MAP = Map.of(
+            HASH_1, "process.name.1",
+            HASH_2, "process.name.2");
+
+    private static final List<DimensionsValue> DV_PAIR_A =
+            Arrays.asList(
+                    DimensionsValue.newBuilder().setValueInt(1000).build(),
+                    DimensionsValue.newBuilder().setValueStrHash(HASH_1).build());
+
+    private static final List<DimensionsValue> DV_PAIR_B =
+            Arrays.asList(
+                    DimensionsValue.newBuilder().setValueInt(2000).build(),
+                    DimensionsValue.newBuilder().setValueStrHash(HASH_2).build());
+
+    private static final List<DimensionsValue> DV_PAIR_MALFORMED =
+            Arrays.asList(
+                    DimensionsValue.newBuilder().setValueInt(3000).build(),
+                    // Wrong format since leaf level dimension value should set value, not field
+                    DimensionsValue.newBuilder().setField(3).build());
+
+    // Subject of the test.
+    private ProcessMemorySnapshotConverter mConverter = new ProcessMemorySnapshotConverter();
+
+    @Test
+    public void testConvertAtomsListWithDimensionValues_putsCorrectDataToPersistableBundle()
+            throws StatsConversionException {
+        List<Atom> atomsList = Arrays.asList(ATOM_A, ATOM_B);
+        List<List<DimensionsValue>> dimensionsValuesList = Arrays.asList(DV_PAIR_A, DV_PAIR_B);
+        SparseArray<AtomFieldAccessor<ProcessMemorySnapshot, ?>> accessorMap =
+                mConverter.getAtomFieldAccessorMap();
+
+        PersistableBundle bundle = mConverter.convert(atomsList, DIM_FIELDS_IDS,
+                dimensionsValuesList, HASH_STR_MAP);
+
+        assertThat(bundle.size()).isEqualTo(10);
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(1000, 2000).inOrder();
+        assertThat(Arrays.asList(bundle.getStringArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+                .containsExactly("process.name.1", "process.name.2").inOrder();
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PID_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(88, 99);
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        OOM_SCORE_ADJ_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(100, 200).inOrder();
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        RSS_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(1234, 6666).inOrder();
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        ANON_RSS_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(99, 100).inOrder();
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        SWAP_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(101, 100).inOrder();
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        ANON_RSS_AND_SWAP_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(200, 200).inOrder();
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        GPU_MEMORY_KB_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(0, 1).inOrder();
+        assertThat(bundle.getBooleanArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        HAS_FOREGROUND_SERVICES_FIELD_NUMBER).getFieldName()))
+                .asList().containsExactly(true, false).inOrder();
+    }
+
+    @Test
+    public void testAtomSetFieldInconsistency_throwsException() {
+        List<Atom> atomsList = Arrays.asList(ATOM_A, ATOM_MISMATCH);
+        List<List<DimensionsValue>> dimensionsValuesList = Arrays.asList(DV_PAIR_A, DV_PAIR_B);
+
+        assertThrows(
+                StatsConversionException.class,
+                () -> mConverter.convert(
+                        atomsList,
+                        DIM_FIELDS_IDS,
+                        dimensionsValuesList,
+                        HASH_STR_MAP));
+    }
+
+    @Test
+    public void testMalformedDimensionValue_throwsException() {
+        List<Atom> atomsList = Arrays.asList(ATOM_A, ATOM_B);
+        List<List<DimensionsValue>> dimensionsValuesList =
+                Arrays.asList(DV_PAIR_A, DV_PAIR_MALFORMED);
+
+        assertThrows(
+                StatsConversionException.class,
+                () -> mConverter.convert(
+                        atomsList,
+                        DIM_FIELDS_IDS,
+                        dimensionsValuesList,
+                        HASH_STR_MAP));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java
index 39fb772..bf82bda 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java
@@ -24,6 +24,7 @@
 import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.SWAP_IN_BYTES_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -117,24 +118,35 @@
                 dimensionsValuesList, HASH_STR_MAP);
 
         assertThat(bundle.size()).isEqualTo(8);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1000, 2000).inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+        assertThat(Arrays.asList(bundle.getStringArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        PROCESS_NAME_FIELD_NUMBER).getFieldName())))
             .containsExactly("process.name.1", "process.name.2").inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(OOM_ADJ_SCORE_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        OOM_ADJ_SCORE_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(100, 200).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(59L, 99L).inOrder();
         assertThat(bundle.getLongArray(
-                accessorMap.get(PAGE_MAJOR_FAULT_FIELD_NUMBER).getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        PAGE_MAJOR_FAULT_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(34L, 55L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(1234L, 2345L).inOrder();
         assertThat(bundle.getLongArray(
-                accessorMap.get(CACHE_IN_BYTES_FIELD_NUMBER).getFieldName()))
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        CACHE_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(234L, 345L).inOrder();
-        assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+        assertThat(bundle.getLongArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
             .asList().containsExactly(111L, 222L).inOrder();
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java
index f0dbdd2..c3a4f68 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java
@@ -20,6 +20,7 @@
 import static com.android.car.telemetry.AtomsProto.WTFOccurred.PROCESS_NAME_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.WTFOccurred.TAG_FIELD_NUMBER;
 import static com.android.car.telemetry.AtomsProto.WTFOccurred.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -76,15 +77,20 @@
         PersistableBundle bundle = mConverter.convert(atomsList, null, null, null);
 
         assertThat(bundle.size()).isEqualTo(4);
-        assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
-                .asList().containsExactly(1000, 2000).inOrder();
-        assertThat(Arrays.asList(
-                bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
-                .containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
-        assertThat(bundle.getStringArray(accessorMap.get(TAG_FIELD_NUMBER).getFieldName()))
-                .asList().containsExactly("tag1", "tag2").inOrder();
-        assertThat(bundle.getIntArray(accessorMap.get(ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
-                .asList().containsExactly(1, 2).inOrder();  // DATA_APP=1, SYSTEM_APP=2
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+            .asList().containsExactly(1000, 2000).inOrder();
+        assertThat(Arrays.asList(bundle.getStringArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+            .containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
+        assertThat(bundle.getStringArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(TAG_FIELD_NUMBER).getFieldName()))
+            .asList().containsExactly("tag1", "tag2").inOrder();
+        assertThat(bundle.getIntArray(
+                STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+                        ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
+            .asList().containsExactly(1, 2).inOrder();  // DATA_APP=1, SYSTEM_APP=2
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java
index da5917c..d1cc98c 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java
@@ -20,6 +20,8 @@
 
 import android.os.PersistableBundle;
 
+import com.android.car.telemetry.publisher.Constants;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
@@ -42,17 +44,17 @@
 
         sAnnotation.addAnnotationsToBundle(data);
 
-        assertThat(data.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(
+        assertThat(data.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(
                 SESSION_ID);
-        assertThat(data.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_STATE)).isEqualTo(
+        assertThat(data.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE)).isEqualTo(
                 SESSION_STATE);
         assertThat(data.getLong(
-                SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS)).isEqualTo(
+                Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS)).isEqualTo(
                 CREATED_AT_SINCE_BOOT_MILLIS);
         assertThat(
-                data.getLong(SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS)).isEqualTo(
+                data.getLong(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS)).isEqualTo(
                 CREATED_AT_MILLIS);
-        assertThat(data.getString(SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON)).isEqualTo(
+        assertThat(data.getString(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON)).isEqualTo(
                 BOOT_REASON);
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index dca7764..34dc354 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -509,6 +509,34 @@
     }
 
     @Test
+    public void testPowerCycleStateChangesDuringSuspend() throws Exception {
+        setCarPowerState(CarPowerManager.STATE_SUSPEND_ENTER);
+        setCarPowerState(CarPowerManager.STATE_SUSPEND_EXIT);
+        setCarPowerState(CarPowerManager.STATE_ON);
+
+        verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER, MISSING_ARG_VALUE);
+        verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_SUSPEND_EXIT, MISSING_ARG_VALUE);
+        verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_RESUME, MISSING_ARG_VALUE);
+    }
+
+    @Test
+    public void testPowerCycleStateChangesDuringHibernation() throws Exception {
+        setCarPowerState(CarPowerManager.STATE_HIBERNATION_ENTER);
+        setCarPowerState(CarPowerManager.STATE_HIBERNATION_EXIT);
+        setCarPowerState(CarPowerManager.STATE_ON);
+
+        verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER, MISSING_ARG_VALUE);
+        verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_SUSPEND_EXIT, MISSING_ARG_VALUE);
+        verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_RESUME, MISSING_ARG_VALUE);
+    }
+
+    @Test
     public void testDeviceRebootBroadcast() throws Exception {
         mBroadcastReceiver.onReceive(mMockContext,
                 new Intent().setAction(Intent.ACTION_REBOOT)
@@ -4537,11 +4565,7 @@
             int userId = userIds[i];
             UserHandle userHandle = UserHandle.of(userId);
 
-            mBroadcastReceiver
-                    .onReceive(mMockContext, new Intent(ACTION_RESOURCE_OVERUSE_DISABLE_APP)
-                    .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
-                    .putExtra(Intent.EXTRA_USER, userHandle)
-                    .putExtra(INTENT_EXTRA_NOTIFICATION_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
+            mCarWatchdogService.performResourceOveruseKill(packageName, userId);
 
             verify(mSpiedPackageManager, atLeastOnce())
                     .getApplicationEnabledSetting(packageName, userId);