Merge "Improve YUY2 to RGBA color conversion" into sc-dev
diff --git a/.clang-format b/.clang-format
index 30e9eda..b652e19 100644
--- a/.clang-format
+++ b/.clang-format
@@ -36,3 +36,7 @@
   - Regex:           '^".*'
     Priority:        1
 ---
+Language: Proto
+BasedOnStyle: Google
+ColumnLimit: 100
+---
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index 2112521..9c11299 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -153,7 +153,6 @@
 droidstubs {
     name: "android.car-stubs-docs",
     defaults: ["android.car-docs-default"],
-    removed_dex_api_filename: "removed-dex.txt",
     args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* " +
         "--hide-package com.android.internal ",
     installable: false,
@@ -182,7 +181,6 @@
 droidstubs {
     name: "android.car-system-stubs-docs",
     defaults: ["android.car-docs-default"],
-    removed_dex_api_filename: "system-removed-dex.txt",
     // TODO(b/174572385): Remove CallbackInterface once this b/174572385 is fixed
     args: "--hide CallbackInterface --hide UnavailableSymbol --hide HiddenSuperclass " +
         "--no-docs --stub-packages android.car* " +
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index 0d93ff1..a677453 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -67,7 +67,7 @@
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_FUEL_TYPE = 289472773;
     /**
-     * Battery capacity of the vehicle, if EV or hybrid.  This is the nominal
+     * Battery capacity of the vehicle in watt-hours (Wh), if EV or hybrid. This is the nominal
      * battery capacity when the vehicle is new.
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
@@ -130,19 +130,19 @@
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EXTERIOR_DIMENSIONS = 289472779;
     /**
-     * Current odometer value of the vehicle
+     * Current odometer value of the vehicle in kilometers.
      * The property is protected by the signature permission: android.car.permission.CAR_MILEAGE.
      */
     @RequiresPermission(Car.PERMISSION_MILEAGE)
     public static final int PERF_ODOMETER = 291504644;
     /**
-     * Speed of the vehicle
+     * Speed of the vehicle in meters per second.
      * Requires permission: {@link Car#PERMISSION_SPEED}.
      */
     @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int PERF_VEHICLE_SPEED = 291504647;
     /**
-     * Speed of the vehicle for displays
+     * Speed of the vehicle in meters per second for displays.
      *
      * Some cars display a slightly slower speed than the actual speed. This is
      * usually displayed on the speedometer.
@@ -151,23 +151,23 @@
     @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int PERF_VEHICLE_SPEED_DISPLAY = 291504648;
     /**
-     * Front bicycle model steering angle for vehicle
+     * Front bicycle model steering angle for vehicle in degrees.
      *
-     * Angle is in degrees. Left is negative.
+     * Left is negative.
      * Requires permission: {@link Car#PERMISSION_READ_STEERING_STATE}.
      */
     @RequiresPermission(Car.PERMISSION_READ_STEERING_STATE)
     public static final int PERF_STEERING_ANGLE = 291504649;
     /**
-     * Rear bicycle model steering angle for vehicle
+     * Rear bicycle model steering angle for vehicle in degrees.
      *
-     * Angle is in degrees. Left is negative.
+     * Left is negative.
      * Requires permission: {@link Car#PERMISSION_READ_STEERING_STATE}.
      */
     @RequiresPermission(Car.PERMISSION_READ_STEERING_STATE)
     public static final int PERF_REAR_STEERING_ANGLE = 291504656;
     /**
-     * Temperature of engine coolant
+     * Temperature of engine coolant in celsius.
      * The property is protected by the signature permission:
      * android.car.permission.CAR_ENGINE_DETAILED.
      */
@@ -181,7 +181,7 @@
     @RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
     public static final int ENGINE_OIL_LEVEL = 289407747;
     /**
-     * Temperature of engine oil
+     * Temperature of engine oil in celsius.
      * The property is protected by the signature permission:
      * android.car.permission.CAR_ENGINE_DETAILED.
      */
@@ -195,8 +195,44 @@
     @RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
     public static final int ENGINE_RPM = 291504901;
     /**
-     * Reports wheel ticks
-     * Requires permission: {@link Car#PERMISSION_SPEED}.
+     * Reports wheel ticks.
+     *
+     * <p>WHEEL_TICK property is {@link VehiclePropertyAccess#Read} access,
+     * {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS} and returns a Long[] type
+     * value.
+     *
+     * <p>The first element in the array is a reset count.  A reset indicates
+     * previous tick counts are not comparable with this and future ones.  Some
+     * sort of discontinuity in tick counting has occurred.
+     *
+     * <p>The next four elements represent ticks for individual wheels in the
+     * following order: front left, front right, rear right, rear left.  All
+     * tick counts are cumulative.  Tick counts increment when the vehicle
+     * moves forward, and decrement when vehicles moves in reverse.  The ticks
+     * should be reset to 0 when the vehicle is started by the user.
+     *
+     * <ul>
+     *  <li>Long[0] = reset count
+     *  <li>Long[1] = front left ticks
+     *  <li>Long[2] = front right ticks
+     *  <li>Long[3] = rear right ticks
+     *  <li>Long[4] = rear left ticks
+     * </ul>
+     *
+     * <p>configArray is used to indicate the micrometers-per-wheel-tick value and
+     * which wheels are supported. configArray is set as follows:
+     *
+     * <ul>
+     *  <li>configArray[0], bits [0:3] = supported wheels.  Uses enum Wheel.
+     *  <li>configArray[1] = micrometers per front left wheel tick
+     *  <li>configArray[2] = micrometers per front right wheel tick
+     *  <li>configArray[3] = micrometers per rear right wheel tick
+     *  <li>configArray[4] = micrometers per rear left wheel tick
+     * </ul>
+     *
+     * <p>NOTE:  If a wheel is not supported, its value is always 0.
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_SPEED}.
      */
     @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int WHEEL_TICK = 290521862;
@@ -216,7 +252,7 @@
     @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS))
     public static final int FUEL_DOOR_OPEN = 287310600;
     /**
-     * EV battery level in WH, if EV or hybrid
+     * EV battery level in watt-hours (Wh), if EV or hybrid.
      * Requires permission: {@link Car#PERMISSION_ENERGY}.
      */
     @RequiresPermission(Car.PERMISSION_ENERGY)
@@ -256,7 +292,7 @@
     @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_ADJUST_RANGE_REMAINING))
     public static final int RANGE_REMAINING = 291504904;
     /**
-     * Tire pressure
+     * Tire pressure in kilopascals.
      *
      * min/max value indicates tire pressure sensor range.  Each tire will have a separate min/max
      * value denoted by its areaConfig.areaId.
@@ -358,7 +394,7 @@
     @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_FAN_DIRECTION = 356517121;
     /**
-     * HVAC current temperature.
+     * HVAC current temperature in celsius.
      * The property is protected by the signature permission:
      * android.car.permission.CONTROL_CAR_CLIMATE.
      */
@@ -625,7 +661,7 @@
             Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364;
     /**
-     * Outside temperature
+     * Outside temperature in celsius.
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
      */
     @RequiresPermission(Car.PERMISSION_EXTERIOR_ENVIRONMENT)
diff --git a/car-lib/src/android/car/hardware/CarPropertyValue.java b/car-lib/src/android/car/hardware/CarPropertyValue.java
index b280e7d..0f2a6bf 100644
--- a/car-lib/src/android/car/hardware/CarPropertyValue.java
+++ b/car-lib/src/android/car/hardware/CarPropertyValue.java
@@ -83,7 +83,10 @@
     }
 
     /**
-     * Creates an instance of CarPropertyValue.
+     * Creates an instance of CarPropertyValue. The {@code timestamp} is the time in nanoseconds at
+     * which the event happened. For a given car property, each new CarPropertyValue should be
+     * monotonically increasing using the same time base as
+     * {@link SystemClock#elapsedRealtimeNanos()}.
      *
      * @param propertyId Property ID
      * @param areaId     Area ID of Property
@@ -189,7 +192,13 @@
     }
 
     /**
-     * @return Elapsed time of CarPropertyValue since boot in nanoseconds
+     * Returns the timestamp in nanoseconds at which the CarPropertyValue happened. For a given car
+     * property, each new CarPropertyValue should be monotonically increasing using the same time
+     * base as {@link SystemClock#elapsedRealtimeNanos()}.
+     *
+     * <p>NOTE: Timestamp should be synchronized with other signals from the platform (e.g.
+     * {@link Location} and {@link SensorEvent} instances). Ideally, timestamp synchronization
+     * error should be below 1 millisecond.
      */
     public long getTimestamp() {
         return mTimestamp;
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index bd47263..4271756 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -108,7 +108,7 @@
         }
     }
 
-    /** Read ON_CHANGE sensors */
+    /** Read ONCHANGE sensors. */
     public static final float SENSOR_RATE_ONCHANGE = 0f;
     /** Read sensors at the rate of  1 hertz */
     public static final float SENSOR_RATE_NORMAL = 1f;
@@ -219,6 +219,9 @@
      *   <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}</li>
      *   <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}</li>
      * </ul>
+     * <b>Note:</b>If listener registers for updates for a
+     * {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE} property, it will receive the
+     * property's current value upon registration.
      * See {@link CarPropertyConfig#getChangeMode()} for details.
      * If rate is higher than {@link CarPropertyConfig#getMaxSampleRate()}, it will be registered
      * with max sample rate.
diff --git a/car-lib/src/android/car/watchdog/CarWatchdogManager.java b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
index da34344..aa930a0 100644
--- a/car-lib/src/android/car/watchdog/CarWatchdogManager.java
+++ b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
@@ -184,6 +184,8 @@
     @RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
     public void registerClient(@NonNull @CallbackExecutor Executor executor,
             @NonNull CarWatchdogClientCallback client, @TimeoutLengthEnum int timeout) {
+        Objects.requireNonNull(client, "Client must be non-null");
+        Objects.requireNonNull(executor, "Executor must be non-null");
         synchronized (mLock) {
             if (mRegisteredClient == client) {
                 return;
@@ -218,6 +220,7 @@
     @SystemApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
     public void unregisterClient(@NonNull CarWatchdogClientCallback client) {
+        Objects.requireNonNull(client, "Client must be non-null");
         synchronized (mLock) {
             if (mRegisteredClient != client) {
                 Log.w(TAG, "Cannot unregister the client. It has not been registered.");
@@ -249,6 +252,7 @@
     @SystemApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
     public void tellClientAlive(@NonNull CarWatchdogClientCallback client, int sessionId) {
+        Objects.requireNonNull(client, "Client must be non-null");
         boolean shouldReport;
         synchronized (mLock) {
             if (mRegisteredClient != client) {
diff --git a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
index 66485be..65a3fb1 100644
--- a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
+++ b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
@@ -94,6 +94,7 @@
 150126 car_user_svc_start_user_in_background_resp (user_id|1),(result|1)
 150127 car_user_svc_stop_user_req (user_id|1)
 150128 car_user_svc_stop_user_resp (user_id|1),(result|1)
+150129 car_user_svc_initial_user_info_req_complete (request_type|1)
 
 150140 car_user_hal_initial_user_info_req (request_id|1),(request_type|1),(timeout|1)
 150141 car_user_hal_initial_user_info_resp (request_id|1),(status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 9437d63..e236c7e 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -37,6 +37,11 @@
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
 
+    <!-- RemoteProvisioner app does not have any UI and will only be run as
+    a background service -->
+    <install-in-user-type package="com.android.remoteprovisioner">
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
 <!--
   Apps that need to run on SYSTEM and evaluated by package owner.
   Here the apps will have FULL and SYSTEM.
@@ -296,11 +301,18 @@
     <install-in-user-type package="com.android.certinstaller">
         <install-in user-type="FULL" />
     </install-in-user-type>
+    <!-- TODO(b/189246976) STOPSHIP Remove for SYSTEM user since this package
+    is needed for SYSTEM user only if the device supports feature_device_admin
+    and it's used by some device owner APIs-->
     <install-in-user-type package="com.android.pacprocessor">
         <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
     </install-in-user-type>
+    <!-- TODO(b/189246976) STOPSHIP Remove for SYSTEM user same as previous
+    package -->
     <install-in-user-type package="com.android.proxyhandler">
         <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
     </install-in-user-type>
     <install-in-user-type package="com.android.vpndialogs">
         <install-in user-type="FULL" />
diff --git a/car_product/rro/CarRotaryImeRRO/Android.bp b/car_product/rro/CarRotaryImeRRO/Android.bp
new file mode 100644
index 0000000..c9f85b9
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/Android.bp
@@ -0,0 +1,25 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+android_app {
+    name: "CarRotaryImeRRO",
+    resource_dirs: ["res"],
+    platform_apis: true,
+    aaptflags: [
+        "--no-resource-deduping",
+        "--no-resource-removal"
+    ],
+}
diff --git a/car_product/rro/CarRotaryImeRRO/AndroidManifest.xml b/car_product/rro/CarRotaryImeRRO/AndroidManifest.xml
new file mode 100644
index 0000000..ba83fce
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.rotary.ime.rro">
+    <application android:hasCode="false"/>
+    <overlay android:targetName="CarRotaryController"
+             android:targetPackage="com.android.car.rotary"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true" />
+</manifest>
diff --git a/car_product/rro/CarRotaryImeRRO/res/values/strings.xml b/car_product/rro/CarRotaryImeRRO/res/values/strings.xml
new file mode 100644
index 0000000..18a59cf
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+<resources>
+    <!-- Component name of rotary IME. Empty if none. Overlaid to use demo rotary IME. -->
+    <string name="rotary_input_method" translatable="false">com.android.car.rotaryime/.RotaryIme</string>
+</resources>
diff --git a/car_product/rro/CarRotaryImeRRO/res/xml/overlays.xml b/car_product/rro/CarRotaryImeRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..2b425a5
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/res/xml/overlays.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ 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.
+  -->
+
+<overlay>
+    <item target="string/rotary_input_method" value="@string/rotary_input_method"/>
+</overlay>
diff --git a/cpp/bugreport/main.cpp b/cpp/bugreport/main.cpp
index 783eaa8..e867144 100644
--- a/cpp/bugreport/main.cpp
+++ b/cpp/bugreport/main.cpp
@@ -18,7 +18,6 @@
 
 #include <android-base/errors.h>
 #include <android-base/file.h>
-#include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
@@ -131,7 +130,7 @@
 
         error = writer->StartEntry(name.c_str(), 0);
         if (error) {
-            ALOGE("Failed to start entry %s", writer->ErrorCodeString(error));
+            ALOGE("Failed to start entry: [%d] %s", error, writer->ErrorCodeString(error));
             return;
         }
         android::base::unique_fd fd(
@@ -157,7 +156,7 @@
             }
             error = writer->WriteBytes(buffer, bytes_read);
             if (error) {
-                ALOGE("WriteBytes() failed %s", ZipWriter::ErrorCodeString(error));
+                ALOGE("WriteBytes() failed: [%d] %s", error, ZipWriter::ErrorCodeString(error));
                 // fail immediately
                 return;
             }
@@ -165,13 +164,13 @@
 
         error = writer->FinishEntry();
         if (error) {
-            ALOGE("failed to finish entry %s", writer->ErrorCodeString(error));
+            ALOGW("failed to finish entry: [%d] %s", error, writer->ErrorCodeString(error));
             continue;
         }
     }
     error = writer->Finish();
     if (error) {
-        ALOGE("failed to finish zip writer %s", writer->ErrorCodeString(error));
+        ALOGW("Failed to finish zip writer to: [%d] %s", error, writer->ErrorCodeString(error));
     }
 }
 
@@ -386,12 +385,12 @@
     ALOGI("capturing screen for display (%s) as %s", id_as_string.c_str(), filename.c_str());
     int status = runCommand(10, "/system/bin/screencap", args);
     if (status == 0) {
-        LOG(INFO) << "Screenshot saved for display:" << id_as_string;
+        ALOGI("Screenshot saved for display: %s", id_as_string.c_str());
     }
     // add the file regardless of the exit status of the screencap util.
     extra_files->push_back(filename);
 
-    LOG(ERROR) << "Failed to take screenshot for display:" << id_as_string;
+    ALOGW("Failed to take screenshot for display: %s", id_as_string.c_str());
 }
 
 void takeScreenshot(const char* tmp_dir, std::vector<std::string>* extra_files) {
diff --git a/cpp/computepipe/aidl/Android.bp b/cpp/computepipe/aidl/Android.bp
index 0820223..2cf9ca1 100644
--- a/cpp/computepipe/aidl/Android.bp
+++ b/cpp/computepipe/aidl/Android.bp
@@ -10,7 +10,7 @@
         "android/automotive/computepipe/*.aidl",
     ],
     imports: [
-        "android.hardware.graphics.common",
+        "android.hardware.graphics.common-V2",
     ],
     stability: "vintf",
     backend: {
diff --git a/cpp/evs/apps/default/Android.bp b/cpp/evs/apps/default/Android.bp
index ea6feff..3b393e1 100644
--- a/cpp/evs/apps/default/Android.bp
+++ b/cpp/evs/apps/default/Android.bp
@@ -40,7 +40,7 @@
 
     shared_libs: [
         "libbase",
-        "libbinder",
+        "libbinder_ndk",
         "libcutils",
         "libutils",
         "libui",
diff --git a/cpp/evs/apps/default/EvsStateControl.cpp b/cpp/evs/apps/default/EvsStateControl.cpp
index 5552deb..e3d9757 100644
--- a/cpp/evs/apps/default/EvsStateControl.cpp
+++ b/cpp/evs/apps/default/EvsStateControl.cpp
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 #include "EvsStateControl.h"
-#include "RenderDirectView.h"
-#include "RenderTopView.h"
-#include "RenderPixelCopy.h"
-#include "FormatConvert.h"
 
-#include <stdio.h>
-#include <string.h>
+#include "FormatConvert.h"
+#include "RenderDirectView.h"
+#include "RenderPixelCopy.h"
+#include "RenderTopView.h"
 
 #include <android-base/logging.h>
-#include <inttypes.h>
+#include <android/binder_manager.h>
 #include <utils/SystemClock.h>
-#include <binder/IServiceManager.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
 
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
@@ -33,8 +34,7 @@
 using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
 
 static bool isSfReady() {
-    const android::String16 serviceName("SurfaceFlinger");
-    return android::defaultServiceManager()->checkService(serviceName) != nullptr;
+    return ::ndk::SpAIBinder(::AServiceManager_getService("SurfaceFlinger")).get() != nullptr;
 }
 
 // TODO:  Seems like it'd be nice if the Vehicle HAL provided such helpers (but how & where?)
diff --git a/cpp/evs/manager/1.1/HalCamera.cpp b/cpp/evs/manager/1.1/HalCamera.cpp
index c7018bf..e527840 100644
--- a/cpp/evs/manager/1.1/HalCamera.cpp
+++ b/cpp/evs/manager/1.1/HalCamera.cpp
@@ -488,7 +488,7 @@
 }
 
 
-Return<EvsResult> HalCamera::unsetMaster(sp<VirtualCamera> virtualCamera) {
+Return<EvsResult> HalCamera::unsetMaster(const VirtualCamera* virtualCamera) {
     if (mPrimaryClient.promote() != virtualCamera) {
         return EvsResult::INVALID_ARG;
     } else {
diff --git a/cpp/evs/manager/1.1/HalCamera.h b/cpp/evs/manager/1.1/HalCamera.h
index 57ceac2..1b05443 100644
--- a/cpp/evs/manager/1.1/HalCamera.h
+++ b/cpp/evs/manager/1.1/HalCamera.h
@@ -95,7 +95,7 @@
     Return<void>        doneWithFrame(const BufferDesc_1_1& buffer);
     Return<EvsResult>   setMaster(sp<VirtualCamera> virtualCamera);
     Return<EvsResult>   forceMaster(sp<VirtualCamera> virtualCamera);
-    Return<EvsResult>   unsetMaster(sp<VirtualCamera> virtualCamera);
+    Return<EvsResult>   unsetMaster(const VirtualCamera* virtualCamera);
     Return<EvsResult>   setParameter(sp<VirtualCamera> virtualCamera,
                                      CameraParam id, int32_t& value);
     Return<EvsResult>   getParameter(CameraParam id, int32_t& value);
diff --git a/cpp/evs/manager/1.1/test/fuzzer/Android.bp b/cpp/evs/manager/1.1/test/fuzzer/Android.bp
index 3ac8924..aa2bc88 100644
--- a/cpp/evs/manager/1.1/test/fuzzer/Android.bp
+++ b/cpp/evs/manager/1.1/test/fuzzer/Android.bp
@@ -49,6 +49,7 @@
     fuzz_config: {
         cc: [
             "changyeon@google.com",
+            "garysungang@google.com",
             "guodonghu@google.com",
             "smara@google.com",
             "zhaomingyin@google.com",
diff --git a/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp b/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
index a528ff7..9ecc6e0 100644
--- a/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
+++ b/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
@@ -188,7 +188,7 @@
                 if (!virtualCameras.empty()) {
                     uint32_t whichCam =
                             fdp.ConsumeIntegralInRange<uint32_t>(0, virtualCameras.size() - 1);
-                    halCamera->unsetMaster(virtualCameras[whichCam]);
+                    halCamera->unsetMaster(virtualCameras[whichCam].get());
                 }
                 break;
             }
diff --git a/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te b/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te
index 93a6760..a7184ab 100644
--- a/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te
+++ b/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te
@@ -16,3 +16,6 @@
 
 # Configuration for carpowerpolicyd to check car_service.
 allow carpowerpolicyd carservice_service:service_manager find;
+
+# Allow reading and writing /sys/power/
+allow carpowerpolicyd sysfs_power:file rw_file_perms;
diff --git a/cpp/telemetry/script_executor/Android.bp b/cpp/telemetry/script_executor/Android.bp
index 734d4dd..78b639a 100644
--- a/cpp/telemetry/script_executor/Android.bp
+++ b/cpp/telemetry/script_executor/Android.bp
@@ -16,13 +16,47 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library {
-   name: "script_executor",
-   srcs: [
-       "src/LuaEngine.cpp",
-   ],
-   static_libs: [
-       "liblua",
-   ],
+cc_defaults {
+    name: "scriptexecutor_defaults",
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+    static_libs: [
+        "libbase",
+        "liblog",
+        "liblua",
+    ],
 }
 
+cc_library {
+    name: "libscriptexecutor",
+    defaults: [
+        "scriptexecutor_defaults",
+    ],
+    srcs: [
+        "src/JniUtils.cpp",
+        "src/LuaEngine.cpp",
+        "src/ScriptExecutorListener.cpp",
+    ],
+    shared_libs: [
+        "libnativehelper",
+    ],
+    // Allow dependents to use the header files.
+    export_include_dirs: [
+        "src",
+    ],
+}
+
+cc_library_shared {
+    name: "libscriptexecutorjniutils-test",
+    defaults: [
+        "scriptexecutor_defaults",
+    ],
+    srcs: [
+        "src/tests/JniUtilsTestHelper.cpp",
+    ],
+    shared_libs: [
+        "libnativehelper",
+        "libscriptexecutor",
+    ],
+}
diff --git a/cpp/telemetry/script_executor/src/JniUtils.cpp b/cpp/telemetry/script_executor/src/JniUtils.cpp
new file mode 100644
index 0000000..93c1af8
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/JniUtils.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#include "JniUtils.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
+    lua_newtable(luaEngine->GetLuaState());
+    // null bundle object is allowed. We will treat it as an empty table.
+    if (bundle == nullptr) {
+        return;
+    }
+
+    // TODO(b/188832769): Consider caching some of these JNI references for
+    // performance reasons.
+    jclass bundleClass = env->FindClass("android/os/Bundle");
+    jmethodID getKeySetMethod = env->GetMethodID(bundleClass, "keySet", "()Ljava/util/Set;");
+    jobject keys = env->CallObjectMethod(bundle, getKeySetMethod);
+    jclass setClass = env->FindClass("java/util/Set");
+    jmethodID iteratorMethod = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
+    jobject keySetIteratorObject = env->CallObjectMethod(keys, iteratorMethod);
+
+    jclass iteratorClass = env->FindClass("java/util/Iterator");
+    jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+    jmethodID nextMethod = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+
+    jclass booleanClass = env->FindClass("java/lang/Boolean");
+    jclass integerClass = env->FindClass("java/lang/Integer");
+    jclass numberClass = env->FindClass("java/lang/Number");
+    jclass stringClass = env->FindClass("java/lang/String");
+    // TODO(b/188816922): Handle more types such as float and integer arrays,
+    // and perhaps nested Bundles.
+
+    jmethodID getMethod =
+            env->GetMethodID(bundleClass, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
+
+    // Iterate over key set of the bundle one key at a time.
+    while (env->CallBooleanMethod(keySetIteratorObject, hasNextMethod)) {
+        // Read the value object that corresponds to this key.
+        jstring key = (jstring)env->CallObjectMethod(keySetIteratorObject, nextMethod);
+        jobject value = env->CallObjectMethod(bundle, getMethod, key);
+
+        // Get the value of the type, extract it accordingly from the bundle and
+        // push the extracted value and the key to the Lua table.
+        if (env->IsInstanceOf(value, booleanClass)) {
+            jmethodID boolMethod = env->GetMethodID(booleanClass, "booleanValue", "()Z");
+            bool boolValue = static_cast<bool>(env->CallBooleanMethod(value, boolMethod));
+            lua_pushboolean(luaEngine->GetLuaState(), boolValue);
+        } else if (env->IsInstanceOf(value, integerClass)) {
+            jmethodID intMethod = env->GetMethodID(integerClass, "intValue", "()I");
+            lua_pushinteger(luaEngine->GetLuaState(), env->CallIntMethod(value, intMethod));
+        } else if (env->IsInstanceOf(value, numberClass)) {
+            // Condense other numeric types using one class. Because lua supports only
+            // integer or double, and we handled integer in previous if clause.
+            jmethodID numberMethod = env->GetMethodID(numberClass, "doubleValue", "()D");
+            /* Pushes a double onto the stack */
+            lua_pushnumber(luaEngine->GetLuaState(), env->CallDoubleMethod(value, numberMethod));
+        } else if (env->IsInstanceOf(value, stringClass)) {
+            const char* rawStringValue = env->GetStringUTFChars((jstring)value, nullptr);
+            lua_pushstring(luaEngine->GetLuaState(), rawStringValue);
+            env->ReleaseStringUTFChars((jstring)value, rawStringValue);
+        } else {
+            // Other types are not implemented yet, skipping.
+            continue;
+        }
+
+        const char* rawKey = env->GetStringUTFChars(key, nullptr);
+        // table[rawKey] = value, where value is on top of the stack,
+        // and the table is the next element in the stack.
+        lua_setfield(luaEngine->GetLuaState(), /* idx= */ -2, rawKey);
+        env->ReleaseStringUTFChars(key, rawKey);
+    }
+}
+
+}  // namespace script_executor
+}  // namespace telemetry
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/telemetry/script_executor/src/JniUtils.h b/cpp/telemetry/script_executor/src/JniUtils.h
new file mode 100644
index 0000000..c3ef677
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/JniUtils.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+#ifndef CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
+#define CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
+
+#include "LuaEngine.h"
+#include "jni.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+// 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
+// the Bundle value types are supported. At this point, we support boolean,
+// integer, double and String types in Java.
+void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle);
+
+}  // namespace script_executor
+}  // namespace telemetry
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.cpp b/cpp/telemetry/script_executor/src/LuaEngine.cpp
index a8cace3..cc1d0b8 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.cpp
+++ b/cpp/telemetry/script_executor/src/LuaEngine.cpp
@@ -28,8 +28,7 @@
 namespace telemetry {
 namespace script_executor {
 
-LuaEngine::LuaEngine(std::unique_ptr<ScriptExecutorListener> listener) :
-      mListener(std::move(listener)) {
+LuaEngine::LuaEngine() {
     mLuaState = luaL_newstate();
     luaL_openlibs(mLuaState);
 }
@@ -38,6 +37,10 @@
     lua_close(mLuaState);
 }
 
+lua_State* LuaEngine::GetLuaState() {
+    return mLuaState;
+}
+
 }  // namespace script_executor
 }  // namespace telemetry
 }  // namespace automotive
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.h b/cpp/telemetry/script_executor/src/LuaEngine.h
index 086dbfe..a0f3978 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.h
+++ b/cpp/telemetry/script_executor/src/LuaEngine.h
@@ -33,14 +33,15 @@
 // Encapsulates Lua script execution environment.
 class LuaEngine {
 public:
-    explicit LuaEngine(std::unique_ptr<ScriptExecutorListener> listener);
+    LuaEngine();
 
     virtual ~LuaEngine();
 
+    // Returns pointer to Lua state object.
+    lua_State* GetLuaState();
+
 private:
     lua_State* mLuaState;  // owned
-
-    std::unique_ptr<ScriptExecutorListener> mListener;
 };
 
 }  // namespace script_executor
diff --git a/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
new file mode 100644
index 0000000..9e2c43a
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#include "JniUtils.h"
+#include "LuaEngine.h"
+#include "jni.h"
+
+#include <cstdint>
+#include <cstring>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+namespace {
+
+extern "C" {
+
+#include "lua.h"
+
+JNIEXPORT jlong JNICALL
+Java_com_android_car_telemetry_JniUtilsTest_nativeCreateLuaEngine(JNIEnv* env, jobject object) {
+    // Cast first to intptr_t to ensure int can hold the pointer without loss.
+    return static_cast<jlong>(reinterpret_cast<intptr_t>(new LuaEngine()));
+}
+
+JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeDestroyLuaEngine(
+        JNIEnv* env, jobject object, jlong luaEnginePtr) {
+    delete reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+}
+
+JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativePushBundleToLuaTableCaller(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jobject bundle) {
+    PushBundleToLuaTable(env, reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr)),
+                         bundle);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeGetObjectSize(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jint index) {
+    LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+    return lua_rawlen(engine->GetLuaState(), static_cast<int>(index));
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasBooleanValue(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jboolean value) {
+    const char* rawKey = env->GetStringUTFChars(key, nullptr);
+    LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+    auto* luaState = engine->GetLuaState();
+    lua_pushstring(luaState, rawKey);
+    env->ReleaseStringUTFChars(key, rawKey);
+    lua_gettable(luaState, -2);
+    bool result = false;
+    if (!lua_isboolean(luaState, -1))
+        result = false;
+    else
+        result = static_cast<bool>(lua_toboolean(luaState, -1)) == static_cast<bool>(value);
+    lua_pop(luaState, 1);
+    return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasIntValue(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jint value) {
+    const char* rawKey = env->GetStringUTFChars(key, nullptr);
+    LuaEngine* engine = reinterpret_cast<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_isinteger(luaState, -1))
+        result = false;
+    else
+        result = lua_tointeger(luaState, -1) == static_cast<int>(value);
+    lua_pop(luaState, 1);
+    return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasDoubleValue(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jdouble value) {
+    const char* rawKey = env->GetStringUTFChars(key, nullptr);
+    LuaEngine* engine = reinterpret_cast<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_isnumber(luaState, -1))
+        result = false;
+    else
+        result = static_cast<double>(lua_tonumber(luaState, -1)) == static_cast<double>(value);
+    lua_pop(luaState, 1);
+    return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasStringValue(
+        JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jstring value) {
+    const char* rawKey = env->GetStringUTFChars(key, nullptr);
+    LuaEngine* engine = reinterpret_cast<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_isstring(luaState, -1)) {
+        result = false;
+    } else {
+        std::string s = lua_tostring(luaState, -1);
+        const char* rawValue = env->GetStringUTFChars(value, nullptr);
+        result = strcmp(lua_tostring(luaState, -1), rawValue) == 0;
+        env->ReleaseStringUTFChars(value, rawValue);
+    }
+    lua_pop(luaState, 1);
+    return result;
+}
+
+}  //  extern "C"
+
+}  //  namespace
+}  //  namespace script_executor
+}  //  namespace telemetry
+}  //  namespace automotive
+}  //  namespace android
diff --git a/cpp/watchdog/aidl/Android.bp b/cpp/watchdog/aidl/Android.bp
index 88b056a..ee13520 100644
--- a/cpp/watchdog/aidl/Android.bp
+++ b/cpp/watchdog/aidl/Android.bp
@@ -31,6 +31,7 @@
     },
     versions: [
         "2",
+        "3",
     ],
 }
 
@@ -48,6 +49,6 @@
         },
     },
     imports: [
-        "android.automotive.watchdog",
+        "android.automotive.watchdog-V3",
     ],
 }
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/.hash b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/.hash
new file mode 100644
index 0000000..1c3bcca
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/.hash
@@ -0,0 +1 @@
+7012931db08df47dbc9d06d9864dbe9d511d7062
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/BootPhase.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/BootPhase.aidl
new file mode 100644
index 0000000..6c260a0
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/BootPhase.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum BootPhase {
+  BOOT_COMPLETED = 1000,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdog.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdog.aidl
new file mode 100644
index 0000000..d7c9255
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdog.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdog {
+  void registerClient(in android.automotive.watchdog.ICarWatchdogClient client, in android.automotive.watchdog.TimeoutLength timeout);
+  void unregisterClient(in android.automotive.watchdog.ICarWatchdogClient client);
+  /**
+   * @deprecated Calling this API will result in unsupported operation binder error.
+   */
+  void registerMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  /**
+   * @deprecated Calling this API will result in unsupported operation binder error.
+   */
+  void unregisterMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  /**
+   * @deprecated Calling this API will result in unsupported operation binder error.
+   */
+  void registerMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  /**
+   * @deprecated Calling this API will result in unsupported operation binder error.
+   */
+  void unregisterMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  void tellClientAlive(in android.automotive.watchdog.ICarWatchdogClient client, in int sessionId);
+  /**
+   * @deprecated Calling this API will result in unsupported operation binder error.
+   */
+  void tellMediatorAlive(in android.automotive.watchdog.ICarWatchdogClient mediator, in int[] clientsNotResponding, in int sessionId);
+  /**
+   * @deprecated Calling this API will result in unsupported operation binder error.
+   */
+  void tellDumpFinished(in android.automotive.watchdog.ICarWatchdogMonitor monitor, in int pid);
+  /**
+   * @deprecated Calling this API will result in unsupported operation binder error.
+   */
+  void notifySystemStateChange(in android.automotive.watchdog.StateType type, in int arg1, in int arg2);
+  void addResourceOveruseListener(in android.automotive.watchdog.ResourceType[] resourceTypes, in android.automotive.watchdog.IResourceOveruseListener listener);
+  void removeResourceOveruseListener(in android.automotive.watchdog.IResourceOveruseListener listener);
+  List<android.automotive.watchdog.ResourceOveruseStats> getResourceOveruseStats(in android.automotive.watchdog.ResourceType[] resourceTypes);
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogClient.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogClient.aidl
new file mode 100644
index 0000000..a4a356d
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogClient.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogClient {
+  oneway void checkIfAlive(in int sessionId, in android.automotive.watchdog.TimeoutLength timeout);
+  oneway void prepareProcessTermination();
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogMonitor.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogMonitor.aidl
new file mode 100644
index 0000000..ba196dc
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogMonitor.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@VintfStability
+interface ICarWatchdogMonitor {
+  oneway void onClientsNotResponding(in int[] pids);
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IResourceOveruseListener.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IResourceOveruseListener.aidl
new file mode 100644
index 0000000..a743cd0
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IResourceOveruseListener.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface IResourceOveruseListener {
+  oneway void onOveruse(in android.automotive.watchdog.ResourceOveruseStats resourceOveruseStats);
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IoOveruseStats.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IoOveruseStats.aidl
new file mode 100644
index 0000000..698617c
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IoOveruseStats.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+parcelable IoOveruseStats {
+  boolean killableOnOveruse;
+  android.automotive.watchdog.PerStateBytes remainingWriteBytes;
+  long startTime;
+  long durationInSeconds;
+  android.automotive.watchdog.PerStateBytes writtenBytes;
+  int totalOveruses;
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PerStateBytes.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PerStateBytes.aidl
new file mode 100644
index 0000000..a933421
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PerStateBytes.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+parcelable PerStateBytes {
+  long foregroundBytes;
+  long backgroundBytes;
+  long garageModeBytes;
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PowerCycle.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PowerCycle.aidl
new file mode 100644
index 0000000..1729027
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PowerCycle.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum PowerCycle {
+  POWER_CYCLE_SHUTDOWN = 0,
+  POWER_CYCLE_SUSPEND = 1,
+  POWER_CYCLE_RESUME = 2,
+  NUM_POWER_CYLES = 3,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceOveruseStats.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceOveruseStats.aidl
new file mode 100644
index 0000000..3715025
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceOveruseStats.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+union ResourceOveruseStats {
+  android.automotive.watchdog.IoOveruseStats ioOveruseStats;
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceType.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceType.aidl
new file mode 100644
index 0000000..8551e13
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceType.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum ResourceType {
+  IO = 0,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/StateType.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/StateType.aidl
new file mode 100644
index 0000000..75a7ea1
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/StateType.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum StateType {
+  POWER_CYCLE = 0,
+  USER_STATE = 1,
+  BOOT_PHASE = 2,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/TimeoutLength.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/TimeoutLength.aidl
new file mode 100644
index 0000000..c109f96
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/TimeoutLength.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum TimeoutLength {
+  TIMEOUT_CRITICAL = 0,
+  TIMEOUT_MODERATE = 1,
+  TIMEOUT_NORMAL = 2,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/UserState.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/UserState.aidl
new file mode 100644
index 0000000..cd25321
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/UserState.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum UserState {
+  USER_STATE_STARTED = 0,
+  USER_STATE_STOPPED = 1,
+  NUM_USER_STATES = 2,
+}
diff --git a/cpp/watchdog/server/Android.bp b/cpp/watchdog/server/Android.bp
index a0d85b8..9b5b973 100644
--- a/cpp/watchdog/server/Android.bp
+++ b/cpp/watchdog/server/Android.bp
@@ -66,6 +66,7 @@
     shared_libs: [
         "libcutils",
         "libprocessgroup",
+        "libtinyxml2",
         "libwatchdog_package_info_resolver",
     ],
 }
@@ -82,6 +83,7 @@
         "src/IoOveruseMonitor.cpp",
         "src/IoPerfCollection.cpp",
         "src/LooperWrapper.cpp",
+        "src/OveruseConfigurationXmlHelper.cpp",
         "src/ProcDiskStats.cpp",
         "src/ProcPidStat.cpp",
         "src/ProcStat.cpp",
@@ -95,6 +97,13 @@
     ],
 }
 
+filegroup {
+    name: "watchdog_test_xml_files",
+    srcs: [
+        "tests/data/*.xml",
+    ],
+}
+
 cc_test {
     name: "libwatchdog_test",
     defaults: [
@@ -108,6 +117,8 @@
         "tests/IoOveruseMonitorTest.cpp",
         "tests/IoPerfCollectionTest.cpp",
         "tests/LooperStub.cpp",
+        "tests/OveruseConfigurationTestUtils.cpp",
+        "tests/OveruseConfigurationXmlHelperTest.cpp",
         "tests/PackageInfoResolverTest.cpp",
         "tests/ProcDiskStatsTest.cpp",
         "tests/ProcPidDir.cpp",
@@ -128,6 +139,7 @@
         "libwatchdog_process_service",
         "libwatchdog_package_info_resolver",
     ],
+    data: [":watchdog_test_xml_files"],
 }
 
 cc_defaults {
diff --git a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp
new file mode 100644
index 0000000..f76bcc5
--- /dev/null
+++ b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp
@@ -0,0 +1,474 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "OveruseConfigurationXmlHelper.h"
+
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android/automotive/watchdog/PerStateBytes.h>
+#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <android/automotive/watchdog/internal/ComponentType.h>
+#include <android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
+#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
+#include <android/automotive/watchdog/internal/PackageMetadata.h>
+#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
+#include <android/automotive/watchdog/internal/ResourceSpecificConfiguration.h>
+
+#include <tinyxml2.h>
+
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::automotive::watchdog::PerStateBytes;
+using ::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::android::automotive::watchdog::internal::ComponentType;
+using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
+using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::android::automotive::watchdog::internal::PackageMetadata;
+using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::android::base::EqualsIgnoreCase;
+using ::android::base::Error;
+using ::android::base::Join;
+using ::android::base::ParseInt;
+using ::android::base::Result;
+using ::android::base::StartsWith;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::Trim;
+using ::android::binder::Status;
+using ::tinyxml2::XML_SUCCESS;
+using ::tinyxml2::XMLDocument;
+using ::tinyxml2::XMLElement;
+
+namespace {
+constexpr const char kTagResourceOveruseConfiguration[] = "resourceOveruseConfiguration";
+constexpr const char kTagComponentType[] = "componentType";
+
+constexpr const char kTagSafeToKillPackages[] = "safeToKillPackages";
+constexpr const char kTagPackage[] = "package";
+
+constexpr const char kTagVendorPackagePrefixes[] = "vendorPackagePrefixes";
+constexpr const char kTagPackagePrefix[] = "packagePrefix";
+
+constexpr const char kTagPackageToAppCategoryTypes[] = "packagesToAppCategoryTypes";
+constexpr const char kTagPackageAppCategory[] = "packageAppCategory";
+
+constexpr const char kTagIoOveruseConfiguration[] = "ioOveruseConfiguration";
+constexpr const char kTagComponentLevelThresholds[] = "componentLevelThresholds";
+constexpr const char kTagPackageSpecificThresholds[] = "packageSpecificThresholds";
+constexpr const char kTagState[] = "state";
+constexpr const char kStateIdForegroundMode[] = "foreground_mode";
+constexpr const char kStateIdBackgroundMode[] = "background_mode";
+constexpr const char kStateIdGarageMode[] = "garage_mode";
+constexpr int kNumStates = 3;
+
+constexpr const char kTagAppCategorySpecificThresholds[] = "appCategorySpecificThresholds";
+constexpr const char kTagAppCategoryThreshold[] = "appCategoryThreshold";
+
+constexpr const char kTagSystemWideThresholds[] = "systemWideThresholds";
+constexpr const char kTagParam[] = "param";
+constexpr const char kParamIdDurationSeconds[] = "duration_seconds";
+constexpr const char kParamIdWrittenBytesPerSecond[] = "written_bytes_per_second";
+constexpr int kNumParams = 2;
+
+constexpr const char kAttrId[] = "id";
+constexpr const char kAttrType[] = "type";
+
+Result<const XMLElement*> readExactlyOneElement(const char* tag, const XMLElement* rootElement) {
+    const XMLElement* element = rootElement->FirstChildElement(tag);
+    if (element == nullptr) {
+        return Error() << "Must specify value for the tag '" << tag << "'";
+    }
+    if (element->NextSiblingElement(tag) != nullptr) {
+        return Error() << "Must specify only one entry for the tag '" << tag << "'";
+    }
+    return element;
+}
+
+Result<ComponentType> readComponentType(const XMLElement* rootElement) {
+    const XMLElement* componentTypeElement;
+    if (const auto result = readExactlyOneElement(kTagComponentType, rootElement); result.ok()) {
+        componentTypeElement = *result;
+    } else {
+        return Error() << "Failed to read tag '" << kTagComponentType << "': " << result.error();
+    }
+    std::string componentTypeStr;
+    if (const auto text = componentTypeElement->GetText(); text == nullptr) {
+        return Error() << "Must specify non-empty component type";
+    } else if (componentTypeStr = Trim(text); componentTypeStr.empty()) {
+        return Error() << "Must specify non-empty component type";
+    }
+    static const std::string* const kSystemComponent =
+            new std::string(toString(ComponentType::SYSTEM));
+    static const std::string* const kVendorComponent =
+            new std::string(toString(ComponentType::VENDOR));
+    static const std::string* const kThirdPartyComponent =
+            new std::string(toString(ComponentType::THIRD_PARTY));
+    if (EqualsIgnoreCase(componentTypeStr, *kSystemComponent)) {
+        return ComponentType::SYSTEM;
+    } else if (EqualsIgnoreCase(componentTypeStr, *kVendorComponent)) {
+        return ComponentType::VENDOR;
+    } else if (EqualsIgnoreCase(componentTypeStr, *kThirdPartyComponent)) {
+        return ComponentType::THIRD_PARTY;
+    }
+    return Error() << "Must specify valid component type. Received " << componentTypeStr;
+}
+
+Result<std::vector<std::string>> readSafeToKillPackages(const XMLElement* rootElement) {
+    std::vector<std::string> safeToKillPackages;
+    for (const XMLElement* outerElement = rootElement->FirstChildElement(kTagSafeToKillPackages);
+         outerElement != nullptr;
+         outerElement = outerElement->NextSiblingElement(kTagSafeToKillPackages)) {
+        for (const XMLElement* innerElement = outerElement->FirstChildElement(kTagPackage);
+             innerElement != nullptr;
+             innerElement = innerElement->NextSiblingElement(kTagPackage)) {
+            std::string packageName;
+            if (const auto text = innerElement->GetText(); text == nullptr) {
+                return Error() << "Must specify non-empty safe-to-kill package name";
+            } else if (packageName = Trim(text); packageName.empty()) {
+                return Error() << "Must specify non-empty safe-to-kill package name";
+            }
+            safeToKillPackages.push_back(std::string(packageName));
+        }
+    }
+    return safeToKillPackages;
+}
+
+Result<std::vector<std::string>> readVendorPackagePrefixes(const XMLElement* rootElement) {
+    std::vector<std::string> vendorPackagePrefixes;
+    for (const XMLElement* outerElement = rootElement->FirstChildElement(kTagVendorPackagePrefixes);
+         outerElement != nullptr;
+         outerElement = outerElement->NextSiblingElement(kTagVendorPackagePrefixes)) {
+        for (const XMLElement* innerElement = outerElement->FirstChildElement(kTagPackagePrefix);
+             innerElement != nullptr;
+             innerElement = innerElement->NextSiblingElement(kTagPackagePrefix)) {
+            std::string packagePrefix;
+            if (const auto text = innerElement->GetText(); text == nullptr) {
+                return Error() << "Must specify non-empty vendor package prefix";
+            } else if (packagePrefix = Trim(text); packagePrefix.empty()) {
+                return Error() << "Must specify non-empty vendor package prefix";
+            }
+            vendorPackagePrefixes.push_back(std::string(packagePrefix));
+        }
+    }
+    return vendorPackagePrefixes;
+}
+
+ApplicationCategoryType toApplicationCategoryType(std::string_view value) {
+    static const std::string* const kMapsAppCategory =
+            new std::string(toString(ApplicationCategoryType::MAPS));
+    static const std::string* const kMediaAppCategory =
+            new std::string(toString(ApplicationCategoryType::MEDIA));
+    if (EqualsIgnoreCase(value, *kMapsAppCategory)) {
+        return ApplicationCategoryType::MAPS;
+    } else if (EqualsIgnoreCase(value, *kMediaAppCategory)) {
+        return ApplicationCategoryType::MEDIA;
+    }
+    return ApplicationCategoryType::OTHERS;
+}
+
+Result<std::vector<PackageMetadata>> readPackageToAppCategoryTypes(const XMLElement* rootElement) {
+    std::vector<PackageMetadata> packageMetadata;
+    for (const XMLElement* outerElement =
+                 rootElement->FirstChildElement(kTagPackageToAppCategoryTypes);
+         outerElement != nullptr;
+         outerElement = outerElement->NextSiblingElement(kTagPackageToAppCategoryTypes)) {
+        for (const XMLElement* innerElement =
+                     outerElement->FirstChildElement(kTagPackageAppCategory);
+             innerElement != nullptr;
+             innerElement = innerElement->NextSiblingElement(kTagPackageAppCategory)) {
+            const char* type = nullptr;
+            if (innerElement->QueryStringAttribute(kAttrType, &type) != XML_SUCCESS) {
+                return Error() << "Failed to read '" << kAttrType << "' attribute in '"
+                               << kTagPackageAppCategory << "' tag";
+            }
+            PackageMetadata meta;
+            if (meta.appCategoryType = toApplicationCategoryType(type);
+                meta.appCategoryType == ApplicationCategoryType::OTHERS) {
+                return Error() << "Must specify valid app category type. Received " << type;
+            }
+            if (const auto text = innerElement->GetText(); text == nullptr) {
+                return Error() << "Must specify non-empty package name";
+            } else if (meta.packageName = Trim(text); meta.packageName.empty()) {
+                return Error() << "Must specify non-empty package name";
+            }
+            packageMetadata.push_back(meta);
+        }
+    }
+    return packageMetadata;
+}
+
+Result<PerStateBytes> readPerStateBytes(const XMLElement* rootElement) {
+    PerStateBytes perStateBytes;
+    std::unordered_set<std::string> seenStates;
+    for (const XMLElement* childElement = rootElement->FirstChildElement(kTagState);
+         childElement != nullptr; childElement = childElement->NextSiblingElement(kTagState)) {
+        const char* state = nullptr;
+        if (childElement->QueryStringAttribute(kAttrId, &state) != XML_SUCCESS) {
+            return Error() << "Failed to read '" << kAttrId << "' attribute in '" << kTagState
+                           << "' tag";
+        }
+        if (seenStates.find(state) != seenStates.end()) {
+            return Error() << "Duplicate threshold specified for state '" << state << "'";
+        }
+        int64_t bytes = 0;
+        if (const auto text = childElement->GetText(); text == nullptr) {
+            return Error() << "Must specify non-empty threshold for state '" << state << "'";
+        } else if (const auto bytesStr = Trim(text); !ParseInt(bytesStr.c_str(), &bytes)) {
+            return Error() << "Failed to parse threshold for the state '" << state
+                           << "': Received threshold value '" << bytesStr << "'";
+        }
+        if (!strcmp(state, kStateIdForegroundMode)) {
+            seenStates.insert(kStateIdForegroundMode);
+            perStateBytes.foregroundBytes = bytes;
+        } else if (!strcmp(state, kStateIdBackgroundMode)) {
+            seenStates.insert(kStateIdBackgroundMode);
+            perStateBytes.backgroundBytes = bytes;
+        } else if (!strcmp(state, kStateIdGarageMode)) {
+            seenStates.insert(kStateIdGarageMode);
+            perStateBytes.garageModeBytes = bytes;
+        } else {
+            return Error() << "Invalid state '" << state << "' in per-state bytes";
+        }
+    }
+    if (seenStates.size() != kNumStates) {
+        return Error() << "Thresholds not specified for all states. Specified only for ["
+                       << Join(seenStates, ", ") << "] states";
+    }
+    return perStateBytes;
+}
+
+Result<PerStateIoOveruseThreshold> readComponentLevelThresholds(ComponentType componentType,
+                                                                const XMLElement* rootElement) {
+    const XMLElement* componentLevelThresholdElement = nullptr;
+    if (const auto result = readExactlyOneElement(kTagComponentLevelThresholds, rootElement);
+        result.ok()) {
+        componentLevelThresholdElement = *result;
+    } else {
+        return Error() << "Failed to read tag '" << kTagComponentLevelThresholds
+                       << "': " << result.error();
+    }
+    PerStateIoOveruseThreshold thresholds;
+    thresholds.name = toString(componentType);
+    if (const auto result = readPerStateBytes(componentLevelThresholdElement); result.ok()) {
+        thresholds.perStateWriteBytes = *result;
+    } else {
+        return Error() << "Failed to read component level thresholds for component '"
+                       << thresholds.name << "': " << result.error();
+    }
+    return thresholds;
+}
+
+Result<std::vector<PerStateIoOveruseThreshold>> readPackageSpecificThresholds(
+        const XMLElement* rootElement) {
+    std::vector<PerStateIoOveruseThreshold> thresholds;
+    for (const XMLElement* childElement =
+                 rootElement->FirstChildElement(kTagPackageSpecificThresholds);
+         childElement != nullptr;
+         childElement = childElement->NextSiblingElement(kTagPackageSpecificThresholds)) {
+        PerStateIoOveruseThreshold threshold;
+        if (const char* name = nullptr;
+            childElement->QueryStringAttribute(kAttrId, &name) != XML_SUCCESS) {
+            return Error() << "Failed to read '" << kAttrId << "' attribute in '"
+                           << kTagPackageSpecificThresholds << "' tag";
+        } else if (threshold.name = name; threshold.name.empty()) {
+            return Error() << "Must provide non-empty package name in '" << kAttrId
+                           << "attribute in '" << kTagPackageSpecificThresholds << "' tag";
+        }
+        if (const auto result = readPerStateBytes(childElement); result.ok()) {
+            threshold.perStateWriteBytes = *result;
+        } else {
+            return Error() << "Failed to read package specific thresholds for package '"
+                           << threshold.name << "': " << result.error();
+        }
+        thresholds.push_back(threshold);
+    }
+    return thresholds;
+}
+
+Result<std::vector<PerStateIoOveruseThreshold>> readAppCategorySpecificThresholds(
+        const XMLElement* rootElement) {
+    std::vector<PerStateIoOveruseThreshold> thresholds;
+    for (const XMLElement* outerElement =
+                 rootElement->FirstChildElement(kTagAppCategorySpecificThresholds);
+         outerElement != nullptr;
+         outerElement = outerElement->NextSiblingElement(kTagAppCategorySpecificThresholds)) {
+        for (const XMLElement* innerElement =
+                     outerElement->FirstChildElement(kTagAppCategoryThreshold);
+             innerElement != nullptr;
+             innerElement = innerElement->NextSiblingElement(kTagAppCategoryThreshold)) {
+            const char* name = nullptr;
+            if (innerElement->QueryStringAttribute(kAttrId, &name) != XML_SUCCESS) {
+                return Error() << "Failed to read '" << kAttrId << "' attribute in '"
+                               << kTagAppCategoryThreshold << "' tag";
+            }
+            PerStateIoOveruseThreshold threshold;
+            threshold.name = name;
+            if (const auto result = readPerStateBytes(innerElement); result.ok()) {
+                threshold.perStateWriteBytes = *result;
+            } else {
+                return Error() << "Failed to read app category specific thresholds for application "
+                               << "category '" << threshold.name << "': " << result.error();
+            }
+            thresholds.push_back(threshold);
+        }
+    }
+    return thresholds;
+}
+
+Result<std::vector<IoOveruseAlertThreshold>> readSystemWideThresholds(
+        const XMLElement* rootElement) {
+    std::vector<IoOveruseAlertThreshold> alertThresholds;
+    for (const XMLElement* outerElement = rootElement->FirstChildElement(kTagSystemWideThresholds);
+         outerElement != nullptr;
+         outerElement = outerElement->NextSiblingElement(kTagSystemWideThresholds)) {
+        IoOveruseAlertThreshold alertThreshold;
+        std::unordered_set<std::string> seenParams;
+        for (const XMLElement* innerElement = outerElement->FirstChildElement(kTagParam);
+             innerElement != nullptr; innerElement = innerElement->NextSiblingElement(kTagParam)) {
+            const char* param = nullptr;
+            if (innerElement->QueryStringAttribute(kAttrId, &param) != XML_SUCCESS) {
+                return Error() << "Failed to read '" << kAttrId << "' attribute in '" << kTagParam
+                               << "' tag";
+            }
+            if (seenParams.find(param) != seenParams.end()) {
+                return Error() << "Duplicate threshold specified for param '" << param << "'";
+            }
+            int64_t value = 0;
+            if (const auto text = innerElement->GetText(); text == nullptr) {
+                return Error() << "Must specify non-empty threshold for param '" << param << "'";
+            } else if (const auto valueStr = Trim(text); !ParseInt(valueStr.c_str(), &value)) {
+                return Error() << "Failed to parse threshold for the param '" << param
+                               << "': Received threshold value '" << valueStr << "'";
+            }
+            if (!strcmp(param, kParamIdDurationSeconds)) {
+                seenParams.insert(kParamIdDurationSeconds);
+                alertThreshold.durationInSeconds = value;
+            } else if (!strcmp(param, kParamIdWrittenBytesPerSecond)) {
+                seenParams.insert(kParamIdWrittenBytesPerSecond);
+                alertThreshold.writtenBytesPerSecond = value;
+            } else {
+                return Error() << "Invalid param '" << param << "' in I/O overuse alert thresholds";
+            }
+        }
+        if (seenParams.size() != kNumParams) {
+            return Error() << "Thresholds not specified for all params. Specified only for ["
+                           << Join(seenParams, ", ") << "] params";
+        }
+        alertThresholds.push_back(alertThreshold);
+    }
+    return alertThresholds;
+}
+
+Result<IoOveruseConfiguration> readIoOveruseConfiguration(ComponentType componentType,
+                                                          const XMLElement* rootElement) {
+    const XMLElement* childElement = nullptr;
+    if (const auto result = readExactlyOneElement(kTagIoOveruseConfiguration, rootElement);
+        result.ok()) {
+        childElement = *result;
+    } else {
+        return Error() << "Failed to read tag '" << kTagIoOveruseConfiguration
+                       << "': " << result.error();
+    }
+    IoOveruseConfiguration configuration;
+    if (const auto result = readComponentLevelThresholds(componentType, childElement);
+        result.ok()) {
+        configuration.componentLevelThresholds = *result;
+    } else {
+        return Error() << "Failed to read component-level thresholds: " << result.error();
+    }
+    if (const auto result = readPackageSpecificThresholds(childElement); result.ok()) {
+        configuration.packageSpecificThresholds = *result;
+    } else {
+        return Error() << "Failed to read package specific thresholds: " << result.error();
+    }
+    if (const auto result = readAppCategorySpecificThresholds(childElement); result.ok()) {
+        configuration.categorySpecificThresholds = *result;
+    } else {
+        return Error() << "Failed to read category specific thresholds: " << result.error();
+    }
+    if (const auto result = readSystemWideThresholds(childElement); result.ok()) {
+        configuration.systemWideThresholds = *result;
+    } else {
+        return Error() << "Failed to read system-wide thresholds: " << result.error();
+    }
+    return configuration;
+}
+
+}  // namespace
+
+Result<ResourceOveruseConfiguration> OveruseConfigurationXmlHelper::parseXmlFile(
+        const char* filePath) {
+    XMLDocument xmlDoc;
+    xmlDoc.LoadFile(filePath);
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        return Error() << "Failed to read and/or parse '" << filePath << "'";
+    }
+    ResourceOveruseConfiguration configuration;
+    const XMLElement* rootElement = xmlDoc.RootElement();
+    if (!rootElement || strcmp(rootElement->Name(), kTagResourceOveruseConfiguration)) {
+        return Error() << "XML file doesn't have the root element '"
+                       << kTagResourceOveruseConfiguration << "'";
+    }
+    if (const auto result = readComponentType(rootElement); result.ok()) {
+        configuration.componentType = *result;
+    } else {
+        return Error() << "Failed to read component type: " << result.error();
+    }
+    if (const auto result = readSafeToKillPackages(rootElement); result.ok()) {
+        configuration.safeToKillPackages = *result;
+    } else {
+        return Error() << "Failed to read safe-to-kill packages: " << result.error();
+    }
+    if (const auto result = readVendorPackagePrefixes(rootElement); result.ok()) {
+        configuration.vendorPackagePrefixes = *result;
+    } else {
+        return Error() << "Failed to read vendor package prefixes: " << result.error();
+    }
+    if (const auto result = readPackageToAppCategoryTypes(rootElement); result.ok()) {
+        configuration.packageMetadata = *result;
+    } else {
+        return Error() << "Failed to read package to app category types: " << result.error();
+    }
+    if (const auto result = readIoOveruseConfiguration(configuration.componentType, rootElement);
+        result.ok()) {
+        configuration.resourceSpecificConfigurations.emplace_back(
+                ResourceSpecificConfiguration(*result));
+    } else {
+        return Error() << "Failed to read I/O overuse configuration: " << result.error();
+    }
+    return configuration;
+}
+
+Result<void> OveruseConfigurationXmlHelper::writeXmlFile(
+        [[maybe_unused]] const ResourceOveruseConfiguration& configuration,
+        [[maybe_unused]] const char* filePath) {
+    // TODO(b/185287136): Write the configuration to file.
+    return {};
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h
new file mode 100644
index 0000000..9f501c4
--- /dev/null
+++ b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
+#define CPP_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
+
+#include <android-base/result.h>
+#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class OveruseConfigurationXmlHelper : public android::RefBase {
+public:
+    static android::base::Result<
+            android::automotive::watchdog::internal::ResourceOveruseConfiguration>
+    parseXmlFile(const char* filePath);
+
+    static android::base::Result<void> writeXmlFile(
+            const android::automotive::watchdog::internal::ResourceOveruseConfiguration&
+                    configuration,
+            const char* filePath);
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  CPP_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
diff --git a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
index 433f027..43d08d7 100644
--- a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "IoOveruseConfigs.h"
+#include "OveruseConfigurationTestUtils.h"
 
 #include <android-base/strings.h>
 #include <gmock/gmock.h>
@@ -32,41 +33,18 @@
 using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
 using ::android::automotive::watchdog::internal::PackageInfo;
 using ::android::automotive::watchdog::internal::PackageMetadata;
-using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
 using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
 using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
 using ::android::automotive::watchdog::internal::UidType;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
-using ::testing::AllOf;
-using ::testing::AnyOf;
-using ::testing::ExplainMatchResult;
-using ::testing::Field;
 using ::testing::IsEmpty;
 using ::testing::Matcher;
 using ::testing::UnorderedElementsAre;
 using ::testing::UnorderedElementsAreArray;
-using ::testing::Value;
 
 namespace {
 
-PerStateBytes toPerStateBytes(const int64_t fgBytes, const int64_t bgBytes,
-                              const int64_t garageModeBytes) {
-    PerStateBytes perStateBytes;
-    perStateBytes.foregroundBytes = fgBytes;
-    perStateBytes.backgroundBytes = bgBytes;
-    perStateBytes.garageModeBytes = garageModeBytes;
-    return perStateBytes;
-}
-
-IoOveruseAlertThreshold toIoOveruseAlertThreshold(const int64_t durationInSeconds,
-                                                  const int64_t writtenBytesPerSecond) {
-    IoOveruseAlertThreshold threshold;
-    threshold.durationInSeconds = durationInSeconds;
-    threshold.writtenBytesPerSecond = writtenBytesPerSecond;
-    return threshold;
-}
-
 const PerStateBytes SYSTEM_COMPONENT_LEVEL_THRESHOLDS = toPerStateBytes(200, 100, 500);
 const PerStateBytes SYSTEM_PACKAGE_A_THRESHOLDS = toPerStateBytes(600, 400, 1000);
 const PerStateBytes SYSTEM_PACKAGE_B_THRESHOLDS = toPerStateBytes(1200, 800, 1500);
@@ -80,43 +58,6 @@
                                                                toIoOveruseAlertThreshold(30,
                                                                                          40000)};
 
-PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
-                                                        const PerStateBytes& perStateBytes) {
-    PerStateIoOveruseThreshold threshold;
-    threshold.name = name;
-    threshold.perStateWriteBytes = perStateBytes;
-    return threshold;
-}
-
-PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
-                                                        const PerStateBytes& perStateBytes) {
-    return toPerStateIoOveruseThreshold(toString(type), perStateBytes);
-}
-
-PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
-                                                        const int64_t fgBytes,
-                                                        const int64_t bgBytes,
-                                                        const int64_t garageModeBytes) {
-    PerStateIoOveruseThreshold threshold;
-    threshold.name = name;
-    threshold.perStateWriteBytes = toPerStateBytes(fgBytes, bgBytes, garageModeBytes);
-    return threshold;
-}
-
-PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
-                                                        const int64_t fgBytes,
-                                                        const int64_t bgBytes,
-                                                        const int64_t garageModeBytes) {
-    return toPerStateIoOveruseThreshold(toString(type), fgBytes, bgBytes, garageModeBytes);
-}
-
-PackageMetadata toPackageMetadata(std::string packageName, ApplicationCategoryType type) {
-    PackageMetadata meta;
-    meta.packageName = packageName;
-    meta.appCategoryType = type;
-    return meta;
-}
-
 std::unordered_map<std::string, ApplicationCategoryType> toPackageToAppCategoryMappings(
         const std::vector<PackageMetadata>& metas) {
     std::unordered_map<std::string, ApplicationCategoryType> mappings;
@@ -137,35 +78,6 @@
     return packageInfo;
 }
 
-ResourceOveruseConfiguration constructResourceOveruseConfig(
-        const ComponentType type, const std::vector<std::string>&& safeToKill,
-        const std::vector<std::string>&& vendorPrefixes,
-        const std::vector<PackageMetadata> packageMetadata,
-        const IoOveruseConfiguration& ioOveruseConfiguration) {
-    ResourceOveruseConfiguration resourceOveruseConfig;
-    resourceOveruseConfig.componentType = type;
-    resourceOveruseConfig.safeToKillPackages = safeToKill;
-    resourceOveruseConfig.vendorPackagePrefixes = vendorPrefixes;
-    resourceOveruseConfig.packageMetadata = packageMetadata;
-    ResourceSpecificConfiguration config;
-    config.set<ResourceSpecificConfiguration::ioOveruseConfiguration>(ioOveruseConfiguration);
-    resourceOveruseConfig.resourceSpecificConfigurations.push_back(config);
-    return resourceOveruseConfig;
-}
-
-IoOveruseConfiguration constructIoOveruseConfig(
-        PerStateIoOveruseThreshold componentLevel,
-        const std::vector<PerStateIoOveruseThreshold>& packageSpecific,
-        const std::vector<PerStateIoOveruseThreshold>& categorySpecific,
-        const std::vector<IoOveruseAlertThreshold>& systemWide) {
-    IoOveruseConfiguration config;
-    config.componentLevelThresholds = componentLevel;
-    config.packageSpecificThresholds = packageSpecific;
-    config.categorySpecificThresholds = categorySpecific;
-    config.systemWideThresholds = systemWide;
-    return config;
-}
-
 std::string toString(std::vector<ResourceOveruseConfiguration> configs) {
     std::string buffer;
     StringAppendF(&buffer, "[");
@@ -179,58 +91,11 @@
     return buffer;
 }
 
-MATCHER_P(IsIoOveruseConfiguration, config, "") {
-    return arg.componentLevelThresholds == config.componentLevelThresholds &&
-            ExplainMatchResult(UnorderedElementsAreArray(config.packageSpecificThresholds),
-                               arg.packageSpecificThresholds, result_listener) &&
-            ExplainMatchResult(UnorderedElementsAreArray(config.categorySpecificThresholds),
-                               arg.categorySpecificThresholds, result_listener) &&
-            ExplainMatchResult(UnorderedElementsAreArray(config.systemWideThresholds),
-                               arg.systemWideThresholds, result_listener);
-}
-
-MATCHER_P(IsResourceSpecificConfiguration, config, "") {
-    if (arg.getTag() != config.getTag()) {
-        return false;
-    }
-    // Reference with the actual datatype so the templated get method can be called.
-    const ResourceSpecificConfiguration& expected = config;
-    const ResourceSpecificConfiguration& actual = arg;
-    switch (arg.getTag()) {
-        case ResourceSpecificConfiguration::ioOveruseConfiguration: {
-            const auto& expectedIoConfig =
-                    expected.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
-            const auto& actualIoConfig =
-                    actual.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
-            return ExplainMatchResult(IsIoOveruseConfiguration(expectedIoConfig), actualIoConfig,
-                                      result_listener);
-        }
-        default:
-            return true;
-    }
-}
-
-Matcher<const ResourceOveruseConfiguration> IsResourceOveruseConfiguration(
-        const ResourceOveruseConfiguration& config) {
-    std::vector<Matcher<const ResourceSpecificConfiguration>> matchers;
-    for (const auto& resourceSpecificConfig : config.resourceSpecificConfigurations) {
-        matchers.push_back(IsResourceSpecificConfiguration(resourceSpecificConfig));
-    }
-
-    return AllOf(Field(&ResourceOveruseConfiguration::componentType, config.componentType),
-                 Field(&ResourceOveruseConfiguration::safeToKillPackages,
-                       UnorderedElementsAreArray(config.safeToKillPackages)),
-                 Field(&ResourceOveruseConfiguration::vendorPackagePrefixes,
-                       UnorderedElementsAreArray(config.vendorPackagePrefixes)),
-                 Field(&ResourceOveruseConfiguration::resourceSpecificConfigurations,
-                       UnorderedElementsAreArray(matchers)));
-}
-
-std::vector<Matcher<const ResourceOveruseConfiguration>> IsResourceOveruseConfigurations(
+std::vector<Matcher<const ResourceOveruseConfiguration>> ResourceOveruseConfigurationsMatchers(
         const std::vector<ResourceOveruseConfiguration>& configs) {
     std::vector<Matcher<const ResourceOveruseConfiguration>> matchers;
     for (const auto config : configs) {
-        matchers.push_back(IsResourceOveruseConfiguration(config));
+        matchers.push_back(ResourceOveruseConfigurationMatcher(config));
     }
     return matchers;
 }
@@ -313,7 +178,7 @@
     std::vector<ResourceOveruseConfiguration> actual;
     ioOveruseConfigs.get(&actual);
 
-    EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+    EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
             << "Expected: " << toString(expected) << "Actual:" << toString(actual);
 
     // Check whether previous configs are overwritten.
@@ -379,7 +244,7 @@
     actual.clear();
     ioOveruseConfigs.get(&actual);
 
-    EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+    EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
             << "Expected: " << toString(expected) << "Actual:" << toString(actual);
 }
 
@@ -558,7 +423,7 @@
     std::vector<ResourceOveruseConfiguration> actual;
     ioOveruseConfigs.get(&actual);
 
-    EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+    EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
             << "Expected: " << toString(expected) << "Actual:" << toString(actual);
 }
 
@@ -597,7 +462,7 @@
     std::vector<ResourceOveruseConfiguration> actual;
     ioOveruseConfigs.get(&actual);
 
-    EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+    EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
             << "Expected: " << toString(expected) << "Actual:" << toString(actual);
 }
 
@@ -636,7 +501,7 @@
     std::vector<ResourceOveruseConfiguration> actual;
     ioOveruseConfigs.get(&actual);
 
-    EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+    EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
             << "Expected: " << toString(expected) << "Actual:" << toString(actual);
 }
 
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp
new file mode 100644
index 0000000..ec5908a
--- /dev/null
+++ b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 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.
+ */
+
+#include "OveruseConfigurationTestUtils.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::android::automotive::watchdog::internal::ComponentType;
+using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
+using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::android::automotive::watchdog::internal::PackageMetadata;
+using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::testing::AllOf;
+using ::testing::ExplainMatchResult;
+using ::testing::Field;
+using ::testing::Matcher;
+using ::testing::UnorderedElementsAreArray;
+
+namespace {
+
+MATCHER_P(IsIoOveruseConfiguration, config, "") {
+    return arg.componentLevelThresholds == config.componentLevelThresholds &&
+            ExplainMatchResult(UnorderedElementsAreArray(config.packageSpecificThresholds),
+                               arg.packageSpecificThresholds, result_listener) &&
+            ExplainMatchResult(UnorderedElementsAreArray(config.categorySpecificThresholds),
+                               arg.categorySpecificThresholds, result_listener) &&
+            ExplainMatchResult(UnorderedElementsAreArray(config.systemWideThresholds),
+                               arg.systemWideThresholds, result_listener);
+}
+
+MATCHER_P(IsResourceSpecificConfiguration, config, "") {
+    if (arg.getTag() != config.getTag()) {
+        return false;
+    }
+    // Reference with the actual datatype so the templated get method can be called.
+    const ResourceSpecificConfiguration& expected = config;
+    const ResourceSpecificConfiguration& actual = arg;
+    switch (arg.getTag()) {
+        case ResourceSpecificConfiguration::ioOveruseConfiguration: {
+            const auto& expectedIoConfig =
+                    expected.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+            const auto& actualIoConfig =
+                    actual.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+            return ExplainMatchResult(IsIoOveruseConfiguration(expectedIoConfig), actualIoConfig,
+                                      result_listener);
+        }
+        default:
+            return true;
+    }
+}
+
+}  // namespace
+
+ResourceOveruseConfiguration constructResourceOveruseConfig(
+        const ComponentType type, const std::vector<std::string>&& safeToKill,
+        const std::vector<std::string>&& vendorPrefixes,
+        const std::vector<PackageMetadata> packageMetadata,
+        const IoOveruseConfiguration& ioOveruseConfiguration) {
+    ResourceOveruseConfiguration resourceOveruseConfig;
+    resourceOveruseConfig.componentType = type;
+    resourceOveruseConfig.safeToKillPackages = safeToKill;
+    resourceOveruseConfig.vendorPackagePrefixes = vendorPrefixes;
+    resourceOveruseConfig.packageMetadata = packageMetadata;
+    ResourceSpecificConfiguration config;
+    config.set<ResourceSpecificConfiguration::ioOveruseConfiguration>(ioOveruseConfiguration);
+    resourceOveruseConfig.resourceSpecificConfigurations.push_back(config);
+    return resourceOveruseConfig;
+}
+
+IoOveruseConfiguration constructIoOveruseConfig(
+        PerStateIoOveruseThreshold componentLevel,
+        const std::vector<PerStateIoOveruseThreshold>& packageSpecific,
+        const std::vector<PerStateIoOveruseThreshold>& categorySpecific,
+        const std::vector<IoOveruseAlertThreshold>& systemWide) {
+    IoOveruseConfiguration config;
+    config.componentLevelThresholds = componentLevel;
+    config.packageSpecificThresholds = packageSpecific;
+    config.categorySpecificThresholds = categorySpecific;
+    config.systemWideThresholds = systemWide;
+    return config;
+}
+
+PerStateBytes toPerStateBytes(const int64_t fgBytes, const int64_t bgBytes,
+                              const int64_t garageModeBytes) {
+    PerStateBytes perStateBytes;
+    perStateBytes.foregroundBytes = fgBytes;
+    perStateBytes.backgroundBytes = bgBytes;
+    perStateBytes.garageModeBytes = garageModeBytes;
+    return perStateBytes;
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
+                                                        const PerStateBytes& perStateBytes) {
+    PerStateIoOveruseThreshold threshold;
+    threshold.name = name;
+    threshold.perStateWriteBytes = perStateBytes;
+    return threshold;
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
+                                                        const int64_t fgBytes,
+                                                        const int64_t bgBytes,
+                                                        const int64_t garageModeBytes) {
+    return toPerStateIoOveruseThreshold(name, toPerStateBytes(fgBytes, bgBytes, garageModeBytes));
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
+                                                        const PerStateBytes& perStateBytes) {
+    return toPerStateIoOveruseThreshold(toString(type), perStateBytes);
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
+                                                        const int64_t fgBytes,
+                                                        const int64_t bgBytes,
+                                                        const int64_t garageModeBytes) {
+    return toPerStateIoOveruseThreshold(type, toPerStateBytes(fgBytes, bgBytes, garageModeBytes));
+}
+
+PackageMetadata toPackageMetadata(std::string packageName, ApplicationCategoryType type) {
+    PackageMetadata meta;
+    meta.packageName = packageName;
+    meta.appCategoryType = type;
+    return meta;
+}
+
+IoOveruseAlertThreshold toIoOveruseAlertThreshold(const int64_t durationInSeconds,
+                                                  const int64_t writtenBytesPerSecond) {
+    IoOveruseAlertThreshold threshold;
+    threshold.durationInSeconds = durationInSeconds;
+    threshold.writtenBytesPerSecond = writtenBytesPerSecond;
+    return threshold;
+}
+
+Matcher<const ResourceOveruseConfiguration> ResourceOveruseConfigurationMatcher(
+        const ResourceOveruseConfiguration& config) {
+    std::vector<Matcher<const ResourceSpecificConfiguration>> matchers;
+    for (const auto& resourceSpecificConfig : config.resourceSpecificConfigurations) {
+        matchers.push_back(IsResourceSpecificConfiguration(resourceSpecificConfig));
+    }
+
+    return AllOf(Field(&ResourceOveruseConfiguration::componentType, config.componentType),
+                 Field(&ResourceOveruseConfiguration::safeToKillPackages,
+                       UnorderedElementsAreArray(config.safeToKillPackages)),
+                 Field(&ResourceOveruseConfiguration::vendorPackagePrefixes,
+                       UnorderedElementsAreArray(config.vendorPackagePrefixes)),
+                 Field(&ResourceOveruseConfiguration::resourceSpecificConfigurations,
+                       UnorderedElementsAreArray(matchers)));
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h
new file mode 100644
index 0000000..84c970a
--- /dev/null
+++ b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_H_
+#define CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_H_
+
+#include <android/automotive/watchdog/PerStateBytes.h>
+#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <android/automotive/watchdog/internal/ComponentType.h>
+#include <android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
+#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
+#include <android/automotive/watchdog/internal/PackageMetadata.h>
+#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
+#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
+#include <gmock/gmock.h>
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+android::automotive::watchdog::internal::ResourceOveruseConfiguration
+constructResourceOveruseConfig(
+        const android::automotive::watchdog::internal::ComponentType type,
+        const std::vector<std::string>&& safeToKill,
+        const std::vector<std::string>&& vendorPrefixes,
+        const std::vector<android::automotive::watchdog::internal::PackageMetadata> packageMetadata,
+        const android::automotive::watchdog::internal::IoOveruseConfiguration&
+                ioOveruseConfiguration);
+
+android::automotive::watchdog::internal::IoOveruseConfiguration constructIoOveruseConfig(
+        android::automotive::watchdog::internal::PerStateIoOveruseThreshold componentLevel,
+        const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+                packageSpecific,
+        const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+                categorySpecific,
+        const std::vector<android::automotive::watchdog::internal::IoOveruseAlertThreshold>&
+                systemWide);
+
+PerStateBytes toPerStateBytes(const int64_t fgBytes, const int64_t bgBytes,
+                              const int64_t garageModeBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+        const std::string& name, const PerStateBytes& perStateBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+        const std::string& name, const int64_t fgBytes, const int64_t bgBytes,
+        const int64_t garageModeBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+        const android::automotive::watchdog::internal::ComponentType type,
+        const PerStateBytes& perStateBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+        const android::automotive::watchdog::internal::ComponentType type, const int64_t fgBytes,
+        const int64_t bgBytes, const int64_t garageModeBytes);
+
+android::automotive::watchdog::internal::PackageMetadata toPackageMetadata(
+        std::string packageName,
+        android::automotive::watchdog::internal::ApplicationCategoryType type);
+
+android::automotive::watchdog::internal::IoOveruseAlertThreshold toIoOveruseAlertThreshold(
+        const int64_t durationInSeconds, const int64_t writtenBytesPerSecond);
+
+testing::Matcher<const android::automotive::watchdog::internal::ResourceOveruseConfiguration>
+ResourceOveruseConfigurationMatcher(
+        const android::automotive::watchdog::internal::ResourceOveruseConfiguration& config);
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_H_
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp b/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp
new file mode 100644
index 0000000..2595c2b
--- /dev/null
+++ b/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright 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.
+ */
+
+#include "OveruseConfigurationTestUtils.h"
+#include "OveruseConfigurationXmlHelper.h"
+
+#include <android-base/file.h>
+#include <android-base/result.h>
+#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <android/automotive/watchdog/internal/ComponentType.h>
+#include <gmock/gmock.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::android::automotive::watchdog::internal::ComponentType;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+
+namespace {
+
+constexpr const char* kTestDataDir = "/tests/data/";
+
+constexpr const char* kValidSystemConfiguration = "valid_overuse_system_configuration.xml";
+constexpr const char* kValidVendorConfiguration = "valid_overuse_vendor_configuration.xml";
+constexpr const char* kValidThirdPartyConfiguration = "valid_overuse_third_party_configuration.xml";
+
+const std::vector<const char*> kInvalidOveruseConfigurations =
+        {"duplicate_component_io_thresholds_overuse_configuration.xml",
+         "duplicate_component_type_overuse_configuration.xml",
+         "duplicate_io_config_overuse_configuration.xml",
+         "incomplete_app_category_io_thresholds_overuse_configuration.xml",
+         "incomplete_component_io_thresholds_overuse_configuration.xml",
+         "incomplete_pkg_io_thresholds_overuse_configuration.xml",
+         "incomplete_systemwide_io_thresholds_overuse_configuration.xml",
+         "invalid_component_type_overuse_configuration.xml",
+         "invalid_param_systemwide_io_thresholds_overuse_configuration.xml",
+         "invalid_state_app_category_io_thresholds_overuse_configuration.xml",
+         "invalid_state_component_io_thresholds_overuse_configuration.xml",
+         "invalid_state_pkg_io_thresholds_overuse_configuration.xml",
+         "invalid_type_app_category_mapping_overuse_configuration.xml",
+         "missing_component_io_thresholds_overuse_configuration.xml",
+         "missing_io_config_overuse_configuration.xml",
+         "missing_pkg_name_app_category_mapping_overuse_configuration.xml",
+         "missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml",
+         "missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml",
+         "missing_threshold_app_category_io_thresholds_overuse_configuration.xml",
+         "missing_threshold_component_io_thresholds_overuse_configuration.xml",
+         "missing_threshold_pkg_io_thresholds_overuse_configuration.xml",
+         "missing_threshold_systemwide_io_thresholds_overuse_configuration.xml"};
+
+std::string getTestFilePath(const char* filename) {
+    static std::string baseDir = android::base::GetExecutableDirectory();
+    return baseDir + kTestDataDir + filename;
+}
+
+}  // namespace
+
+TEST(OveruseConfigurationXmlHelperTest, TestValidSystemConfiguration) {
+    auto ioConfig = constructIoOveruseConfig(
+            /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 300, 150, 500),
+            /*packageSpecific=*/
+            {toPerStateIoOveruseThreshold("system.package.C", 400, 100, 200),
+             toPerStateIoOveruseThreshold("system.package.D", 1024, 500, 2048)},
+            /*categorySpecific=*/{},
+            /*systemWide=*/{toIoOveruseAlertThreshold(10, 200), toIoOveruseAlertThreshold(5, 50)});
+    ResourceOveruseConfiguration expected =
+            constructResourceOveruseConfig(ComponentType::SYSTEM,
+                                           /*safeToKill=*/{"system.package.A", "system.package.B"},
+                                           /*vendorPrefixes=*/{},
+                                           /*packageMetadata=*/
+                                           {toPackageMetadata("system.package.A",
+                                                              ApplicationCategoryType::MEDIA),
+                                            toPackageMetadata("system.package.B",
+                                                              ApplicationCategoryType::MAPS)},
+                                           ioConfig);
+    auto actual = OveruseConfigurationXmlHelper::parseXmlFile(
+            getTestFilePath(kValidSystemConfiguration).c_str());
+    ASSERT_RESULT_OK(actual);
+    EXPECT_THAT(*actual, ResourceOveruseConfigurationMatcher(expected))
+            << "Expected: " << expected.toString() << "\nActual: " << actual->toString();
+}
+
+TEST(OveruseConfigurationXmlHelperTest, TestValidVendorConfiguration) {
+    auto ioConfig = constructIoOveruseConfig(
+            /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::VENDOR, 1024, 512, 3072),
+            /*packageSpecific=*/
+            {toPerStateIoOveruseThreshold("com.vendor.package.C", 400, 100, 200),
+             toPerStateIoOveruseThreshold("com.vendor.package.D", 1024, 500, 2048)},
+            /*categorySpecific=*/
+            {toPerStateIoOveruseThreshold("MAPS", 800, 900, 2048),
+             toPerStateIoOveruseThreshold("MEDIA", 600, 700, 1024)},
+            /*systemWide=*/{});
+    ResourceOveruseConfiguration expected =
+            constructResourceOveruseConfig(ComponentType::VENDOR,
+                                           /*safeToKill=*/
+                                           {"com.vendor.package.A", "com.vendor.package.B"},
+                                           /*vendorPrefixes=*/{"com.vendor.package"},
+                                           /*packageMetadata=*/
+                                           {toPackageMetadata("com.vendor.package.A",
+                                                              ApplicationCategoryType::MEDIA),
+                                            toPackageMetadata("com.vendor.package.B",
+                                                              ApplicationCategoryType::MAPS),
+                                            toPackageMetadata("com.third.party.package.C",
+                                                              ApplicationCategoryType::MEDIA),
+                                            toPackageMetadata("system.package.D",
+                                                              ApplicationCategoryType::MAPS)},
+                                           ioConfig);
+    auto actual = OveruseConfigurationXmlHelper::parseXmlFile(
+            getTestFilePath(kValidVendorConfiguration).c_str());
+    ASSERT_RESULT_OK(actual);
+    EXPECT_THAT(*actual, ResourceOveruseConfigurationMatcher(expected))
+            << "Expected: " << expected.toString() << "\nActual: " << actual->toString();
+}
+
+TEST(OveruseConfigurationXmlHelperTest, TestValidThirdPartyConfiguration) {
+    auto ioConfig = constructIoOveruseConfig(
+            /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 300, 150,
+                                                            500),
+            /*packageSpecific=*/{},
+            /*categorySpecific=*/{},
+            /*systemWide=*/{});
+    ResourceOveruseConfiguration expected =
+            constructResourceOveruseConfig(ComponentType::THIRD_PARTY,
+                                           /*safeToKill=*/{},
+                                           /*vendorPrefixes=*/{},
+                                           /*packageMetadata=*/{}, ioConfig);
+    auto actual = OveruseConfigurationXmlHelper::parseXmlFile(
+            getTestFilePath(kValidThirdPartyConfiguration).c_str());
+    ASSERT_RESULT_OK(actual);
+    EXPECT_THAT(*actual, ResourceOveruseConfigurationMatcher(expected))
+            << "Expected: " << expected.toString() << "\nActual: " << actual->toString();
+}
+
+TEST(OveruseConfigurationXmlHelperTest, TestInvalidOveruseConfigurations) {
+    for (const auto& filename : kInvalidOveruseConfigurations) {
+        ASSERT_FALSE(
+                OveruseConfigurationXmlHelper::parseXmlFile(getTestFilePath(filename).c_str()).ok())
+                << "Must return error on parsing '" << filename << "'";
+    }
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/watchdog/server/tests/data/duplicate_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/duplicate_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..9db8129
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/duplicate_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/duplicate_component_type_overuse_configuration.xml b/cpp/watchdog/server/tests/data/duplicate_component_type_overuse_configuration.xml
new file mode 100644
index 0000000..9b04e11
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/duplicate_component_type_overuse_configuration.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+  <componentType> THIRD_PARTY </componentType>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/duplicate_io_config_overuse_configuration.xml b/cpp/watchdog/server/tests/data/duplicate_io_config_overuse_configuration.xml
new file mode 100644
index 0000000..5a1b801
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/duplicate_io_config_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/incomplete_app_category_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_app_category_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..3de9084
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_app_category_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <appCategorySpecificThresholds>
+      <appCategoryThreshold id="MEDIA">
+        <state id="foreground_mode"> 600 </state>
+        <state id="background_mode"> 700 </state>
+      </appCategoryThreshold>
+    </appCategorySpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/incomplete_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..59f5f2c
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/incomplete_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..abd372c
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <packageSpecificThresholds id="system.package.C">
+      <state id="foreground_mode"> 400 </state>
+      <state id="background_mode"> 100 </state>
+    </packageSpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/incomplete_systemwide_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_systemwide_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..8233207
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_systemwide_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <systemWideThresholds>
+      <param id="written_bytes_per_second"> 200 </param>
+    </systemWideThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_component_type_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_component_type_overuse_configuration.xml
new file mode 100644
index 0000000..06f351f
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_component_type_overuse_configuration.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> RANDOM </componentType>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_param_systemwide_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_param_systemwide_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..77f523e
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_param_systemwide_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <systemWideThresholds>
+      <param id="duration_seconds"> 10 </param>
+      <param id="written_bytes_per_second"> 200 </param>
+      <param id="random_param"> 200 </param>
+    </systemWideThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_state_app_category_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_state_app_category_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..c2f6d6a
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_state_app_category_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <appCategorySpecificThresholds>
+      <appCategoryThreshold id="MEDIA">
+        <state id="foreground_mode"> 600 </state>
+        <state id="background_mode"> 700 </state>
+        <state id="garage_mode"> 1024 </state>
+        <state id="random_mode"> 1024 </state>
+      </appCategoryThreshold>
+    </appCategorySpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_state_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_state_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..a86cf54
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_state_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+      <state id="random_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_state_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_state_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..377b2d7
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_state_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <packageSpecificThresholds id="system.package.C">
+      <state id="foreground_mode"> 400 </state>
+      <state id="background_mode"> 100 </state>
+      <state id="garage_mode"> 500 </state>
+      <state id="random_mode"> 500 </state>
+    </packageSpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_type_app_category_mapping_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_type_app_category_mapping_overuse_configuration.xml
new file mode 100644
index 0000000..412c6d1
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_type_app_category_mapping_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <packagesToAppCategoryTypes>
+    <packageAppCategory type="OTHERS"> system.package.A </packageAppCategory>
+    <packageAppCategory type="MAPS"> system.package.B </packageAppCategory>
+  </packagesToAppCategoryTypes>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..4fe5fd3
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration/>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_io_config_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_io_config_overuse_configuration.xml
new file mode 100644
index 0000000..0d286cf
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_io_config_overuse_configuration.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_pkg_name_app_category_mapping_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_pkg_name_app_category_mapping_overuse_configuration.xml
new file mode 100644
index 0000000..10b5019
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_pkg_name_app_category_mapping_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <packagesToAppCategoryTypes>
+    <packageAppCategory type="MEDIA"> </packageAppCategory>
+    <packageAppCategory type="MAPS"> system.package.B </packageAppCategory>
+  </packagesToAppCategoryTypes>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..554f385
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <packageSpecificThresholds id="">
+      <state id="foreground_mode"> 400 </state>
+      <state id="background_mode"> 100 </state>
+      <state id="garage_mode"> 200 </state>
+    </packageSpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml
new file mode 100644
index 0000000..a6fdb1d
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <safeToKillPackages>
+    <package/>
+  </safeToKillPackages>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_app_category_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_app_category_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..7c264ef
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_app_category_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <appCategorySpecificThresholds>
+      <appCategoryThreshold id="MEDIA">
+        <state id="foreground_mode"/>
+        <state id="background_mode"> 700 </state>
+        <state id="garage_mode"> 500 </state>
+      </appCategoryThreshold>
+    </appCategorySpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..dfab251
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"/>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..8914406
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <packageSpecificThresholds id="system.package.C">
+      <state id="foreground_mode"> 400 </state>
+      <state id="background_mode"/>
+      <state id="garage_mode"> 100 </state>
+    </packageSpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_systemwide_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_systemwide_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..0341c06
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_systemwide_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <ioOveruseConfiguration>
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <systemWideThresholds>
+      <param id="duration_seconds"> 10 </param>
+      <param id="written_bytes_per_second"/>
+    </systemWideThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/valid_overuse_system_configuration.xml b/cpp/watchdog/server/tests/data/valid_overuse_system_configuration.xml
new file mode 100644
index 0000000..854abc7
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/valid_overuse_system_configuration.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> SYSTEM </componentType>
+
+  <!-- List of safe to kill system packages. -->
+  <safeToKillPackages>
+    <package> system.package.A </package>
+    <package> system.package.B </package>
+  </safeToKillPackages>
+
+  <!-- List of unique package names to app category mappings. -->
+  <packagesToAppCategoryTypes>
+    <packageAppCategory type="MEDIA"> system.package.A </packageAppCategory>
+    <packageAppCategory type="MAPS"> system.package.B </packageAppCategory>
+  </packagesToAppCategoryTypes>
+
+  <ioOveruseConfiguration>
+    <!-- Thresholds in MiB for all system packages that don’t have package specific thresholds. -->
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+
+    <!-- Package specific thresholds. -->
+    <packageSpecificThresholds id="system.package.C">
+      <state id="foreground_mode"> 400 </state>
+      <state id="background_mode"> 100 </state>
+      <state id="garage_mode"> 200 </state>
+    </packageSpecificThresholds>
+
+    <packageSpecificThresholds id="system.package.D">
+      <state id="foreground_mode"> 1024 </state>
+      <state id="background_mode"> 500 </state>
+      <state id="garage_mode"> 2048 </state>
+    </packageSpecificThresholds>
+
+    <!-- List of system-wide disk I/O overuse alert thresholds. -->
+    <systemWideThresholds>
+      <param id="duration_seconds"> 10 </param>
+      <param id="written_bytes_per_second"> 200 </param>
+    </systemWideThresholds>
+
+    <systemWideThresholds>
+      <param id="duration_seconds"> 5 </param>
+      <param id="written_bytes_per_second"> 50 </param>
+    </systemWideThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/valid_overuse_third_party_configuration.xml b/cpp/watchdog/server/tests/data/valid_overuse_third_party_configuration.xml
new file mode 100644
index 0000000..b3bacb6
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/valid_overuse_third_party_configuration.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> THIRD_PARTY </componentType>
+  <ioOveruseConfiguration>
+    <!-- Thresholds in MiB for all third-party packages. -->
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 300 </state>
+      <state id="background_mode"> 150 </state>
+      <state id="garage_mode"> 500 </state>
+    </componentLevelThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/valid_overuse_vendor_configuration.xml b/cpp/watchdog/server/tests/data/valid_overuse_vendor_configuration.xml
new file mode 100644
index 0000000..b7b4341
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/valid_overuse_vendor_configuration.xml
@@ -0,0 +1,75 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+  <componentType> VENDOR </componentType>
+
+  <!-- List of safe to kill system packages. -->
+  <safeToKillPackages>
+    <package> com.vendor.package.A </package>
+    <package> com.vendor.package.B </package>
+  </safeToKillPackages>
+
+  <!-- List of vendor package prefixes. -->
+  <vendorPackagePrefixes>
+    <packagePrefix> com.vendor.package </packagePrefix>
+  </vendorPackagePrefixes>
+
+  <!-- List of unique package names to app category mappings. -->
+  <packagesToAppCategoryTypes>
+    <packageAppCategory type="MEDIA"> com.vendor.package.A </packageAppCategory>
+    <packageAppCategory type="MAPS"> com.vendor.package.B </packageAppCategory>
+    <packageAppCategory type="MEDIA"> com.third.party.package.C </packageAppCategory>
+    <packageAppCategory type="MAPS"> system.package.D </packageAppCategory>
+  </packagesToAppCategoryTypes>
+
+  <ioOveruseConfiguration>
+    <!-- Thresholds in MiB for all vendor packages that don’t have package specific thresholds. -->
+    <componentLevelThresholds>
+      <state id="foreground_mode"> 1024 </state>
+      <state id="background_mode"> 512 </state>
+      <state id="garage_mode"> 3072 </state>
+    </componentLevelThresholds>
+
+    <!-- Package specific thresholds. -->
+    <packageSpecificThresholds id="com.vendor.package.C">
+      <state id="foreground_mode"> 400 </state>
+      <state id="background_mode"> 100 </state>
+      <state id="garage_mode"> 200 </state>
+    </packageSpecificThresholds>
+
+    <packageSpecificThresholds id="com.vendor.package.D">
+      <state id="foreground_mode"> 1024 </state>
+      <state id="background_mode"> 500 </state>
+      <state id="garage_mode"> 2048 </state>
+    </packageSpecificThresholds>
+
+    <!-- Application category specific thresholds. -->
+    <appCategorySpecificThresholds>
+      <appCategoryThreshold id="MEDIA">
+        <state id="foreground_mode"> 600 </state>
+        <state id="background_mode"> 700 </state>
+        <state id="garage_mode"> 1024 </state>
+      </appCategoryThreshold>
+
+      <appCategoryThreshold id="MAPS">
+        <state id="foreground_mode"> 800 </state>
+        <state id="background_mode"> 900 </state>
+        <state id="garage_mode"> 2048 </state>
+      </appCategoryThreshold>
+    </appCategorySpecificThresholds>
+  </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/packages/CarDeveloperOptions/AndroidManifest.xml b/packages/CarDeveloperOptions/AndroidManifest.xml
index ddd97dc..6dbba33 100644
--- a/packages/CarDeveloperOptions/AndroidManifest.xml
+++ b/packages/CarDeveloperOptions/AndroidManifest.xml
@@ -21,8 +21,9 @@
           package="com.android.car.developeroptions"
           android:sharedUserId="android.uid.system">
 
-    <application android:label="@string/settings_label"
-                 tools:node="merge">
+    <application android:label="@string/development_settings_title"
+                 tools:node="merge"
+                 tools:replace="android:label">
 
         <activity
             android:name=".CarDevelopmentSettingsDashboardActivity"
@@ -562,6 +563,15 @@
         </activity>
 
         <activity
+            android:name="com.android.settings.Settings$LockScreenSettingsActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.SettingsLicenseActivity"
             android:enabled="false"
             android:exported="false"
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index 5b8c5e2..3e30d75 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -127,10 +127,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"গাড়ির ভেন্ডরের অনুমতি সম্পর্কে তথ্য অ্যাক্সেস করুন।"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইটের স্ট্যাটাস দেখা"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইটের স্ট্যাটাস অ্যাক্সেস করা।"</string>
-    <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
-    <skip />
-    <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
-    <skip />
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"গাড়ির সময় পর্বের তথ্য ব্যবহার করুন"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"গাড়ির সময় পর্বের তথ্য ব্যবহার করুন।"</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"গাড়ির এনক্রিপশন বাইন্ডিং সিড অ্যাক্সেস করুন"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"গাড়ির এনক্রিপশন বাইন্ডিং সিড অ্যাক্সেস করুন।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইট দেখা"</string>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 484ef9d..b587127 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -128,10 +128,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"કારના વિક્રેતાની પરવાનગી વિશેની માહિતીને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"કારની બહારની લાઇટની સ્થિતિને વાંચો"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"કારની બહારની લાઇટની સ્થિતિને ઍક્સેસ કરો."</string>
-    <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
-    <skip />
-    <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
-    <skip />
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"કારનો epoch સમય ઍક્સેસ કરો"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"કારનો epoch સમય ઍક્સેસ કરો."</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"કારના એન્ક્રિપ્શન બાઇન્ડિંગ સીડને ઍક્સેસ કરો"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"કારના એન્ક્રિપ્શન બાઇન્ડિંગ સીડને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"કારની બહારની લાઇટ વિશે વાંચો"</string>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index e0e339e..2feb952 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -127,10 +127,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"ಕಾರಿನ ಮಾರಾಟಗಾರರ ಅನುಮತಿ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯನ್ನು ಓದಿ"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
-    <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
-    <skip />
-    <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
-    <skip />
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"ಕಾರ್‌ನ epoch ಸಮಯವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"ಕಾರ್‌ನ epoch ಸಮಯವನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ಕಾರ್‌ನ ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಬೈಡಿಂಗ್ ಸೀಡ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ಕಾರ್‌ನ ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಬೈಡಿಂಗ್ ಸೀಡ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಮಾಹಿತಿಯನ್ನು ಓದಿ"</string>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index d1b58b1..b93702f 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -127,10 +127,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"कारच्या विक्रेता परवानगी माहिती ॲक्सेस करा."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"कारच्या बाहेरील लाइटची स्थिती वाचा"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कारच्या बाहेरील लाइटची स्थिती अ‍ॅक्सेस करा."</string>
-    <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
-    <skip />
-    <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
-    <skip />
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"कारचा कालावधी अ‍ॅक्सेस करू द्या"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"कारचा कालावधी अ‍ॅक्सेस करू द्या."</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"कारचे एंक्रिप्शन बाइंडिंग सीड अ‍ॅक्सेस करा"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"कारचे एंक्रिप्शन बाइंडिंग सीड अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कारच्या बाहेरच्या लाइटची स्थिती वाचा"</string>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index c6754ac..0aad28e 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -127,10 +127,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"କାର୍\'ର ଭେଣ୍ଡର୍ ଅନୁମତି ସୂୂଚନା ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ଷ୍ଟେଟ୍‌କୁ ପଢ଼ିବ"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ଷ୍ଟେଟ୍‌କୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
-    <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
-    <skip />
-    <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
-    <skip />
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"କାରର epoch ସମୟକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"କାରର epoch ସମୟକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"କାରର ଏନକ୍ରିପସନ୍ ବାଇଣ୍ଡିଂ ସିଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"କାରର ଏନକ୍ରିପସନ୍ ବାଇଣ୍ଡିଂ ସିଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ସ୍ଥିତିକୁ ପଢ଼ିବ"</string>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 457df66..6f3cf6f 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -128,7 +128,7 @@
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"перегляд стану зовнішніх світлових приладів автомобіля"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Керування зовнішніми світловими приладами автомобіля."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"доступ до часу UNIX автомобіля"</string>
-    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Доступ до часу UNIX автомобіля"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Доступ до часу UNIX автомобіля."</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"доступ до джерела шифрування автомобіля"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Доступ до джерела шифрування автомобіля."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"перегляд зовнішніх світлових приладів автомобіля"</string>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index 3708846..c29597b 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -127,10 +127,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"کار کے وینڈر کے اجازت کی معلومات تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"کار کی بیرونی روشنیوں کی صورتحال کے بارے میں پڑھیں"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"کار کی بیرونی روشنیوں کی صورتحال تک رسائی حاصل کریں۔"</string>
-    <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
-    <skip />
-    <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
-    <skip />
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"کار کے epoch وقت تک رسائی حاصل کریں"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"کار کے epoch وقت تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"کار کی مرموز کاری واجب التعمیل سیڈ تک رسائی حاصل کریں"</string>
     <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"کار کی مرموز کاری واجب التعمیل سیڈ تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"کار کی بیرونی روشنیوں کے بارے میں پڑھیں"</string>
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index 9800e4d..7a8c9cb 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -238,6 +238,8 @@
                 PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_KEY,
                 android.Manifest.permission.INJECT_EVENTS);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_ROTARY,
+                android.Manifest.permission.INJECT_EVENTS);
     }
 
     private static final String PARAM_DAY_MODE = "day";
diff --git a/service/src/com/android/car/audio/CarAudioContext.java b/service/src/com/android/car/audio/CarAudioContext.java
index c93eca3..ecd8259 100644
--- a/service/src/com/android/car/audio/CarAudioContext.java
+++ b/service/src/com/android/car/audio/CarAudioContext.java
@@ -220,6 +220,9 @@
         }
     }
 
+    private CarAudioContext() {
+    }
+
     /**
      * Checks if the audio context is within the valid range from MUSIC to SYSTEM_SOUND
      */
diff --git a/service/src/com/android/car/audio/CarAudioUtils.java b/service/src/com/android/car/audio/CarAudioUtils.java
index 6724156..b787efb 100644
--- a/service/src/com/android/car/audio/CarAudioUtils.java
+++ b/service/src/com/android/car/audio/CarAudioUtils.java
@@ -16,7 +16,10 @@
 
 package com.android.car.audio;
 
-class CarAudioUtils {
+final class CarAudioUtils {
+    private CarAudioUtils() {
+    }
+
     static boolean hasExpired(long startTimeMs, long currentTimeMs, int timeoutMs) {
         return (currentTimeMs - startTimeMs) > timeoutMs;
     }
diff --git a/service/src/com/android/car/audio/CarAudioZonesValidator.java b/service/src/com/android/car/audio/CarAudioZonesValidator.java
index 4a74cd8..5fe495d 100644
--- a/service/src/com/android/car/audio/CarAudioZonesValidator.java
+++ b/service/src/com/android/car/audio/CarAudioZonesValidator.java
@@ -21,7 +21,10 @@
 import java.util.HashSet;
 import java.util.Set;
 
-class CarAudioZonesValidator {
+final class CarAudioZonesValidator {
+    private CarAudioZonesValidator() {
+    }
+
     static void validate(SparseArray<CarAudioZone> carAudioZones) {
         validateAtLeastOneZoneDefined(carAudioZones);
         validateVolumeGroupsForEachZone(carAudioZones);
diff --git a/service/src/com/android/car/audio/CarDuckingUtils.java b/service/src/com/android/car/audio/CarDuckingUtils.java
index d86a5bc..f386d62 100644
--- a/service/src/com/android/car/audio/CarDuckingUtils.java
+++ b/service/src/com/android/car/audio/CarDuckingUtils.java
@@ -106,6 +106,9 @@
         sContextsToDuck.append(ANNOUNCEMENT, new int[0]);
     }
 
+    private CarDuckingUtils() {
+    }
+
     static int[] getUsagesHoldingFocus(List<AudioFocusInfo> focusHolders) {
         Set<Integer> uniqueUsages = new HashSet<>();
         for (AudioFocusInfo focusInfo : focusHolders) {
diff --git a/service/src/com/android/car/audio/hal/AudioControlFactory.java b/service/src/com/android/car/audio/hal/AudioControlFactory.java
index 9f4b248..5f26372 100644
--- a/service/src/com/android/car/audio/hal/AudioControlFactory.java
+++ b/service/src/com/android/car/audio/hal/AudioControlFactory.java
@@ -27,6 +27,9 @@
 public final class AudioControlFactory {
     private static final String TAG = CarLog.tagFor(AudioControlFactory.class);
 
+    private AudioControlFactory() {
+    }
+
     /**
      * Generates {@link AudioControlWrapper} for interacting with IAudioControl HAL service. The HAL
      * version priority is: Current AIDL, HIDL V2, HIDL V1. The wrapper will try to fetch the
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
index 67c7584..b985407 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
@@ -202,6 +202,16 @@
         }
 
         @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+
+        @Override
         public void requestAudioFocus(String usage, int zoneId, int focusGain) {
             @AttributeUsage int usageValue = AudioAttributes.xsdStringToUsage(usage);
             mListener.requestAudioFocus(usageValue, zoneId, focusGain);
diff --git a/service/src/com/android/car/evs/CarEvsService.java b/service/src/com/android/car/evs/CarEvsService.java
index 416d3eb..764fb08 100644
--- a/service/src/com/android/car/evs/CarEvsService.java
+++ b/service/src/com/android/car/evs/CarEvsService.java
@@ -144,12 +144,16 @@
         public boolean isRequestingToStartActivity() {
             return mOn;
         }
+
+        public String toString() {
+            return "ServiceType = " + mServiceType + ", mOn = " + mOn +
+                    ", Timestamp = " + mTimestamp;
+        }
     }
 
     private final Context mContext;
     private final EvsHalService mEvsHalService;
     private final CarPropertyService mPropertyService;
-    // Shouldn't acquire mStateLock holding mLock.
     private final Object mLock = new Object();
 
     // This handler is to monitor the client sends a video stream request within a given time
@@ -223,18 +227,16 @@
 
     // CarEvsService state machine implementation to handle all state transitions.
     private final class StateMachine {
-        private Object mStateLock = new Object();
-
         // Current state
-        @GuardedBy("mStateLock")
+        @GuardedBy("mLock")
         private int mState = SERVICE_STATE_UNAVAILABLE;
 
         // Current service type
-        @GuardedBy("mStateLock")
+        @GuardedBy("mLock")
         private int mServiceType = CarEvsManager.SERVICE_TYPE_REARVIEW;
 
         // Priority of a last service request
-        @GuardedBy("mStateLock")
+        @GuardedBy("mLock")
         private int mLastRequestPriority = REQUEST_PRIORITY_LOW;
 
         public @CarEvsError int execute(int priority, int destination) {
@@ -253,17 +255,18 @@
         public @CarEvsError int execute(int priority, int destination, int service, IBinder token,
                 ICarEvsStreamCallback callback) {
 
-            if (mState == destination && destination != SERVICE_STATE_REQUESTED) {
-                // Nothing to do
-                return ERROR_NONE;
-            }
+            int result = ERROR_NONE;
+            synchronized (mLock) {
+                // TODO(b/188970686): Reduce this lock duration.
+                if (mState == destination && destination != SERVICE_STATE_REQUESTED) {
+                    // Nothing to do
+                    return ERROR_NONE;
+                }
 
-            int previousState = mState;
-            int result;
-            Slog.d(TAG_EVS, "Transition requested: " + toString(previousState) +
-                    " -> " + toString(destination));
+                int previousState = mState;
+                Slog.d(TAG_EVS, "Transition requested: " + toString(previousState) +
+                        " -> " + toString(destination));
 
-            synchronized (mStateLock) {
                 switch (destination) {
                     case SERVICE_STATE_UNAVAILABLE:
                         result = handleTransitionToUnavailableLocked();
@@ -296,24 +299,24 @@
         }
 
         public @CarEvsServiceState int getState() {
-            synchronized (mStateLock) {
+            synchronized (mLock) {
                 return mState;
             }
         }
 
         public @CarEvsServiceType int getServiceType() {
-            synchronized (mStateLock) {
+            synchronized (mLock) {
                 return mServiceType;
             }
         }
 
         public CarEvsStatus getStateAndServiceType() {
-            synchronized (mStateLock) {
+            synchronized (mLock) {
                 return new CarEvsStatus(mServiceType, mState);
             }
         }
 
-        @GuardedBy("mStateLock")
+        @GuardedBy("mLock")
         private @CarEvsError int handleTransitionToUnavailableLocked() {
             // This transition happens only when CarEvsService loses the active connection to the
             // Extended View System service.
@@ -332,7 +335,7 @@
             return ERROR_NONE;
         }
 
-        @GuardedBy("mStateLock")
+        @GuardedBy("mLock")
         private @CarEvsError int handleTransitionToInactiveLocked(int priority, int service,
                 ICarEvsStreamCallback callback) {
 
@@ -383,7 +386,7 @@
             return ERROR_NONE;
         }
 
-        @GuardedBy("mStateLock")
+        @GuardedBy("mLock")
         private @CarEvsError int handleTransitionToRequestedLocked(int priority, int service) {
             switch (mState) {
                 case SERVICE_STATE_UNAVAILABLE:
@@ -440,7 +443,7 @@
             return ERROR_NONE;
         }
 
-        @GuardedBy("mStateLock")
+        @GuardedBy("mLock")
         private @CarEvsError int handleTransitionToActiveLocked(int priority, int service,
                 IBinder token, ICarEvsStreamCallback callback) {
 
@@ -504,6 +507,10 @@
                     return "UNKNOWN";
             }
         }
+
+        public String toString() {
+            return toString(mState);
+        }
     }
 
     private final StateMachine mStateEngine = new StateMachine();
@@ -700,14 +707,15 @@
     @Override
     public void dump(IndentingPrintWriter writer) {
         writer.println("*CarEvsService*");
-        writer.printf("%s to HAL service",
+        writer.printf("Current state = %s\n", mStateEngine);
+        writer.printf("%s to HAL service\n",
                 mNativeEvsServiceObj == 0 ? "Not connected" : "Connected");
-        writer.printf("%d stream listeners subscribed.",
+        writer.printf("%d stream listeners subscribed.\n",
                 mStreamCallbacks.getRegisteredCallbackCount());
-        writer.printf("%d service listeners subscribed.",
+        writer.printf("%d service listeners subscribed.\n",
                 mStatusListeners.getRegisteredCallbackCount());
-
-        // TODO(b/177923530): Dump more status information
+        writer.printf("Last HAL event = %s\n", mLastEvsHalEvent);
+        writer.printf("Current session token = %s\n", mSessionToken);
     }
 
     /**
diff --git a/service/src/com/android/car/hal/EvsHalService.java b/service/src/com/android/car/hal/EvsHalService.java
index f0228b9..011c6d8 100644
--- a/service/src/com/android/car/hal/EvsHalService.java
+++ b/service/src/com/android/car/hal/EvsHalService.java
@@ -190,7 +190,7 @@
 
     @Override
     public void dump(PrintWriter writer) {
-        writer.println("*EVS HAL*");
+        writer.println("*EVSHALSERVICE*");
         writer.printf("Use EVS_SERVICE_REQUEST: %b\n", isEvsServiceRequestSupported());
     }
 }
diff --git a/service/src/com/android/car/power/SilentModeHandler.java b/service/src/com/android/car/power/SilentModeHandler.java
index d64a070..11d6c8c 100644
--- a/service/src/com/android/car/power/SilentModeHandler.java
+++ b/service/src/com/android/car/power/SilentModeHandler.java
@@ -105,11 +105,14 @@
 
     void init() {
         boolean forcedMode;
+        boolean silentMode;
         synchronized (mLock) {
             forcedMode = mForcedMode;
+            silentMode = mSilentModeByHwState;
         }
         if (forcedMode) {
-            updateKernelSilentMode(mSilentModeByHwState);
+            updateKernelSilentMode(silentMode);
+            mService.notifySilentModeChange(silentMode);
             Slogf.i(TAG, "Now in forced mode: monitoring %s is disabled",
                     mHwStateMonitoringFileName);
         } else {
diff --git a/service/src/com/android/car/telemetry/CarTelemetryService.java b/service/src/com/android/car/telemetry/CarTelemetryService.java
index d107cbd..695e25e 100644
--- a/service/src/com/android/car/telemetry/CarTelemetryService.java
+++ b/service/src/com/android/car/telemetry/CarTelemetryService.java
@@ -31,6 +31,7 @@
 import android.util.Slog;
 
 import com.android.car.CarServiceBase;
+import com.android.internal.annotations.GuardedBy;
 
 import com.google.protobuf.InvalidProtocolBufferException;
 
@@ -43,13 +44,18 @@
  */
 public class CarTelemetryService extends ICarTelemetryService.Stub implements CarServiceBase {
 
+    // TODO(b/189340793): Rename Manifest to MetricsConfig
+
     private static final boolean DEBUG = false;
     private static final int DEFAULT_VERSION = 0;
     private static final String TAG = CarTelemetryService.class.getSimpleName();
 
     private final Context mContext;
+    @GuardedBy("mLock")
     private final Map<String, Integer> mNameVersionMap = new HashMap<>();
+    private final Object mLock = new Object();
 
+    @GuardedBy("mLock")
     private ICarTelemetryServiceListener mListener;
 
     public CarTelemetryService(Context context) {
@@ -79,10 +85,9 @@
         // TODO(b/184890506): verify that only a hardcoded app can set the listener
         mContext.enforceCallingOrSelfPermission(
                 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
-        if (DEBUG) {
-            Slog.d(TAG, "Setting the listener for car telemetry service");
+        synchronized (mLock) {
+            setListenerLocked(listener);
         }
-        mListener = listener;
     }
 
     /**
@@ -92,45 +97,25 @@
     public void clearListener() {
         mContext.enforceCallingOrSelfPermission(
                 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
-        if (DEBUG) {
-            Slog.d(TAG, "Clearing listener");
+        synchronized (mLock) {
+            clearListenerLocked();
         }
-        mListener = null;
     }
 
     /**
      * Allows client to send telemetry manifests.
      *
-     * @param key      the unique key to identify the manifest.
-     * @param manifest the serialized bytes of a Manifest object.
+     * @param key    the unique key to identify the manifest.
+     * @param config the serialized bytes of a Manifest object.
      * @return {@link AddManifestError} the error code.
      */
     @Override
-    public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] manifest) {
+    public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] config) {
         mContext.enforceCallingOrSelfPermission(
                 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
-        if (DEBUG) {
-            Slog.d(TAG, "Adding manifest to car telemetry service");
+        synchronized (mLock) {
+            return addManifestLocked(key, config);
         }
-        int currentVersion = mNameVersionMap.getOrDefault(key.getName(), DEFAULT_VERSION);
-        if (currentVersion > key.getVersion()) {
-            return ERROR_NEWER_MANIFEST_EXISTS;
-        } else if (currentVersion == key.getVersion()) {
-            return ERROR_SAME_MANIFEST_EXISTS;
-        }
-
-        TelemetryProto.Manifest parsedManifest;
-        try {
-            parsedManifest = TelemetryProto.Manifest.parseFrom(manifest);
-        } catch (InvalidProtocolBufferException e) {
-            Slog.e(TAG, "Failed to parse manifest.", e);
-            return ERROR_PARSE_MANIFEST_FAILED;
-        }
-        mNameVersionMap.put(key.getName(), key.getVersion());
-
-        // TODO(b/186047142): Store the manifest to disk
-        // TODO(b/186047142): Send parsedManifest to a script manager or a queue
-        return ERROR_NONE;
     }
 
     /**
@@ -140,15 +125,9 @@
     public boolean removeManifest(@NonNull ManifestKey key) {
         mContext.enforceCallingOrSelfPermission(
                 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
-        if (DEBUG) {
-            Slog.d(TAG, "Removing manifest from car telemetry service");
+        synchronized (mLock) {
+            return removeManifestLocked(key);
         }
-        Integer version = mNameVersionMap.remove(key.getName());
-        if (version == null) {
-            return false;
-        }
-        // TODO(b/186047142): Delete manifest from disk and remove it from queue
-        return true;
     }
 
     /**
@@ -158,11 +137,9 @@
     public void removeAllManifests() {
         mContext.enforceCallingOrSelfPermission(
                 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
-        if (DEBUG) {
-            Slog.d(TAG, "Removing all manifest from car telemetry service");
+        synchronized (mLock) {
+            removeAllManifestsLocked();
         }
-        mNameVersionMap.clear();
-        // TODO(b/186047142): Delete all manifests from disk & queue
     }
 
     /**
@@ -204,4 +181,65 @@
             Slog.d(TAG, "Flushing script execution errors");
         }
     }
+
+    @GuardedBy("mLock")
+    private void setListenerLocked(@NonNull ICarTelemetryServiceListener listener) {
+        if (DEBUG) {
+            Slog.d(TAG, "Setting the listener for car telemetry service");
+        }
+        mListener = listener;
+    }
+
+    @GuardedBy("mLock")
+    private void clearListenerLocked() {
+        if (DEBUG) {
+            Slog.d(TAG, "Clearing listener");
+        }
+        mListener = null;
+    }
+
+    @GuardedBy("mLock")
+    private @AddManifestError int addManifestLocked(ManifestKey key, byte[] configProto) {
+        if (DEBUG) {
+            Slog.d(TAG, "Adding MetricsConfig to car telemetry service");
+        }
+        int currentVersion = mNameVersionMap.getOrDefault(key.getName(), DEFAULT_VERSION);
+        if (currentVersion > key.getVersion()) {
+            return ERROR_NEWER_MANIFEST_EXISTS;
+        } else if (currentVersion == key.getVersion()) {
+            return ERROR_SAME_MANIFEST_EXISTS;
+        }
+
+        TelemetryProto.MetricsConfig metricsConfig;
+        try {
+            metricsConfig = TelemetryProto.MetricsConfig.parseFrom(configProto);
+        } catch (InvalidProtocolBufferException e) {
+            Slog.e(TAG, "Failed to parse MetricsConfig.", e);
+            return ERROR_PARSE_MANIFEST_FAILED;
+        }
+        mNameVersionMap.put(key.getName(), key.getVersion());
+
+        // TODO(b/186047142): Store the MetricsConfig to disk
+        // TODO(b/186047142): Send metricsConfig to a script manager or a queue
+        return ERROR_NONE;
+    }
+
+    @GuardedBy("mLock")
+    private boolean removeManifestLocked(@NonNull ManifestKey key) {
+        Integer version = mNameVersionMap.remove(key.getName());
+        if (version == null) {
+            return false;
+        }
+        // TODO(b/186047142): Delete manifest from disk and remove it from queue
+        return true;
+    }
+
+    @GuardedBy("mLock")
+    private void removeAllManifestsLocked() {
+        if (DEBUG) {
+            Slog.d(TAG, "Removing all manifest from car telemetry service");
+        }
+        mNameVersionMap.clear();
+        // TODO(b/186047142): Delete all manifests from disk & queue
+    }
 }
diff --git a/service/src/com/android/car/telemetry/Channel.java b/service/src/com/android/car/telemetry/Channel.java
new file mode 100644
index 0000000..100e227
--- /dev/null
+++ b/service/src/com/android/car/telemetry/Channel.java
@@ -0,0 +1,38 @@
+/*
+ * 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.android.car.telemetry;
+
+import android.os.Bundle;
+
+/**
+ * Buffers data passing from publishers to subscribers. There is one channel per script receptor.
+ *
+ * TODO(b/187525360, b/187743369): make it a class or create an impl class for this.
+ */
+public interface Channel {
+    /**
+     * Buffers the given data.
+     *
+     * TODO(b/189241508): Use ScriptExecutor supported data structure
+     */
+    void push(Bundle message);
+
+    /** Returns the publisher configuration for this channel. */
+    TelemetryProto.Publisher getPublisherConfig();
+
+    // TODO(b/187525360, b/187743369): Add other methods to check/get data from the channel.
+}
diff --git a/service/src/com/android/car/telemetry/LogFilter.java b/service/src/com/android/car/telemetry/LogFilter.java
deleted file mode 100644
index 8f72fe8..0000000
--- a/service/src/com/android/car/telemetry/LogFilter.java
+++ /dev/null
@@ -1,205 +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.android.car.telemetry;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
-import android.util.Log;
-
-import com.android.car.telemetry.TelemetryProto.LogListener;
-import com.android.car.telemetry.TelemetryProto.Manifest;
-
-import java.lang.annotation.Retention;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * Encapsulates a filter that can be matched on log entries. Contains builder function to create
- * list of LogFilter given the loglistener.
- */
-public final class LogFilter {
-
-    private static final String TAG = LogFilter.class.getSimpleName();
-
-    /**
-     * Types of filters to match against the logs. Different filter types will match in different
-     * ways.
-     */
-    @Retention(SOURCE)
-    @IntDef({FILTER_TAG, SUBSTRING})
-    @interface FilterType {}
-    static final int FILTER_TAG = 0;
-    static final int SUBSTRING = 1;
-
-    private final int mLogListenerIndex;
-    private final @FilterType int mFilterType;
-    private final String mFilter;
-
-    LogFilter(int logListenerIndex, @FilterType int filterType, String filter) {
-        this.mLogListenerIndex = logListenerIndex;
-        this.mFilterType = filterType;
-        if (filter == null) {
-            throw new NullPointerException("Null filter");
-        }
-        this.mFilter = filter;
-    }
-
-    int getLogListenerIndex() {
-        return mLogListenerIndex;
-    }
-
-    @LogFilter.FilterType int getFilterType() {
-        return mFilterType;
-    }
-
-    String getFilter() {
-        return mFilter;
-    }
-
-    /**
-     * Creates a LogFilter instance.
-     *
-     * @param logListenerIndex the index of the logListener associated with the filter.
-     * @param filterType the type of filter.
-     * @param filter the value of the filter.
-     * @return created LogFilter instance.
-     */
-    static LogFilter create(int logListenerIndex, @FilterType int filterType, String filter) {
-        return new LogFilter(logListenerIndex, filterType, filter);
-    }
-
-    /**
-     * Builds a List of {@link LogFilter} instances from {@link Manifest} and the logListener name.
-     *
-     * @param manifest {@link Manifest} file that contains list of logListeners.
-     * @param logListenerName the name of the logListener as registered in the {@link Manifest}.
-     * @return List of {@link LogFilter} instances.
-     */
-    static List<LogFilter> buildFilters(Manifest manifest, String logListenerName) {
-        int logListenerIndex = getLogListenerIndexFromName(manifest, logListenerName);
-        if (logListenerIndex == -1) {
-            Log.w(TAG, "log listener with name " + logListenerName
-                    + " does not exist in manifest.");
-            return Collections.unmodifiableList(new ArrayList<>());
-        }
-
-        List<LogFilter> result = new ArrayList<>();
-        result.addAll(
-                manifest.getLogListeners(logListenerIndex).getTagsList().stream()
-                .map(tag -> LogFilter.create(logListenerIndex, FILTER_TAG, tag))
-                .collect(Collectors.toList()));
-        result.addAll(
-                manifest.getLogListeners(logListenerIndex).getTypesList().stream()
-                .map(LogFilter::typeToFilter)
-                .filter(Optional::isPresent)
-                .map(filter ->
-                        LogFilter.create(logListenerIndex, SUBSTRING, filter.get()))
-                .collect(Collectors.toList()));
-        return Collections.unmodifiableList(result);
-    }
-
-    /**
-     * Gets the index of the {@link LogListener} in the manifest's list of logListeners.
-     * Returns -1 if not found.
-     *
-     * @param manifest the {@link Manifest} that contains the definitions of the logListeners.
-     * @param logListenerName name of the {@link LogListener} to get index for.
-     * @return index of the logListener, -1 if not found.
-     */
-    static int getLogListenerIndexFromName(Manifest manifest, String logListenerName) {
-        for (int i = 0; i < manifest.getLogListenersCount(); i++) {
-            LogListener listener = manifest.getLogListeners(i);
-            if (listener.getName().equals(logListenerName)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Converts log message filter {@link LogListener.Type} to corresponding filter string.
-     *
-     * @param type the filter {@link LogListener.Type}.
-     * @return the corresponding filter string for the logListener type.
-     */
-    private static Optional<String> typeToFilter(LogListener.Type type) {
-        switch (type) {
-            case TYPE_UNSPECIFIED:
-                return Optional.empty();
-            case EXCEPTIONS:
-                return Optional.of("Exception: ");
-        }
-        return Optional.empty();
-    }
-
-    /**
-     * Matches in different ways against {@link LogcatReader.LogEntry} components depending on
-     * filterType.
-     *
-     * @param entry the {@link LogcatReader.LogEntry} whose components will be matched against the
-     *       filters.
-     * @return boolean denoting whether the filter can match the {@link LogcatReader.LogEntry}.
-     */
-    boolean matches(LogcatReader.LogEntry entry) {
-        switch (getFilterType()) {
-            case FILTER_TAG:
-                return entry.mTag.equals(getFilter());
-            case SUBSTRING:
-                return entry.mMessage.contains(getFilter());
-        }
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return "LogFilter{"
-                + "mLogListenerIndex=" + mLogListenerIndex + ", "
-                + "mFilterType=" + mFilterType + ", "
-                + "mFilter=" + mFilter
-                + "}";
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-        if (o instanceof LogFilter) {
-            LogFilter that = (LogFilter) o;
-            return this.mLogListenerIndex == that.getLogListenerIndex()
-                    && this.mFilterType == that.getFilterType()
-                    && this.mFilter.equals(that.getFilter());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 1;
-        hash *= 1000003;
-        hash ^= mLogListenerIndex;
-        hash *= 1000003;
-        hash ^= Integer.hashCode(mFilterType);
-        hash *= 1000003;
-        hash ^= mFilter.hashCode();
-        return hash;
-    }
-}
-
diff --git a/service/src/com/android/car/telemetry/LogcatReader.java b/service/src/com/android/car/telemetry/LogcatReader.java
deleted file mode 100644
index a83a72e..0000000
--- a/service/src/com/android/car/telemetry/LogcatReader.java
+++ /dev/null
@@ -1,302 +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.android.car.telemetry;
-
-import android.annotation.Nullable;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.ObjIntConsumer;
-import java.util.function.Supplier;
-
-/**
- * Reads Android logs while there are log listeners registered to it and sends the event through the
- * mLogEventConsumer.
- */
-public class LogcatReader {
-    private static final String TAG = LogcatReader.class.getSimpleName();
-
-    // TODO(b/180515554). Find a proper place for LOG_* constants.
-    // They will be used in ScriptExecutor as well.
-    /** The value of key to retrieve log seconds since epoch time from bundle. */
-    private static final String LOG_SEC_KEY = "log.sec";
-
-    /** The value of key to retrieve log nanoseconds from bundle. */
-    private static final String LOG_NSEC_KEY = "log.nsec";
-
-    /** The value of key to retrieve log tag from bundle. */
-    private static final String LOG_TAG_KEY = "log.tag";
-
-    /** The value of key to retrieve log message from bundle. */
-    private static final String LOG_MESSAGE_KEY = "log.message";
-
-    // Defined in system/core/liblog/include/log/log_read.h
-    private static final int LOGGER_ENTRY_MAX_LEN = 5 * 1024;
-
-    // The entry sizes differ in Android 10. See
-    // https://cs.android.com/android/platform/superproject/+/android-10.0.0_r30:system/core/liblog/include/log/log_read.h
-    public static final int ENTRY_V1_SIZE = 20;
-    public static final int ENTRY_V2_V3_SIZE = 24;
-    public static final int ENTRY_V4_SIZE = 28;
-
-    private final AtomicBoolean mRunning = new AtomicBoolean(false);
-
-    private final ObjIntConsumer<Bundle> mLogEventConsumer;
-    private final Supplier<LocalSocket> mLocalSocketSupplier;
-    private final Executor mExecutor;
-
-    private final HashSet<LogFilter> mLogFilters = new HashSet<>();
-
-    private synchronized boolean logFiltersEmpty() {
-        return mLogFilters.isEmpty();
-    }
-
-    /**
-     * Replicates {@code struct log_msg} from system/core/liblog/include/log/log_read.h and {@code
-     * struct AndroidLogEntry} from system/core/liblog/include/log/logprint.h.
-     */
-    static class LogEntry {
-        long mTvSec; // seconds since Epoch
-        long mTvNSec; // nanoseconds
-        int mPid; // generating process's pid
-        long mTid; // generating process's tid
-        long mUid; // generating process's uid
-        int mPriority; // log priority, e.g. {@link Log#INFO}.
-        String mTag;
-        String mMessage;
-
-        /**
-         * Parses raw bytes received from {@code logd}.
-         *
-         * @param data raw bytes
-         * @param readSize number of bytes received from logd.
-         */
-        @Nullable
-        static LogEntry parse(byte[] data, int readSize) {
-            // Parsing log_msg struct defined in system/core/liblog/include/log/log_read.h.
-            // Only first headerSize is used to create LogEntry. Following message messageSize bytes
-            // define log message.
-            ByteBuffer dataBytes = ByteBuffer.wrap(data);
-            dataBytes.order(ByteOrder.LITTLE_ENDIAN);
-            int messageSize = dataBytes.getShort();
-            int headerSize = dataBytes.getShort();
-            if (readSize < messageSize + headerSize) {
-                Log.w(
-                        TAG, "Invalid log message size "
-                        + (messageSize + headerSize)
-                        + ", received only "
-                        + readSize);
-                return null;
-            }
-            LogEntry entry = new LogEntry();
-            entry.mPid = dataBytes.getInt();
-            entry.mTid = dataBytes.getInt();
-            entry.mTvSec = dataBytes.getInt();
-            entry.mTvNSec = dataBytes.getInt();
-            if (headerSize >= ENTRY_V2_V3_SIZE) {
-                dataBytes.position(dataBytes.position() + 4); // lid is not used here.
-            }
-            if (headerSize >= ENTRY_V4_SIZE) {
-                entry.mUid = dataBytes.getInt();
-            }
-
-            // Parsing log message.
-            // See android_log_processLogBuffer() in system/core/liblog/logprint.cpp for details.
-            // message format: <priority:1><tag:N>\0<message:N>\0
-            // TODO(b/180516393): improve message parsing that were not transferred
-            // from the cpp above. Also verify this mechanism is ok from selinux perspective.
-
-            if (messageSize < 3) {
-                Log.w(TAG, "Log message is too small, size=" + messageSize);
-                return null;
-            }
-            if (headerSize != dataBytes.position()) {
-                Log.w(TAG, "Invalid header size " + headerSize + ", expected "
-                        + dataBytes.position());
-                return null;
-            }
-            int msgStart = -1;
-            int msgEnd = -1;
-            for (int i = 1; i < messageSize; i++) {
-                if (data[headerSize + i] == 0) {
-                    if (msgStart == -1) {
-                        msgStart = i + 1 + headerSize;
-                    } else {
-                        msgEnd = i + headerSize;
-                        break;
-                    }
-                }
-            }
-            if (msgStart == -1) {
-                Log.w(TAG, "Invalid log message");
-                return null;
-            }
-            if (msgEnd == -1) {
-                msgEnd = Math.max(msgStart, messageSize - 1);
-            }
-            entry.mPriority = data[headerSize];
-            entry.mTag =
-                new String(data, headerSize + 1, msgStart - headerSize - 2,
-                    StandardCharsets.US_ASCII);
-            entry.mMessage =
-                    new String(data, msgStart, msgEnd - msgStart, StandardCharsets.US_ASCII);
-            return entry;
-        }
-    }
-
-    /**
-     * Constructs {@link LogcatReader}.
-     *
-     * @param logEventConsumer a consumer that's called when a filter matches a log.
-     * @param localSocketSupplier a supplier for LocalSocket to connect logd.
-     * @param executor an {@link Executor} to run the LogcatReader instance.
-     */
-    public LogcatReader(
-            ObjIntConsumer<Bundle> logEventConsumer,
-            Supplier<LocalSocket> localSocketSupplier,
-            Executor executor) {
-        this.mLogEventConsumer = logEventConsumer;
-        this.mLocalSocketSupplier = localSocketSupplier;
-        this.mExecutor = executor;
-    }
-
-    /** Runs {@link LogcatReader}. */
-    private void run() {
-        Log.d(TAG, "Running LogcatReader");
-
-        // Under the hood, logcat receives logs from logd, to remove the middleman, LogcatReader
-        // doesn't run logcat, but directly connects to logd socket and parses raw logs.
-        try (LocalSocket socket = mLocalSocketSupplier.get()) {
-            // Connect to /dev/socket/logdr
-            socket.connect(new LocalSocketAddress("logdr", LocalSocketAddress.Namespace.RESERVED));
-            try (OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
-                  InputStream reader = socket.getInputStream()) {
-                // Ask for streaming log and set tail=1 to get only new logs.
-                // See system/core/liblog/logd_reader.cpp for example on how to interact with logdr.
-                writer.write("stream tail=1");
-                writer.flush();
-                Log.d(TAG, "Sent request to logd and awaiting for logs");
-
-                byte[] data = new byte[LOGGER_ENTRY_MAX_LEN + 1];
-                while (!logFiltersEmpty()) {
-                    int n = reader.read(data, 0, LOGGER_ENTRY_MAX_LEN);
-                    if (n == -1) {
-                        Log.e(TAG, "Disconnected from logd");
-                        return;
-                    }
-                    LogEntry entry = LogEntry.parse(data, n);
-                    if (entry == null) {
-                        continue;
-                    }
-
-                    // Ignore the logs from the telemetry service. This
-                    // makes sure a recursive log storm does not happen - i.e. app produces a log
-                    // which in turn executes a code path that produces another log.
-                    if (entry.mUid == Process.myUid()) {
-                        continue;
-                    }
-                    // Check if it's running before processing the logs, because by the time we get
-                    // here ScriptExecutor might get disconnected.
-                    if (!mRunning.get()) {
-                        Log.d(TAG, "Not running anymore, exiting.");
-                        return;
-                    }
-                    // Keep track of which logListener an event for this entry has been sent,
-                    // so that the same entry isn't sent multiple times for the same logListener
-                    // if its multiple filters match.
-                    HashSet<Integer> sentLogListenerIndices = new HashSet<>();
-                    for (LogFilter filter : mLogFilters) {
-                        if (!sentLogListenerIndices.contains(filter.getLogListenerIndex())
-                                && filter.matches(entry)) {
-                            sentLogListenerIndices.add(filter.getLogListenerIndex());
-                            sendLogEvent(filter.getLogListenerIndex(), entry);
-                        }
-                    }
-                }
-                Log.d(TAG, "Log filters are empty, exiting.");
-            }
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to connect to logd", e);
-        } finally {
-            mRunning.set(false);
-        }
-    }
-
-    /**
-     * Sends the log event to the through the mLogEventConsumer.
-     *
-     * @param logListenerIndex the index of the logListener, whose function will receive the log
-     *     event.
-     * @param entry the LogEntry instance to be bundled up and sent as event.
-     */
-    private void sendLogEvent(int logListenerIndex, LogEntry entry) {
-        Bundle event = new Bundle();
-        event.putLong(LOG_SEC_KEY, entry.mTvSec);
-        event.putLong(LOG_NSEC_KEY, entry.mTvNSec);
-        event.putString(LOG_TAG_KEY, entry.mTag);
-        event.putString(LOG_MESSAGE_KEY, entry.mMessage);
-        mLogEventConsumer.accept(event, logListenerIndex);
-    }
-
-    /**
-     * Subscribes the list of {@link LogFilter} instances.
-     *
-     * @param newLogFilters the list of new log filters to be added to mLogFilters.
-     */
-    synchronized void subscribeLogFilters(List<LogFilter> newLogFilters) {
-        mLogFilters.addAll(newLogFilters);
-    }
-
-    /**
-     * Unsubscribes all {@link LogFilter} associated with the logListenerIndex
-     *
-     * @param logListenerIndex the index of the logListener to unregister.
-     */
-    synchronized void unsubscribeLogListener(int logListenerIndex) {
-        mLogFilters.removeIf(lf -> lf.getLogListenerIndex() == logListenerIndex);
-    }
-
-    /** Starts the run method in a new thread if logcatReader isn't running already. */
-    void startAsyncIfNotStarted() {
-        if (mRunning.compareAndSet(false, true)) {
-            mExecutor.execute(this::run);
-        }
-    }
-
-    /** Gracefully stops {@link LogcatReader}. */
-    synchronized void stop() {
-        mRunning.set(false);
-        mLogFilters.clear();
-    }
-
-    /** Builds a {@link LocalSocket} to read from {@code logdr}. */
-    static LocalSocket buildLocalSocket() {
-        return new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
-    }
-}
diff --git a/service/src/com/android/car/telemetry/README.md b/service/src/com/android/car/telemetry/README.md
new file mode 100644
index 0000000..a2aee72
--- /dev/null
+++ b/service/src/com/android/car/telemetry/README.md
@@ -0,0 +1,28 @@
+<!--
+  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
+  -->
+
+# CarTelemetryService
+
+Source code for AAOS OEM Telemetry solution.
+
+
+## Enabling CarTelemetryService
+
+CarTelemetryService can be enabled with
+
+```
+adb shell cmd car_service enable-feature car_telemetry_service
+```
diff --git a/service/src/com/android/car/telemetry/databroker/DataBroker.java b/service/src/com/android/car/telemetry/databroker/DataBroker.java
new file mode 100644
index 0000000..4f96966
--- /dev/null
+++ b/service/src/com/android/car/telemetry/databroker/DataBroker.java
@@ -0,0 +1,62 @@
+/*
+ * 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.android.car.telemetry.databroker;
+
+import android.os.Bundle;
+
+import com.android.car.telemetry.TelemetryProto;
+
+import java.util.List;
+
+/** Interface for the data path. Handles data forwarding from publishers to subscribers */
+public interface DataBroker {
+
+    /**
+     * ScriptResultListener is the listener for script results.
+     */
+    public interface ScriptResultListener {
+        /**
+         * Notifies listener of script result.
+         *
+         * @param scriptResult the script result.
+         */
+        void onScriptResult(Bundle scriptResult);
+    }
+
+    /**
+     * Updates the set of publishers whose data can be consumed by subscribers.
+     *
+     * @param allowedPublishers the types publisher data source that can be consumed. The class is
+     *                          generated by Protobuf oneof fields.
+     * @see
+     * <a href="https://developers.google.com/protocol-buffers/docs/reference/java-generated#oneof-fields">Oneof
+     * Fields Generated Code</a>
+     */
+    void enablePublishers(List<TelemetryProto.Publisher.PublisherCase> allowedPublishers);
+
+    /**
+     * Adds an active {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} that is pending
+     * execution.
+     */
+    void addMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
+
+    /**
+     * Removes a {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} and all its
+     * relevant subscriptions.
+     */
+    void removeMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
+}
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
new file mode 100644
index 0000000..ab449e8
--- /dev/null
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
@@ -0,0 +1,60 @@
+/*
+ * 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.android.car.telemetry.databroker;
+
+import android.os.Bundle;
+
+import com.android.car.telemetry.TelemetryProto.MetricsConfig;
+import com.android.car.telemetry.TelemetryProto.Publisher.PublisherCase;
+
+import java.util.ArrayList;
+
+/**
+ * DataBrokerController instantiates the DataBroker and manages what Publishers
+ * it can read from based current system states and policies.
+ */
+public class DataBrokerController {
+
+    private MetricsConfig mMetricsConfig;
+    private final DataBroker mDataBroker;
+    private final ArrayList<PublisherCase> mAllowedPublishers = new ArrayList<>();
+
+    public DataBrokerController() {
+        mDataBroker = new DataBrokerImpl(this::onScriptResult);
+        mAllowedPublishers.add(PublisherCase.VEHICLE_PROPERTY);
+        mDataBroker.enablePublishers(mAllowedPublishers);
+    }
+
+    /**
+     * Listens to script result from {@link DataBroker}.
+     *
+     * @param scriptResult the script result.
+     */
+    public void onScriptResult(Bundle scriptResult) {
+        // TODO(b/187744195)
+    }
+
+    /**
+     * Listens to new {@link MetricsConfig}.
+     *
+     * @param metricsConfig the metrics config.
+     */
+    public void onNewMetricsConfig(MetricsConfig metricsConfig) {
+        mMetricsConfig = metricsConfig;
+        mDataBroker.addMetricsConfiguration(mMetricsConfig);
+    }
+}
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
new file mode 100644
index 0000000..ff12dc2
--- /dev/null
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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.android.car.telemetry.databroker;
+
+import com.android.car.telemetry.TelemetryProto;
+
+import java.util.List;
+
+/**
+ * Implementation of the data path component of CarTelemetryService. Forwards the published data
+ * from publishers to consumers subject to the Controller's decision.
+ */
+public class DataBrokerImpl implements DataBroker {
+
+    private final ScriptResultListener mScriptResultListener;
+
+    public DataBrokerImpl(ScriptResultListener scriptResultListener) {
+        mScriptResultListener = scriptResultListener;
+    }
+
+    @Override
+    public void enablePublishers(List<TelemetryProto.Publisher.PublisherCase> allowedPublishers) {
+        // TODO(b/187743369): implement
+    }
+
+    @Override
+    public void addMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig) {
+        // TODO(b/187743369): implement
+    }
+
+    @Override
+    public void removeMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig) {
+        // TODO(b/187743369): implement
+    }
+}
diff --git a/service/src/com/android/car/telemetry/proto/telemetry.proto b/service/src/com/android/car/telemetry/proto/telemetry.proto
index 422c4a2..5787d62 100644
--- a/service/src/com/android/car/telemetry/proto/telemetry.proto
+++ b/service/src/com/android/car/telemetry/proto/telemetry.proto
@@ -21,50 +21,35 @@
 option java_package = "com.android.car.telemetry";
 option java_outer_classname = "TelemetryProto";
 
-// A Tpk (Telemetry Package) manifest.
-// It contains a script and the rules how the script runs on devices.
-message Manifest {
+// A metrics configuration.
+//
+// The metrics configuration describes a metric that is collected from a device.
+// It includes a declarative part that configures the metric and the data publisher
+// and a data handler to process the data and create a statistic.
+// The latter is written in Lua language.
+message MetricsConfig {
   // Required.
-  // Name of the Tpk, used to distinguish TPKs.
+  // The name of the configuration. Must be unique within a device.
   // Only alphanumeric and _ characters are allowed. Minimum length is 3 chars.
   optional string name = 1;
 
   // Required.
-  // A script that is executed in devices. Must contain all the functions
-  // defined in the listeners below.
-  optional string script = 2;
+  // Version number of the configuration.
+  optional int32 version = 2;
 
   // Required.
-  // A unique version number of the Tpk, used to distinguish between Tpks of the
-  // same name.
-  optional int32 version = 3;
+  // A script that is executed in devices. Must contain all the handler functions
+  // defined in the listeners below.
+  // The script functions must be `pure` functions.
+  optional string script = 3;
 
-  // Telemetry service subscribes these listeners to vehicle property change events.
-  // The functions must be present in the script.
-  repeated PropertyChangeListener property_change_listeners = 4;
-
-  // Telemetry service subscribes these listeners to Android log (logcat) events.
-  // The functions must be present in the script.
-  repeated LogListener log_listeners = 5;
-
-  // Telemetry service subscribes these listeners to stats anomalies, such as
-  // Alerts, Alarms, stats out-of-space anomaly and historical data anomaly.
-  // The number of listener is limited to 10 by statsd.
-  // The functions must be present in the script.
-  repeated StatsListener stats_listeners = 6;
-
-  // Dumpsys result listeners can be registered to retrieve dump report for
-  // specified report types.
-  // The functions must be present in the script.
-  repeated DumpsysResultListener dumpsys_result_listeners = 7;
-
-  // This timer executes functions when a specific event happens.
-  // The functions must be present in the script.
-  repeated Timer timers = 8;
+  // Required.
+  repeated Subscriber subscribers = 4;
 }
 
-// A function that is executed when a vehicle property change events occur.
-message PropertyChangeListener {
+// Parameters for Vehicle Properties publisher.
+// See https://source.android.com/devices/automotive/vhal/properties
+message VehiclePropertyPublisher {
   // Required.
   // See packages/services/Car/car-lib/src/android/car/VehiclePropertyIds.java
   optional int32 vehicle_property_id = 1;
@@ -73,197 +58,21 @@
   // packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java
   // look for constants SENSOR_RATE_*;
   optional float read_rate = 2;
-
-  // Required.
-  optional string function_name = 3;
 }
 
-// A function that receives Android log (logcat) events. The log event is passed
-// as a string argument to the function.
-//
-// The LogListener will receive log events if the log event matches any of the
-// "types" or "tags".
-//
-// Please see ../README.md for details.
-//
-// Example:
-//   function processException(log_event_line) ... end
-message LogListener {
-  enum Type {
-    // Default value.
-    TYPE_UNSPECIFIED = 0;
-
-    // Matches logged exceptions.
-    EXCEPTIONS = 1;
+// Specifies data publisher and its parameters.
+message Publisher {
+  oneof publisher {
+    VehiclePropertyPublisher vehicle_property = 1;
   }
-
-  // Required.
-  // Unique name of the logListener within the Tpk. Used to
-  // subscribe/unsubscribe from log events.
-  optional string name = 1;
-
-  // Required.
-  // Name of the function to be executed when the logs the logListener has a
-  // match with its filters
-  optional string function_name = 2;
-
-  // Message types to listen to in LogCat.
-  // At least one "types" or "tags" must be provided.
-  repeated Type types = 3;
-
-  // Tags to listen to in LogCat.
-  // At least one "types" or "tags" must be provided.
-  repeated string tags = 4;
 }
 
-// A function that receives stats reports.
-//
-// LogProcessor App provides limited statsd support. Please see
-// logprocessor/README.md for details.
-//
-// Script function semantics:
-//    -- Param report_list is a table with 1-1 mapping
-//                         to ConfigMetricsReportList.
-//    -- Param extra_stats is a table { config_uid, config_key, ... } coming
-//    --  from PendingIntent described in StatsManager#setBroadcastSubscriber().
-//    function onStatdEvent(report_list, extra_stats) end
-message StatsListener {
-  // Function to be called when the subscriptions below get triggered.
-  optional string function_name = 1;
+// Specifies publisher with its parameters and the handler function that's invoked
+// when data is received. The format of the data depends on the Publisher.
+message Subscriber {
+  // Name of the script function that's invoked when this subscriber is triggered.
+  optional string handler = 1;
 
-  // Serialized StatsdConfig defined in
-  // AOSP/frameworks/base/cmds/statsd/src/statsd_config.proto
-  // NOTE: Config ID and other generated IDs must be unique within this
-  //       statsd_config.
-  optional bytes statsd_config = 2;
-
-  // Subscribe the telemetry service to stats broadcast events: Alarms and Alerts.
-  // Subscriptions must be defined in the statsd_config as
-  // BroadcastSubscriberDetails.
-  // NOTE: It must be unique within the statsd_config.
-  optional int64 subscriber_id = 3;
-}
-
-// A function that receives Dumpsys reports.
-//
-// The DumpsysResultListener will receive dumpsys reports of the specified
-// DumpsysReportType
-message DumpsysResultListener {
-  // Names of the system services that's allowed to run dumpsys on.
-  enum SystemServiceName {
-    UNSPECIFIED = 0;
-
-    // Matches car service com.android.car.CarService.
-    CAR_SERVICE = 1;
-
-    // Matches package manager service
-    // com.android.server.pm.PackageManagerService.
-    PACKAGE = 2;  //
-  }
-
-  // Required.
-  // Unique name of the DumpsysResultListener within the Tpk.
-  // Used to register the specific DumpsysResultListener needed.
-  optional string name = 1;
-
-  // Required.
-  // Name of the function to be executed when a dumpsys report of the specified
-  // system services are retrieved.
-  optional string function_name = 2;
-
-  // Required.
-  // System service to run dumpsys for.
-  optional SystemServiceName system_service_name = 3;
-
-  // Extra arguments for dumpsys
-  optional string arguments = 4;
-}
-
-// Runs a script function after some delay when an event happens.
-message Timer {
-  enum TriggerType {
-    TRIGGER_TYPE_UNSPECIFIED = 0;
-
-    // When the device boots up.
-    //
-    // Note that when device wakes up from a deep sleep (suspend to ram), this
-    // trigger doesn't work.
-    //
-    // It doesn't guarantee immediate activation of the timer right after the
-    // boot, only after the system and the script is ready.
-    // "initial_delay_millis" parameter denotes a delay from boot (not from
-    // the script is initialized and ready).
-    TRIGGER_TYPE_BOOT = 1;
-  }
-
-  // Required.
-  // Name of the script function that will be executed.
-  optional string function_name = 1;
-
-  // Required.
-  // An event trigger that activates this timer.
-  optional TriggerType trigger_type = 2;
-
-  // Required.
-  // Delay after the trigger event before initial executing the function.
-  //
-  // Be careful putting long delays (>30 minutes), because the average
-  // driving duration might be shorter than the delay, and the function
-  // will be executed less frequently than desired amount.
-  optional int64 initial_delay_millis = 3;
-
-  // The max number of times the function will be periodically executed.
-  // When this number of execution is reached, the timer will be stopped.
-  // 0 means the timer is disabled.
-  // -1 means the timer never stops.
-  optional int32 max_count = 4;
-
-  // Time between successive function executions if max_count >= 2.
-  optional int64 period_millis = 5;
-}
-
-// A message that encapsulates different types of error or log metadata as
-// for informational and debugging purposes.
-//
-// When the app crashes or the system restarts, the timers will reset.
-message SecularTrendsLog {
-  // Required.
-  optional int64 timestamp = 1;
-
-  enum LogType {
-    // Default enum.
-    UNSPECIFIED = 0;
-
-    // Used when manifest is misconfigurated, such as missing required fields.
-    MANIFEST_MISCONFIGURATION = 1;
-
-    // Used when a Java service throws an exception.
-    JAVA_EXCEPTION = 2;
-
-    // Used when LogProc service failes to bind to sandbox service.
-    SANDBOX_SERVICE_CONNECTION_FAILURE = 3;
-
-    // Used when an error occurs in the native code.
-    NATIVE_RUNTIME_ERROR = 4;
-
-    // Used when an error occurs while executing the Lua script (such as
-    // errors returned by lua_pcall)
-    LUA_RUNTIME_ERROR = 5;
-
-    // Used when a service that telemetry service depends on crashes or fails.
-    DEPENDENT_SERVICE_FAILURE = 6;
-  }
-
-  // Required.
-  // A type that indicates where the log is generated.
-  optional LogType type = 2;
-
-  // Required.
-  // Human readable message explaining what’s wrong or how to fix it.
-  optional string message = 3;
-
-  // Optional.
-  // If there is an exception, there will be stack trace. However this
-  // information is not always available.
-  optional string stack_trace = 4;
+  // Publisher and its parameters.
+  optional Publisher publisher = 2;
 }
diff --git a/service/src/com/android/car/telemetry/publisher/LogcatPublisher.java b/service/src/com/android/car/telemetry/publisher/LogcatPublisher.java
new file mode 100644
index 0000000..a8795c2
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/LogcatPublisher.java
@@ -0,0 +1,36 @@
+/*
+ * 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.android.car.telemetry.publisher;
+
+import com.android.car.telemetry.Channel;
+
+/**
+ * Publisher for Android logs (adb logcat).
+ *
+ * TODO(b/187525360): Move the logic from LogcatReader here.
+ */
+public class LogcatPublisher implements Publisher {
+    /** See {@link Publisher#addChannel()} for details. */
+    public void addChannel(Channel channel) {
+        // TODO(b/187525360): implement
+    }
+
+    /** See {@link Publisher#removeChannel()} for details. */
+    public void removeChannel(Channel channel) {
+        // TODO(b/187525360): implement
+    }
+}
diff --git a/service/src/com/android/car/telemetry/publisher/Publisher.java b/service/src/com/android/car/telemetry/publisher/Publisher.java
new file mode 100644
index 0000000..5962711
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/Publisher.java
@@ -0,0 +1,45 @@
+/*
+ * 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.android.car.telemetry.publisher;
+
+import com.android.car.telemetry.Channel;
+
+/**
+ * Interface for publishers. It's implemented per data source, data is sent to {@link Channel}.
+ * Publisher stops itself when there are no channels.
+ *
+ * <p>Note that it doesn't map 1-1 to {@link TelemetryProto.Publisher} configuration. Single
+ * publisher instance can send data as several {@link TelemetryProto.Publisher} to subscribers.
+ */
+public interface Publisher {
+    /**
+     * Adds a channel to the publisher. Publisher will immediately start pushing
+     * data to the channel.
+     *
+     * @param channel a channel to publish data.
+     *
+     * @throws IllegalArgumentException if the channel was added before.
+     */
+    void addChannel(Channel channel);
+
+    /**
+     * Removes the channel from the publisher.
+     *
+     * @throws IllegalArgumentException if the channel was not found.
+     */
+    void removeChannel(Channel channel);
+}
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 52799cf..0e8e9f2 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -791,6 +791,8 @@
 
         if (!isUserHalSupported()) {
             fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest);
+            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ_COMPLETE,
+                    requestType);
             return;
         }
 
@@ -843,6 +845,8 @@
                 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
                 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
             }
+            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ_COMPLETE,
+                    requestType);
         });
     }
 
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 8a83a9d..86858d4 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -137,6 +137,7 @@
      */
     @Override
     public void registerClient(ICarWatchdogServiceCallback client, int timeout) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         mWatchdogProcessHandler.registerClient(client, timeout);
     }
 
@@ -146,6 +147,7 @@
      */
     @Override
     public void unregisterClient(ICarWatchdogServiceCallback client) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         mWatchdogProcessHandler.unregisterClient(client);
     }
 
@@ -154,6 +156,7 @@
      */
     @Override
     public void tellClientAlive(ICarWatchdogServiceCallback client, int sessionId) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         mWatchdogProcessHandler.tellClientAlive(client, sessionId);
     }
 
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index feff1ef..8d15e0f 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -87,6 +87,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 
 /**
  * Handles system resource performance monitoring module.
@@ -112,11 +113,11 @@
     private final List<PackageResourceOveruseAction> mOveruseActionsByUserPackage =
             new ArrayList<>();
     @GuardedBy("mLock")
-    private final SparseArray<ResourceOveruseListenerInfo> mOveruseListenerInfosByUid =
+    private final SparseArray<ArrayList<ResourceOveruseListenerInfo>> mOveruseListenerInfosByUid =
             new SparseArray<>();
     @GuardedBy("mLock")
-    private final SparseArray<ResourceOveruseListenerInfo> mOveruseSystemListenerInfosByUid =
-            new SparseArray<>();
+    private final SparseArray<ArrayList<ResourceOveruseListenerInfo>>
+            mOveruseSystemListenerInfosByUid = new SparseArray<>();
     /* Set of safe-to-kill system and vendor packages. */
     @GuardedBy("mLock")
     public final Set<String> mSafeToKillPackages = new ArraySet<>();
@@ -516,7 +517,7 @@
         synchronized (mLock) {
             checkAndHandleDateChangeLocked();
             for (PackageIoOveruseStats stats : packageIoOveruseStats) {
-                String packageName = packageNamesByUid.get(stats.uid, null);
+                String packageName = packageNamesByUid.get(stats.uid);
                 if (packageName == null) {
                     continue;
                 }
@@ -640,27 +641,19 @@
     private void notifyResourceOveruseStatsLocked(int uid,
             ResourceOveruseStats resourceOveruseStats) {
         String packageName = resourceOveruseStats.getPackageName();
-        ResourceOveruseListenerInfo listenerInfo = mOveruseListenerInfosByUid.get(uid, null);
-        if (listenerInfo != null && (listenerInfo.flag & FLAG_RESOURCE_OVERUSE_IO) != 0) {
-            try {
-                listenerInfo.listener.onOveruse(resourceOveruseStats);
-            } catch (RemoteException e) {
-                Slogf.e(TAG, e, "Failed to notify listener(uid %d, package '%s') on resource "
-                        + "overuse", uid, resourceOveruseStats);
+        ArrayList<ResourceOveruseListenerInfo> listenerInfos = mOveruseListenerInfosByUid.get(uid);
+        if (listenerInfos != null) {
+            for (ResourceOveruseListenerInfo listenerInfo : listenerInfos) {
+                listenerInfo.notifyListener(FLAG_RESOURCE_OVERUSE_IO, uid, packageName,
+                        resourceOveruseStats);
             }
         }
         for (int i = 0; i < mOveruseSystemListenerInfosByUid.size(); ++i) {
-            ResourceOveruseListenerInfo systemListenerInfo =
+            ArrayList<ResourceOveruseListenerInfo> systemListenerInfos =
                     mOveruseSystemListenerInfosByUid.valueAt(i);
-            if ((systemListenerInfo.flag & FLAG_RESOURCE_OVERUSE_IO) == 0) {
-                continue;
-            }
-            try {
-                systemListenerInfo.listener.onOveruse(resourceOveruseStats);
-            } catch (RemoteException e) {
-                Slogf.e(TAG, e, "Failed to notify system listener(uid %d, pid: %d) of resource "
-                        + "overuse by package(uid %d, package '%s')", systemListenerInfo.uid,
-                        systemListenerInfo.pid, uid, packageName);
+            for (ResourceOveruseListenerInfo listenerInfo : systemListenerInfos) {
+                listenerInfo.notifyListener(FLAG_RESOURCE_OVERUSE_IO, uid, packageName,
+                        resourceOveruseStats);
             }
         }
         if (DEBUG) {
@@ -744,17 +737,21 @@
     private void addResourceOveruseListenerLocked(
             @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
             @NonNull IResourceOveruseListener listener,
-            SparseArray<ResourceOveruseListenerInfo> listenerInfosByUid) {
+            SparseArray<ArrayList<ResourceOveruseListenerInfo>> listenerInfosByUid) {
         int callingPid = Binder.getCallingPid();
         int callingUid = Binder.getCallingUid();
         boolean isListenerForSystem = listenerInfosByUid == mOveruseSystemListenerInfosByUid;
         String listenerType = isListenerForSystem ? "resource overuse listener for system" :
                 "resource overuse listener";
 
-        ResourceOveruseListenerInfo existingListenerInfo = listenerInfosByUid.get(callingUid, null);
-        if (existingListenerInfo != null) {
-            IBinder binder = listener.asBinder();
-            if (existingListenerInfo.listener.asBinder() == binder) {
+        IBinder binder = listener.asBinder();
+        ArrayList<ResourceOveruseListenerInfo> listenerInfos = listenerInfosByUid.get(callingUid);
+        if (listenerInfos == null) {
+            listenerInfos = new ArrayList<>();
+            listenerInfosByUid.put(callingUid, listenerInfos);
+        }
+        for (ResourceOveruseListenerInfo listenerInfo : listenerInfos) {
+            if (listenerInfo.listener.asBinder() == binder) {
                 throw new IllegalStateException(
                         "Cannot add " + listenerType + " as it is already added");
             }
@@ -768,49 +765,44 @@
             Slogf.w(TAG, "Cannot add %s: linkToDeath to listener failed", listenerType);
             return;
         }
-
-        if (existingListenerInfo != null) {
-            Slogf.w(TAG, "Overwriting existing %s: pid %d, uid: %d", listenerType,
-                    existingListenerInfo.pid, existingListenerInfo.uid);
-            existingListenerInfo.unlinkToDeath();
-        }
-
-
-        listenerInfosByUid.put(callingUid, listenerInfo);
+        listenerInfos.add(listenerInfo);
         if (DEBUG) {
-            Slogf.d(TAG, "The %s (pid: %d, uid: %d) is added", listenerType, callingPid,
-                    callingUid);
+            Slogf.d(TAG, "The %s (pid: %d, uid: %d) is added", listenerType,
+                    callingPid, callingUid);
         }
     }
 
     private void removeResourceOveruseListenerLocked(@NonNull IResourceOveruseListener listener,
-            SparseArray<ResourceOveruseListenerInfo> listenerInfosByUid) {
+            SparseArray<ArrayList<ResourceOveruseListenerInfo>> listenerInfosByUid) {
         int callingUid = Binder.getCallingUid();
-
         String listenerType = listenerInfosByUid == mOveruseSystemListenerInfosByUid
                 ? "resource overuse system listener" : "resource overuse listener";
-
-        ResourceOveruseListenerInfo listenerInfo = listenerInfosByUid.get(callingUid, null);
-        if (listenerInfo == null || listenerInfo.listener.asBinder() != listener.asBinder()) {
+        ArrayList<ResourceOveruseListenerInfo> listenerInfos = listenerInfosByUid.get(callingUid);
+        if (listenerInfos == null) {
             Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
             return;
         }
-        listenerInfo.unlinkToDeath();
-        listenerInfosByUid.remove(callingUid);
-        if (DEBUG) {
-            Slogf.d(TAG, "The %s (pid: %d, uid: %d) is removed", listenerType, listenerInfo.pid,
-                    listenerInfo.uid);
-        }
-    }
-
-    private void onResourceOveruseListenerDeath(int uid, boolean isListenerForSystem) {
-        synchronized (mLock) {
-            if (isListenerForSystem) {
-                mOveruseSystemListenerInfosByUid.remove(uid);
-            } else {
-                mOveruseListenerInfosByUid.remove(uid);
+        IBinder binder = listener.asBinder();
+        ResourceOveruseListenerInfo cachedListenerInfo = null;
+        for (ResourceOveruseListenerInfo listenerInfo : listenerInfos) {
+            if (listenerInfo.listener.asBinder() == binder) {
+                cachedListenerInfo = listenerInfo;
+                break;
             }
         }
+        if (cachedListenerInfo == null) {
+            Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
+            return;
+        }
+        cachedListenerInfo.unlinkToDeath();
+        listenerInfos.remove(cachedListenerInfo);
+        if (listenerInfos.isEmpty()) {
+            listenerInfosByUid.remove(callingUid);
+        }
+        if (DEBUG) {
+            Slogf.d(TAG, "The %s (pid: %d, uid: %d) is removed", listenerType,
+                    cachedListenerInfo.pid, cachedListenerInfo.uid);
+        }
     }
 
     @GuardedBy("mLock")
@@ -1306,10 +1298,42 @@
         public void binderDied() {
             Slogf.w(TAG, "Resource overuse listener%s (pid: %d) died",
                     isListenerForSystem ? " for system" : "", pid);
-            onResourceOveruseListenerDeath(uid, isListenerForSystem);
+            Consumer<SparseArray<ArrayList<ResourceOveruseListenerInfo>>> removeListenerInfo =
+                    listenerInfosByUid -> {
+                        ArrayList<ResourceOveruseListenerInfo> listenerInfos =
+                                listenerInfosByUid.get(uid);
+                        if (listenerInfos == null) {
+                            return;
+                        }
+                        listenerInfos.remove(this);
+                        if (listenerInfos.isEmpty()) {
+                            listenerInfosByUid.remove(uid);
+                        }
+                    };
+            if (isListenerForSystem) {
+                removeListenerInfo.accept(mOveruseSystemListenerInfosByUid);
+            } else {
+                removeListenerInfo.accept(mOveruseListenerInfosByUid);
+            }
             unlinkToDeath();
         }
 
+        public void notifyListener(@CarWatchdogManager.ResourceOveruseFlag int resourceType,
+                int overusingUid, String overusingPackage,
+                ResourceOveruseStats resourceOveruseStats) {
+            if ((flag & resourceType) == 0) {
+                return;
+            }
+            try {
+                listener.onOveruse(resourceOveruseStats);
+            } catch (RemoteException e) {
+                Slogf.e(TAG, "Failed to notify %s (uid %d, pid: %d) of resource overuse by "
+                                + "package(uid %d, package '%s'): %s",
+                        (isListenerForSystem ? "system listener" : "listener"), uid, pid,
+                        overusingUid, overusingPackage, e);
+            }
+        }
+
         private void linkToDeath() throws RemoteException {
             listener.asBinder().linkToDeath(this, 0);
         }
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
index baf7675..f0cb1e7 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
@@ -492,7 +492,8 @@
     static void showBugReportFinishedNotification(Context context, MetaBugReport bug) {
         Intent intent = new Intent(context, BugReportInfoActivity.class);
         PendingIntent startBugReportInfoActivity =
-                PendingIntent.getActivity(context, 0, intent, 0);
+                PendingIntent.getActivity(context.getApplicationContext(),
+                        /* requestCode= */ 0, intent, PendingIntent.FLAG_IMMUTABLE);
         Notification notification = new Notification
                 .Builder(context, STATUS_CHANNEL_ID)
                 .setContentTitle(context.getText(R.string.notification_bugreport_finished_title))
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index 6cc9160..098c7b2 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -156,6 +156,9 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".insets.WindowInsetsTestActivity"
+                  android:label="@string/window_insets_test_activity"/>
+
         <meta-data android:name="android.car.application"
              android:resource="@xml/automotive_app_desc"/>
 
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/fullscreen_activity.xml b/tests/EmbeddedKitchenSinkApp/res/layout/fullscreen_activity.xml
new file mode 100644
index 0000000..5c0957d
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/fullscreen_activity.xml
@@ -0,0 +1,27 @@
+<?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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:id="@+id/cancel_button"
+        android:text="@string/cancel"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/toggle_fullscreen_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/toggle_fullscreen_fragment.xml
new file mode 100644
index 0000000..890a6b2
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/toggle_fullscreen_fragment.xml
@@ -0,0 +1,27 @@
+<?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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/show_full_screen_button"
+        android:layout_gravity="center"
+        android:text="@string/nav_to_full_screen"/>
+</FrameLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index d02cce7..0613b45 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -366,10 +366,15 @@
     <string name="empty_activity" translatable="false">Empty Activity</string>
     <string name="audio_auto_start_activity" translatable="false">Audio Auto Start Activity</string>
     <string name="occupant_zone_start_activity" translatable="false">Occupant Zone Start Activity</string>
+    <string name="window_insets_test_activity" translatable="false">Window Insets Test Activity</string>
 
     <!-- ExperimentalFeatureTest -->
     <string name="experimental_ping" translatable="false">Ping Service</string>
 
     <!-- User Profile -->
     <string name="status_message_title">Status Message</string>
+
+    <!-- Fullscreen Activity Test -->
+    <string name="nav_to_full_screen" translatable="false">Navigate to Full Screen</string>
+    <string name="cancel" translatable="false">Cancel</string>
 </resources>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index 5012f46..beeac2a 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -59,6 +59,7 @@
 import com.google.android.car.kitchensink.displayinfo.DisplayInfoFragment;
 import com.google.android.car.kitchensink.experimental.ExperimentalFeatureTestFragment;
 import com.google.android.car.kitchensink.hvac.HvacTestFragment;
+import com.google.android.car.kitchensink.insets.WindowInsetsFullScreenFragment;
 import com.google.android.car.kitchensink.notification.NotificationFragment;
 import com.google.android.car.kitchensink.orientation.OrientationTestFragment;
 import com.google.android.car.kitchensink.packageinfo.PackageInfoFragment;
@@ -211,7 +212,9 @@
             new FragmentMenuEntry("vehicle hal", VehicleHalFragment.class),
             new FragmentMenuEntry("volume test", VolumeTestFragment.class),
             new FragmentMenuEntry("watchdog", CarWatchdogTestFragment.class),
-            new FragmentMenuEntry("web links", WebLinksTestFragment.class));
+            new FragmentMenuEntry("web links", WebLinksTestFragment.class),
+            new FragmentMenuEntry("window insets full screen",
+                    WindowInsetsFullScreenFragment.class));
 
     private Car mCarApi;
     private CarHvacManager mHvacManager;
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsFullScreenFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsFullScreenFragment.java
new file mode 100644
index 0000000..4140598
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsFullScreenFragment.java
@@ -0,0 +1,59 @@
+/*
+ * 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.kitchensink.insets;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+/**
+ * Test fragment showing the transition to a full screen activity {@link WindowInsetsTestActivity}.
+ *
+ * The current fragment {@link WindowInsetsFullScreenFragment} and the activity
+ * {@link WindowInsetsTestActivity} has a view defined at the center of the screen to show the UX
+ * transition to/from full screen activity for fast tap cases.
+ */
+public final class WindowInsetsFullScreenFragment extends Fragment {
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable  ViewGroup container,
+            @Nullable  Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.toggle_fullscreen_fragment, container, false);
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        Button showFullScrnBtn = view.requireViewById(R.id.show_full_screen_button);
+        showFullScrnBtn.setOnClickListener(l -> navToFullScreen());
+    }
+
+    private void navToFullScreen() {
+        Intent intent = new Intent(getActivity(), WindowInsetsTestActivity.class);
+        startActivity(intent);
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsTestActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsTestActivity.java
new file mode 100644
index 0000000..0afe369
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsTestActivity.java
@@ -0,0 +1,51 @@
+/*
+ * 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.kitchensink.insets;
+
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsetsController;
+
+import androidx.annotation.Nullable;
+
+import com.google.android.car.kitchensink.R;
+
+/**
+ * {@link WindowInsetsTestActivity} shows usage of {@link WindowInsetsController} api's to hide
+ * systems bars to present the activity in full screen.
+ */
+public final class WindowInsetsTestActivity extends Activity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        hideSysUI();
+
+        setContentView(R.layout.fullscreen_activity);
+        findViewById(R.id.cancel_button).setOnClickListener(l -> finish());
+    }
+
+    private void hideSysUI() {
+        View decorView = getWindow().getDecorView();
+        WindowInsetsController windowInsetsController = decorView.getWindowInsetsController();
+        windowInsetsController.hide(WindowInsets.Type.systemBars());
+        windowInsetsController.setSystemBarsBehavior(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
+    }
+}
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
index 43f07f4..18ee4a8 100644
--- a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
+++ b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
@@ -18,6 +18,9 @@
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.METERED_ALL;
 import static android.net.NetworkStats.ROAMING_ALL;
+import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION;
+
+import static java.util.concurrent.TimeUnit.HOURS;
 
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
@@ -32,6 +35,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.Pair;
 
@@ -76,7 +80,14 @@
         mConnectivityManager = context.getSystemService(ConnectivityManager.class);
         mNetStatsMan = context.getSystemService(NetworkStatsManager.class);
         mMetricMessageHandler = handler;
-        mStartTime = System.currentTimeMillis();
+
+        /* If the start time is set to the current time without accounting for bucket duration,
+           the reported rx/tx bytes will be inaccurate, since bucket sizes are on the order of
+           hours. This will manifest itself as the rx/tx values slowly climbing, even when there is
+           no network traffic. Setting the start time to one bucket duration prior to the current
+           time seems to fix this issue. */
+        mStartTime = System.currentTimeMillis() - Settings.Global.getLong(
+                mContext.getContentResolver(), NETSTATS_UID_BUCKET_DURATION, HOURS.toMillis(2));
 
         scanAndPrintOemNetworksIfExist();
     }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
index 1ff7911..799e569 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
@@ -26,13 +26,16 @@
 import static org.junit.Assume.assumeFalse;
 
 import android.annotation.NonNull;
+import android.app.UiAutomation;
 import android.car.Car;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ServiceConnection;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
 import android.os.Build;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.Log;
@@ -44,6 +47,11 @@
 import org.junit.Rule;
 import org.junit.rules.TestName;
 
+import java.io.BufferedReader;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
@@ -138,6 +146,8 @@
     protected static void suspendToRamAndResume() throws Exception {
         Log.d(TAG, "Emulate suspend to RAM and resume");
         PowerManager powerManager = sContext.getSystemService(PowerManager.class);
+        // clear log
+        runShellCommand("logcat -b all -c");
         runShellCommand("cmd car_service suspend");
         // Check for suspend success
         waitUntil("screen is still on after suspend",
@@ -146,6 +156,40 @@
         // Force turn off garage mode
         runShellCommand("cmd car_service garage-mode off");
         runShellCommand("cmd car_service resume");
+        waitForLogcatMessage("logcat -b events", "car_user_svc_initial_user_info_req_complete: "
+                + InitialUserInfoRequestType.RESUME, 60_000);
+    }
+
+    /**
+     * Wait for a particular logcat message.
+     *
+     * @param cmd is logcat command with buffer or filters
+     * @param match is the string to be found in the log
+     * @param timeoutMs for which call should wait for the match
+     */
+    protected static void waitForLogcatMessage(String cmd, String match, int timeoutMs) {
+        Log.d(TAG, "waiting for logcat match: " + match);
+        long startTime = SystemClock.elapsedRealtime();
+        UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        ParcelFileDescriptor output = automation.executeShellCommand(cmd);
+        FileDescriptor fd = output.getFileDescriptor();
+        FileInputStream fileInputStream = new FileInputStream(fd);
+        try (BufferedReader bufferedReader = new BufferedReader(
+                new InputStreamReader(fileInputStream))) {
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                if (line.contains(match)) {
+                    Log.d(TAG, "match found in "
+                            + (SystemClock.elapsedRealtime() - startTime) + " ms");
+                    break;
+                }
+                if ((SystemClock.elapsedRealtime() - startTime) > timeoutMs) {
+                    fail("match was not found, Timeout: " + timeoutMs + " ms");
+                }
+            }
+        } catch (IOException e) {
+            fail("match was not found, IO exception: " + e);
+        }
     }
 
     protected static boolean waitUntil(String msg, long timeoutMs,
diff --git a/tests/carservice_unit_test/Android.bp b/tests/carservice_unit_test/Android.bp
index 57e14d9..cf9d238 100644
--- a/tests/carservice_unit_test/Android.bp
+++ b/tests/carservice_unit_test/Android.bp
@@ -69,6 +69,7 @@
     // mockito-target-inline dependency
     jni_libs: [
         "libdexmakerjvmtiagent",
+        "libscriptexecutorjniutils-test",
         "libstaticjvmtiagent",
     ],
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
index 1d1f9d0..ca3a301 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
@@ -102,21 +102,38 @@
     private static final String TAG = UserHalServiceTest.class.getSimpleName();
 
     /**
-     * Timeout passed to {@link UserHalService} methods
+     * Timeout passed to {@link UserHalService} methods. This is the timeout for which
+     * {@link UserHalService} wait for the property change event and return
+     * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} if HAL doesn't respond. This timeout is used
+     * where we expect HAL to return something and {@link UserHalService} methods are not expected
+     * to timeout. Tests are not supposed to wait for this much so this value can be high. If test
+     * requires HAL to timeout, then use {@link HAL_TIMEOUT_MS}.
      */
-    private static final int TIMEOUT_MS = 50;
+    private static final int HAL_TIMEOUT_MS = 5_000;
 
     /**
-     * Timeout for {@link GenericHalCallback#assertCalled()} for tests where the HAL is supposed to
-     * return something - it's a short time so it doesn't impact the test duration.
+     * Timeout passed to {@link UserHalService} methods only if test expects that call will be
+     * timeout and {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is expected response. A higher
+     * value for this is going to slow down tests. If this timeout is used, then it is expected that
+     * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is checked.
      */
-    private static final int CALLBACK_TIMEOUT_SUCCESS = TIMEOUT_MS + 50;
+    private static final int HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS = 250;
 
     /**
-     * Timeout for {@link GenericHalCallback#assertCalled()} for tests where the HAL is not supposed
-     * to return anything - it's a slightly longer to make sure the test doesn't fail prematurely.
+     * If tests expect {@link UserHalService} call to timeout, and if they require to sleep then
+     * sleep for this much time. This value should be higher than {@link HAL_TIMEOUT_MS}. A much
+     * higher value for this is going to slow down the test.
      */
-    private static final int CALLBACK_TIMEOUT_TIMEOUT = TIMEOUT_MS + 450;
+    private static final int WAITING_TIME_FOR_NEGATIVE_TESTS_MS = HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS
+            + 100;
+
+    /**
+     * Timeout for {@link GenericHalCallback#assertCalled()} for tests. In each case,
+     * {@link UserHalService} is supposed to return something - either a valid response or a
+     * timeout. This timeout is for the callback to wait for the response. A higher value of this
+     * timeout should not affect the test duration.
+     */
+    private static final int CALLBACK_TIMEOUT = 5_000;
 
     // Used when crafting a request property - the real value will be set by the mock.
     private static final int REQUEST_ID_PLACE_HOLDER = 1111;
@@ -254,7 +271,7 @@
         UserHalService myHalService = new UserHalService(mVehicleHal);
 
         assertThrows(IllegalStateException.class, () -> myHalService.getInitialUserInfo(COLD_BOOT,
-                TIMEOUT_MS, mUsersInfo, noOpCallback()));
+                HAL_TIMEOUT_MS, mUsersInfo, noOpCallback()));
     }
 
     @Test
@@ -267,14 +284,14 @@
 
     @Test
     public void testGetUserInfo_noUsersInfo() {
-        assertThrows(NullPointerException.class, () ->
-                mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, null, noOpCallback()));
+        assertThrows(NullPointerException.class, () -> mUserHalService.getInitialUserInfo(COLD_BOOT,
+                HAL_TIMEOUT_MS, null, noOpCallback()));
     }
 
     @Test
     public void testGetUserInfo_noCallback() {
         assertThrows(NullPointerException.class,
-                () -> mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS,
+                () -> mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS,
                         mUsersInfo, null));
     }
 
@@ -283,8 +300,8 @@
         replySetPropertyWithTimeoutException(INITIAL_USER_INFO);
 
         GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
                 callback);
 
         callback.assertCalled();
@@ -292,15 +309,15 @@
         assertThat(callback.response).isNull();
 
         // Make sure the pending request was removed
-        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
         callback.assertNotCalledAgain();
     }
 
     @Test
     public void testGetUserInfo_halDidNotReply() throws Exception {
         GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo,
                 callback);
 
         callback.assertCalled();
@@ -311,12 +328,12 @@
     @Test
     public void testGetUserInfo_secondCallFailWhilePending() throws Exception {
         GenericHalCallback<InitialUserInfoResponse> callback1 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
         GenericHalCallback<InitialUserInfoResponse> callback2 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo,
                 callback1);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
                 callback2);
 
         callback1.assertCalled();
@@ -337,8 +354,8 @@
                 /* rightRequestId= */ false);
 
         GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo,
                 callback);
 
         callback.assertCalled();
@@ -355,8 +372,8 @@
                 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
                 callback);
 
         callback.assertCalled();
@@ -378,8 +395,8 @@
                 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
                 callback);
 
         callback.assertCalled();
@@ -408,8 +425,8 @@
                 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
                 callback);
 
         callback.assertCalled();
@@ -441,8 +458,8 @@
                 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                CALLBACK_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
                 callback);
 
         callback.assertCalled();
@@ -475,7 +492,7 @@
 
         assertThrows(IllegalStateException.class,
                 () -> myHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
-                        TIMEOUT_MS, noOpCallback()));
+                        HAL_TIMEOUT_MS, noOpCallback()));
     }
 
     @Test
@@ -489,25 +506,27 @@
     @Test
     public void testSwitchUser_noUsersInfo() {
         assertThrows(IllegalArgumentException.class, () -> mUserHalService
-                .switchUser(createUserSwitchRequest(mUser10, null), TIMEOUT_MS, noOpCallback()));
+                .switchUser(createUserSwitchRequest(mUser10, null), HAL_TIMEOUT_MS,
+                        noOpCallback()));
     }
 
     @Test
     public void testSwitchUser_noCallback() {
         assertThrows(NullPointerException.class, () -> mUserHalService
-                .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS, null));
+                .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, null));
     }
 
     @Test
     public void testSwitchUser_nullRequest() {
         assertThrows(NullPointerException.class, () -> mUserHalService
-                .switchUser(null, TIMEOUT_MS, noOpCallback()));
+                .switchUser(null, HAL_TIMEOUT_MS, noOpCallback()));
     }
 
     @Test
     public void testSwitchUser_noTarget() {
         assertThrows(NullPointerException.class, () -> mUserHalService
-                .switchUser(createUserSwitchRequest(null, mUsersInfo), TIMEOUT_MS, noOpCallback()));
+                .switchUser(createUserSwitchRequest(null, mUsersInfo), HAL_TIMEOUT_MS,
+                        noOpCallback()));
     }
 
     @Test
@@ -515,8 +534,9 @@
         replySetPropertyWithTimeoutException(SWITCH_USER);
 
         GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+                HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
                 callback);
 
         callback.assertCalled();
@@ -524,15 +544,16 @@
         assertThat(callback.response).isNull();
 
         // Make sure the pending request was removed
-        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
         callback.assertNotCalledAgain();
     }
 
     @Test
     public void testSwitchUser_halDidNotReply() throws Exception {
         GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+                HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
                 callback);
 
         callback.assertCalled();
@@ -549,8 +570,9 @@
                 /* rightRequestId= */ false);
 
         GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+                HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
                 callback);
 
         callback.assertCalled();
@@ -568,8 +590,8 @@
                 SWITCH_USER, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
                 callback);
 
         callback.assertCalled();
@@ -593,8 +615,8 @@
                 SWITCH_USER, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
                 callback);
 
         callback.assertCalled();
@@ -622,8 +644,8 @@
                 SWITCH_USER, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
                 callback);
 
         callback.assertCalled();
@@ -643,12 +665,13 @@
     @Test
     public void testSwitchUser_secondCallFailWhilePending() throws Exception {
         GenericHalCallback<SwitchUserResponse> callback1 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
         GenericHalCallback<SwitchUserResponse> callback2 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+                HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
                 callback1);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
                 callback2);
 
         callback1.assertCalled();
@@ -670,8 +693,8 @@
                 SWITCH_USER, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                CALLBACK_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
                 callback);
 
         callback.assertCalled();
@@ -869,13 +892,14 @@
         UserHalService myHalService = new UserHalService(mVehicleHal);
 
         assertThrows(IllegalStateException.class,
-                () -> myHalService.createUser(new CreateUserRequest(), TIMEOUT_MS, noOpCallback()));
+                () -> myHalService.createUser(new CreateUserRequest(), HAL_TIMEOUT_MS,
+                        noOpCallback()));
     }
 
     @Test
     public void testCreateUser_noRequest() {
         assertThrows(NullPointerException.class, () -> mUserHalService
-                .createUser(null, TIMEOUT_MS, noOpCallback()));
+                .createUser(null, HAL_TIMEOUT_MS, noOpCallback()));
     }
 
     @Test
@@ -893,7 +917,7 @@
         request.usersInfo.existingUsers.add(request.newUserInfo);
 
         assertThrows(NullPointerException.class, () -> mUserHalService
-                .createUser(request, TIMEOUT_MS, null));
+                .createUser(request, HAL_TIMEOUT_MS, null));
     }
 
     /**
@@ -912,23 +936,25 @@
         replySetPropertyWithTimeoutException(CREATE_USER);
 
         GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+                CALLBACK_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+                callback);
 
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
         assertThat(callback.response).isNull();
 
         // Make sure the pending request was removed
-        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
         callback.assertNotCalledAgain();
     }
 
     @Test
     public void testCreateUser_halDidNotReply() throws Exception {
         GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+                CALLBACK_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+                callback);
 
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -944,8 +970,9 @@
                 /* rightRequestId= */ false);
 
         GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+                CALLBACK_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+                callback);
 
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -965,8 +992,8 @@
         request.newUserInfo = mUser10;
         request.usersInfo = mUsersInfo;
         GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.createUser(request, TIMEOUT_MS, callback);
+                CALLBACK_TIMEOUT);
+        mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback);
 
         callback.assertCalled();
 
@@ -994,8 +1021,8 @@
         request.newUserInfo = mUser10;
         request.usersInfo = mUsersInfo;
         GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.createUser(request, TIMEOUT_MS, callback);
+                CALLBACK_TIMEOUT);
+        mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback);
 
         callback.assertCalled();
 
@@ -1012,11 +1039,12 @@
     @Test
     public void testCreateUser_secondCallFailWhilePending() throws Exception {
         GenericHalCallback<CreateUserResponse> callback1 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
         GenericHalCallback<CreateUserResponse> callback2 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
-        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback1);
-        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback2);
+                CALLBACK_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+                callback1);
+        mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback2);
 
         callback1.assertCalled();
         assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -1037,8 +1065,8 @@
                 CREATE_USER, propResponse, /* rightRequestId= */ true);
 
         GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_SUCCESS);
-        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+                CALLBACK_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback);
 
         callback.assertCalled();
 
@@ -1170,8 +1198,9 @@
         // Cannot use mUserHalService because it's already set with supported properties
         UserHalService myHalService = new UserHalService(mVehicleHal);
 
-        assertThrows(IllegalStateException.class, () -> myHalService.setUserAssociation(TIMEOUT_MS,
-                new UserIdentificationSetRequest(), noOpCallback()));
+        assertThrows(IllegalStateException.class,
+                () -> myHalService.setUserAssociation(HAL_TIMEOUT_MS,
+                        new UserIdentificationSetRequest(), noOpCallback()));
     }
 
     @Test
@@ -1186,14 +1215,14 @@
     @Test
     public void testSetUserAssociation_nullRequest() {
         assertThrows(NullPointerException.class, () ->
-                mUserHalService.setUserAssociation(TIMEOUT_MS, null, noOpCallback()));
+                mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, null, noOpCallback()));
     }
 
     @Test
     public void testSetUserAssociation_nullCallback() {
         UserIdentificationSetRequest request = new UserIdentificationSetRequest();
         assertThrows(NullPointerException.class, () ->
-                mUserHalService.setUserAssociation(TIMEOUT_MS, request, null));
+                mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, null));
     }
 
     @Test
@@ -1207,24 +1236,24 @@
         request.associations.add(association1);
 
         assertThrows(IllegalArgumentException.class, () ->
-                mUserHalService.setUserAssociation(TIMEOUT_MS, request, noOpCallback()));
+                mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, noOpCallback()));
     }
 
     @Test
     public void testSetUserAssociation_halSetTimedOut() throws Exception {
         UserIdentificationSetRequest request = validUserIdentificationSetRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
         replySetPropertyWithTimeoutException(USER_IDENTIFICATION_ASSOCIATION);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback);
 
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
         assertThat(callback.response).isNull();
 
         // Make sure the pending request was removed
-        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
         callback.assertNotCalledAgain();
     }
 
@@ -1232,9 +1261,9 @@
     public void testSetUserAssociation_halDidNotReply() throws Exception {
         UserIdentificationSetRequest request = validUserIdentificationSetRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback);
 
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -1245,12 +1274,12 @@
     public void testSetUserAssociation_secondCallFailWhilePending() throws Exception {
         UserIdentificationSetRequest request = validUserIdentificationSetRequest();
         GenericHalCallback<UserIdentificationResponse> callback1 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
         GenericHalCallback<UserIdentificationResponse> callback2 = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback1);
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback2);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback1);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback2);
 
         callback1.assertCalled();
         assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -1270,9 +1299,9 @@
                 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
         UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
 
         // Assert request
         verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1295,9 +1324,9 @@
                 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
         UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
 
         // Assert request
         verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1322,9 +1351,9 @@
                 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
         UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
 
         // Assert request
         verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1347,9 +1376,9 @@
                 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
         UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
 
         // Assert request
         verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1372,9 +1401,9 @@
                 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
         UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
-                CALLBACK_TIMEOUT_TIMEOUT);
+                CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
 
         // Assert request
         verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1521,7 +1550,7 @@
      * Run empty runnable to make sure that all posted handlers are done.
      */
     private void waitForHandler() {
-        mHandler.runWithScissors(() -> { }, /* Default timeout */ CALLBACK_TIMEOUT_TIMEOUT);
+        mHandler.runWithScissors(() -> { }, /* Default timeout */ CALLBACK_TIMEOUT);
     }
 
     private void mockNextRequestId(int requestId) {
@@ -1617,14 +1646,14 @@
 
         @Override
         public void onResponse(int status, R response) {
-            Log.d(TAG, "onResponse(): status=" + status + ", response=" +  response);
-            this.status = status;
-            this.response = response;
+            Log.d(TAG, "onResponse(): status=" + status + ", response=" + response);
             if (mLatch.getCount() == 0) {
                 Log.e(TAG, "Already responded");
                 mExtraCalls.add(new Pair<>(status, response));
                 return;
             }
+            this.status = status;
+            this.response = response;
             mLatch.countDown();
         }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
index 14824b2..5bc7974 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
@@ -18,8 +18,6 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
@@ -92,7 +90,6 @@
         writeStringToFile(mFileHwStateMonitoring.getFile(), VALUE_SILENT_MODE);
 
         assertWithMessage("Silent mode in forced mode").that(handler.isSilentMode()).isTrue();
-        verify(mCarPowerManagementService, never()).notifySilentModeChange(anyBoolean());
     }
 
     @Test
@@ -107,7 +104,6 @@
         writeStringToFile(mFileHwStateMonitoring.getFile(), VALUE_SILENT_MODE);
 
         assertWithMessage("Silent mode in forced mode").that(handler.isSilentMode()).isFalse();
-        verify(mCarPowerManagementService, never()).notifySilentModeChange(anyBoolean());
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
index d8bf9a2..0e9a168 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
@@ -40,8 +40,8 @@
 
     private final ManifestKey mManifestKeyV1 = new ManifestKey("Name", 1);
     private final ManifestKey mManifestKeyV2 = new ManifestKey("Name", 2);
-    private final TelemetryProto.Manifest mManifest =
-            TelemetryProto.Manifest.newBuilder().setScript("no-op").build();
+    private final TelemetryProto.MetricsConfig mMetricsConfig =
+            TelemetryProto.MetricsConfig.newBuilder().setScript("no-op").build();
 
     private CarTelemetryService mService;
 
@@ -52,16 +52,16 @@
 
     @Test
     public void testAddManifest_newManifest_shouldSucceed() {
-        int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+        int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
 
         assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
     }
 
     @Test
     public void testAddManifest_duplicateManifest_shouldFail() {
-        mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+        mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
 
-        int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+        int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
 
         assertThat(result).isEqualTo(CarTelemetryManager.ERROR_SAME_MANIFEST_EXISTS);
     }
@@ -75,25 +75,25 @@
 
     @Test
     public void testAddManifest_olderManifest_shouldFail() {
-        mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+        mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
 
-        int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+        int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
 
         assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NEWER_MANIFEST_EXISTS);
     }
 
     @Test
     public void testAddManifest_newerManifest_shouldReplace() {
-        mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+        mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
 
-        int result = mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+        int result = mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
 
         assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
     }
 
     @Test
     public void testRemoveManifest_manifestExists_shouldSucceed() {
-        mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+        mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
 
         boolean result = mService.removeManifest(mManifestKeyV1);
 
@@ -109,15 +109,15 @@
 
     @Test
     public void testRemoveAllManifests_shouldSucceed() {
-        mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
-        mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+        mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
+        mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
 
         mService.removeAllManifests();
 
         // verify that the manifests are cleared by adding them again, should succeed
-        int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+        int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
         assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
-        result = mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+        result = mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
         assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/JniUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/JniUtilsTest.java
new file mode 100644
index 0000000..67a5ac8
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/JniUtilsTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.android.car.telemetry;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class JniUtilsTest {
+
+    private static final String TAG = JniUtilsTest.class.getSimpleName();
+
+    private static final String BOOLEAN_KEY = "boolean_key";
+    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 boolean BOOLEAN_VALUE = true;
+    private static final double NUMBER_VALUE = 0.1;
+    private static final int INT_VALUE = 10;
+    private static final String STRING_VALUE = "test";
+
+    // Pointer to Lua Engine instantiated in native space.
+    private long mLuaEnginePtr = 0;
+
+    static {
+        System.loadLibrary("scriptexecutorjniutils-test");
+    }
+
+    @Before
+    public void setUp() {
+        mLuaEnginePtr = nativeCreateLuaEngine();
+    }
+
+    @After
+    public void tearDown() {
+        nativeDestroyLuaEngine(mLuaEnginePtr);
+    }
+
+    // Simply invokes PushBundleToLuaTable native method under test.
+    private native void nativePushBundleToLuaTableCaller(long luaEnginePtr, Bundle bundle);
+
+    // Creates an instance of LuaEngine on the heap and returns the pointer.
+    private native long nativeCreateLuaEngine();
+
+    // Destroys instance of LuaEngine on the native side at provided memory address.
+    private native void nativeDestroyLuaEngine(long luaEnginePtr);
+
+    // Returns size of a Lua object located at the specified position on the stack.
+    private native int nativeGetObjectSize(long luaEnginePtr, int index);
+
+    /*
+     * Family of methods to check if the table on top of the stack has
+     * the given value under provided key.
+     */
+    private native boolean nativeHasBooleanValue(long luaEnginePtr, String key, boolean value);
+    private native boolean nativeHasStringValue(long luaEnginePtr, String key, String value);
+    private native boolean nativeHasIntValue(long luaEnginePtr, String key, int value);
+    private native boolean nativeHasDoubleValue(long luaEnginePtr, String key, double value);
+
+    @Test
+    public void pushBundleToLuaTable_nullBundleMakesEmptyLuaTable() {
+        Log.d(TAG, "Using Lua Engine with address " + mLuaEnginePtr);
+        nativePushBundleToLuaTableCaller(mLuaEnginePtr, null);
+        // Get the size of the object on top of the stack,
+        // which is where our table is supposed to be.
+        assertThat(nativeGetObjectSize(mLuaEnginePtr, 1)).isEqualTo(0);
+    }
+
+    @Test
+    public void pushBundleToLuaTable_valuesOfDifferentTypes() {
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(BOOLEAN_KEY, BOOLEAN_VALUE);
+        bundle.putInt(INT_KEY, INT_VALUE);
+        bundle.putDouble(NUMBER_KEY, NUMBER_VALUE);
+        bundle.putString(STRING_KEY, STRING_VALUE);
+
+        // Invokes the corresponding helper method to convert the bundle
+        // to Lua table on Lua stack.
+        nativePushBundleToLuaTableCaller(mLuaEnginePtr, bundle);
+
+        // Check contents of Lua table.
+        assertThat(nativeHasBooleanValue(mLuaEnginePtr, BOOLEAN_KEY, BOOLEAN_VALUE)).isTrue();
+        assertThat(nativeHasIntValue(mLuaEnginePtr, INT_KEY, INT_VALUE)).isTrue();
+        assertThat(nativeHasDoubleValue(mLuaEnginePtr, NUMBER_KEY, NUMBER_VALUE)).isTrue();
+        assertThat(nativeHasStringValue(mLuaEnginePtr, STRING_KEY, STRING_VALUE)).isTrue();
+    }
+
+
+    @Test
+    public void pushBundleToLuaTable_wrongKey() {
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(BOOLEAN_KEY, BOOLEAN_VALUE);
+
+        // Invokes the corresponding helper method to convert the bundle
+        // to Lua table on Lua stack.
+        nativePushBundleToLuaTableCaller(mLuaEnginePtr, bundle);
+
+        // Check contents of Lua table.
+        assertThat(nativeHasBooleanValue(mLuaEnginePtr, "wrong key", BOOLEAN_VALUE)).isFalse();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index ac1b1e8..364a4ca 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -568,7 +568,7 @@
         mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_SUCCESS);
 
         AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
-        mCarUserService.stopUser(userId, userStopResult);
+        stopUser(userId, userStopResult);
 
         assertThat(getResult(userStopResult).getStatus())
                 .isEqualTo(UserStopResult.STATUS_SUCCESSFUL);
@@ -582,8 +582,7 @@
         mockManageUsersPermission(android.Manifest.permission.CREATE_USERS, false);
 
         AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
-        assertThrows(SecurityException.class,
-                () -> mCarUserService.stopUser(userId, userStopResult));
+        assertThrows(SecurityException.class, () -> stopUser(userId, userStopResult));
     }
 
     @Test
@@ -593,7 +592,7 @@
         mockStopUserWithDelayedLockingThrowsRemoteException(userId);
 
         AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
-        mCarUserService.stopUser(userId, userStopResult);
+        stopUser(userId, userStopResult);
 
         assertThat(getResult(userStopResult).getStatus())
                 .isEqualTo(UserStopResult.STATUS_ANDROID_FAILURE);
@@ -607,7 +606,7 @@
         mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_UNKNOWN_USER);
 
         AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
-        mCarUserService.stopUser(userId, userStopResult);
+        stopUser(userId, userStopResult);
 
         assertThat(getResult(userStopResult).getStatus())
                 .isEqualTo(UserStopResult.STATUS_USER_DOES_NOT_EXIST);
@@ -620,7 +619,7 @@
                 UserHandle.USER_SYSTEM, ActivityManager.USER_OP_ERROR_IS_SYSTEM);
 
         AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
-        mCarUserService.stopUser(UserHandle.USER_SYSTEM, userStopResult);
+        stopUser(UserHandle.USER_SYSTEM, userStopResult);
 
         assertThat(getResult(userStopResult).getStatus())
                 .isEqualTo(UserStopResult.STATUS_FAILURE_SYSTEM_USER);
@@ -634,7 +633,7 @@
         mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_IS_CURRENT);
 
         AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
-        mCarUserService.stopUser(userId, userStopResult);
+        stopUser(userId, userStopResult);
 
         assertThat(getResult(userStopResult).getStatus())
                 .isEqualTo(UserStopResult.STATUS_FAILURE_CURRENT_USER);
@@ -1864,7 +1863,7 @@
         mockAmStartUserInBackground(userId, true);
 
         AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
-        mCarUserService.startUserInBackground(userId, userStartResult);
+        startUserInBackground(userId, userStartResult);
 
         assertThat(getResult(userStartResult).getStatus())
                 .isEqualTo(UserStartResult.STATUS_SUCCESSFUL);
@@ -1879,7 +1878,7 @@
 
         AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
         assertThrows(SecurityException.class,
-                () -> mCarUserService.startUserInBackground(userId, userStartResult));
+                () -> startUserInBackground(userId, userStartResult));
     }
 
     @Test
@@ -1891,7 +1890,7 @@
         mockAmStartUserInBackground(userId, false);
 
         AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
-        mCarUserService.startUserInBackground(userId, userStartResult);
+        startUserInBackground(userId, userStartResult);
 
         assertThat(getResult(userStartResult).getStatus())
                 .isEqualTo(UserStartResult.STATUS_ANDROID_FAILURE);
@@ -1907,7 +1906,7 @@
         mockAmStartUserInBackground(userId, true);
 
         AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
-        mCarUserService.startUserInBackground(userId, userStartResult);
+        startUserInBackground(userId, userStartResult);
 
         assertThat(getResult(userStartResult).getStatus())
                 .isEqualTo(UserStartResult.STATUS_SUCCESSFUL_USER_IS_CURRENT_USER);
@@ -1922,7 +1921,7 @@
         mockAmStartUserInBackground(userId, true);
 
         AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
-        mCarUserService.startUserInBackground(userId, userStartResult);
+        startUserInBackground(userId, userStartResult);
 
         assertThat(getResult(userStartResult).getStatus())
                 .isEqualTo(UserStartResult.STATUS_USER_DOES_NOT_EXIST);
@@ -2357,6 +2356,18 @@
         waitForHandlerThreadToFinish();
     }
 
+    private void startUserInBackground(@UserIdInt int userId,
+            @NonNull AndroidFuture<UserStartResult> userStartResultFuture) {
+        mCarUserService.startUserInBackground(userId, userStartResultFuture);
+        waitForHandlerThreadToFinish();
+    }
+
+    private void stopUser(@UserIdInt int userId,
+            @NonNull AndroidFuture<UserStopResult> userStopResultFuture) {
+        mCarUserService.stopUser(userId, userStopResultFuture);
+        waitForHandlerThreadToFinish();
+    }
+
     @NonNull
     private UserSwitchResult getUserSwitchResult() throws Exception {
         return getResult(mUserSwitchFuture);
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 ad47fa1..0014d57 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
@@ -87,6 +87,7 @@
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
 import com.android.internal.util.function.TriConsumer;
 
 import com.google.common.truth.Correspondence;
@@ -97,7 +98,6 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
@@ -128,6 +128,9 @@
     private CarWatchdogService mCarWatchdogService;
     private ICarWatchdogServiceForSystem mWatchdogServiceForSystemImpl;
     private IBinder.DeathRecipient mCarWatchdogDaemonBinderDeathRecipient;
+    private final SparseArray<String> mPackageNamesByUids = new SparseArray<>();
+    private final SparseArray<String[]> mSharedPackagesByUids = new SparseArray<>();
+    private final ArrayMap<String, ApplicationInfo> mApplicationInfosByPackages = new ArrayMap<>();
 
     @Override
     protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
@@ -151,6 +154,7 @@
         mCarWatchdogService.init();
         mWatchdogServiceForSystemImpl = registerCarWatchdogService();
         captureDaemonBinderDeathRecipient();
+        mockPackageManager();
     }
 
     @Test
@@ -200,9 +204,7 @@
 
     @Test
     public void testGetResourceOveruseStats() throws Exception {
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
-        injectUidToPackageNameMapping(packageNamesByUid);
+        mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
 
         List<PackageIoOveruseStats> packageIoOveruseStats = Collections.singletonList(
                 constructPackageIoOveruseStats(
@@ -214,8 +216,9 @@
         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
 
         ResourceOveruseStats expectedStats =
-                constructResourceOveruseStats(packageNamesByUid.keyAt(0),
-                        packageNamesByUid.valueAt(0), packageIoOveruseStats.get(0).ioOveruseStats);
+                constructResourceOveruseStats(mPackageNamesByUids.keyAt(0),
+                        mPackageNamesByUids.valueAt(0),
+                        packageIoOveruseStats.get(0).ioOveruseStats);
 
         ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
@@ -239,18 +242,18 @@
 
     @Test
     public void testGetAllResourceOveruseStatsWithNoMinimum() throws Exception {
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(1103456, "third_party_package");
-        packageNamesByUid.put(1201278, "vendor_package.critical");
-        injectUidToPackageNameMapping(packageNamesByUid);
+        mPackageNamesByUids.put(1103456, "third_party_package");
+        mPackageNamesByUids.put(1201278, "vendor_package.critical");
 
         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
-                constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+                constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(0),
+                        /* shouldNotify= */false,
                         constructInternalIoOveruseStats(/* killableOnOveruse= */true,
                                 /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
                                 /* writtenBytes= */constructPerStateBytes(100, 200, 300),
                                 /* totalOveruses= */2)),
-                constructPackageIoOveruseStats(packageNamesByUid.keyAt(1), /* shouldNotify= */false,
+                constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(1),
+                        /* shouldNotify= */false,
                         constructInternalIoOveruseStats(/* killableOnOveruse= */false,
                                 /* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
                                 /* writtenBytes= */constructPerStateBytes(5000, 6000, 9000),
@@ -258,10 +261,12 @@
         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
 
         List<ResourceOveruseStats> expectedStats = Arrays.asList(
-                constructResourceOveruseStats(packageNamesByUid.keyAt(0),
-                        packageNamesByUid.valueAt(0), packageIoOveruseStats.get(0).ioOveruseStats),
-                constructResourceOveruseStats(packageNamesByUid.keyAt(1),
-                        packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats));
+                constructResourceOveruseStats(mPackageNamesByUids.keyAt(0),
+                        mPackageNamesByUids.valueAt(0),
+                        packageIoOveruseStats.get(0).ioOveruseStats),
+                constructResourceOveruseStats(mPackageNamesByUids.keyAt(1),
+                        mPackageNamesByUids.valueAt(1),
+                        packageIoOveruseStats.get(1).ioOveruseStats));
 
         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */0,
@@ -297,18 +302,18 @@
 
     @Test
     public void testGetAllResourceOveruseStatsWithMinimum() throws Exception {
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(1103456, "third_party_package");
-        packageNamesByUid.put(1201278, "vendor_package.critical");
-        injectUidToPackageNameMapping(packageNamesByUid);
+        mPackageNamesByUids.put(1103456, "third_party_package");
+        mPackageNamesByUids.put(1201278, "vendor_package.critical");
 
         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
-                constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+                constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(0),
+                        /* shouldNotify= */false,
                         constructInternalIoOveruseStats(/* killableOnOveruse= */true,
                                 /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
                                 /* writtenBytes= */constructPerStateBytes(100, 200, 300),
                                 /* totalOveruses= */2)),
-                constructPackageIoOveruseStats(packageNamesByUid.keyAt(1), /* shouldNotify= */false,
+                constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(1),
+                        /* shouldNotify= */false,
                         constructInternalIoOveruseStats(/* killableOnOveruse= */false,
                                 /* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
                                 /* writtenBytes= */constructPerStateBytes(7000000, 6000, 9000),
@@ -316,8 +321,9 @@
         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
 
         List<ResourceOveruseStats> expectedStats = Collections.singletonList(
-                constructResourceOveruseStats(packageNamesByUid.keyAt(1),
-                        packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats));
+                constructResourceOveruseStats(mPackageNamesByUids.keyAt(1),
+                        mPackageNamesByUids.valueAt(1),
+                        packageIoOveruseStats.get(1).ioOveruseStats));
 
         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
@@ -330,18 +336,18 @@
 
     @Test
     public void testGetResourceOveruseStatsForUserPackage() throws Exception {
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(1103456, "third_party_package");
-        packageNamesByUid.put(1201278, "vendor_package.critical");
-        injectUidToPackageNameMapping(packageNamesByUid);
+        mPackageNamesByUids.put(1103456, "third_party_package");
+        mPackageNamesByUids.put(1201278, "vendor_package.critical");
 
         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
-                constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+                constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(0),
+                        /* shouldNotify= */false,
                         constructInternalIoOveruseStats(/* killableOnOveruse= */true,
                                 /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
                                 /* writtenBytes= */constructPerStateBytes(100, 200, 300),
                                 /* totalOveruses= */2)),
-                constructPackageIoOveruseStats(packageNamesByUid.keyAt(1), /* shouldNotify= */false,
+                constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(1),
+                        /* shouldNotify= */false,
                         constructInternalIoOveruseStats(/* killableOnOveruse= */false,
                                 /* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
                                 /* writtenBytes= */constructPerStateBytes(500, 600, 900),
@@ -349,8 +355,9 @@
         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
 
         ResourceOveruseStats expectedStats =
-                constructResourceOveruseStats(packageNamesByUid.keyAt(1),
-                        packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats);
+                constructResourceOveruseStats(mPackageNamesByUids.keyAt(1),
+                        mPackageNamesByUids.valueAt(1),
+                        packageIoOveruseStats.get(1).ioOveruseStats);
 
         ResourceOveruseStats actualStats =
                 mCarWatchdogService.getResourceOveruseStatsForUserPackage(
@@ -402,40 +409,111 @@
 
     @Test
     public void testResourceOveruseListener() throws Exception {
-        int callingUid = Binder.getCallingUid();
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(callingUid, "critical.system.package");
-        injectUidToPackageNameMapping(packageNamesByUid);
+        mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
 
         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
+        IBinder mockBinder = mockListener.asBinder();
+
         mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
                 mockListener);
 
-        IBinder mockBinder = mockListener.asBinder();
         verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
 
-        List<PackageIoOveruseStats> packageIoOveruseStats = Collections.singletonList(
-                constructPackageIoOveruseStats(callingUid, /* shouldNotify= */true,
-                        constructInternalIoOveruseStats(/* killableOnOveruse= */true,
-                                /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
-                                /* writtenBytes= */constructPerStateBytes(100, 200, 300),
-                                /* totalOveruses= */2)));
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(),
+                /* shouldNotifyPackages= */new ArraySet<>(
+                        Collections.singleton(mMockContext.getPackageName())));
 
-        mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
-
-        verify(mockListener, times(1)).onOveruse(any());
+        verify(mockListener).onOveruse(any());
 
         mCarWatchdogService.removeResourceOveruseListener(mockListener);
 
         verify(mockListener, atLeastOnce()).asBinder();
         verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
 
-        mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(),
+                /* shouldNotifyPackages= */new ArraySet<>(
+                        Collections.singletonList(mMockContext.getPackageName())));
 
         verifyNoMoreInteractions(mockListener);
     }
 
     @Test
+    public void testDuplicateAddResourceOveruseListener() throws Exception {
+        mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
+
+        IResourceOveruseListener mockListener = createMockResourceOveruseListener();
+        IBinder mockBinder = mockListener.asBinder();
+
+        mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+                mockListener);
+
+        assertThrows(IllegalStateException.class,
+                () -> mCarWatchdogService.addResourceOveruseListener(
+                        CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockListener));
+
+        verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+        mCarWatchdogService.removeResourceOveruseListener(mockListener);
+
+        verify(mockListener, atLeastOnce()).asBinder();
+        verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+        verifyNoMoreInteractions(mockListener);
+    }
+
+    @Test
+    public void testAddMultipleResourceOveruseListeners() throws Exception {
+        mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
+
+        IResourceOveruseListener firstMockListener = createMockResourceOveruseListener();
+        IBinder firstMockBinder = firstMockListener.asBinder();
+        IResourceOveruseListener secondMockListener = createMockResourceOveruseListener();
+        IBinder secondMockBinder = secondMockListener.asBinder();
+
+        mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+                firstMockListener);
+        mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+                secondMockListener);
+
+        verify(firstMockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+        verify(secondMockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(),
+                /* shouldNotifyPackages= */new ArraySet<>(
+                        Collections.singleton(mMockContext.getPackageName())));
+
+        verify(firstMockListener).onOveruse(any());
+
+        mCarWatchdogService.removeResourceOveruseListener(firstMockListener);
+
+        verify(firstMockListener, atLeastOnce()).asBinder();
+        verify(firstMockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(),
+                /* shouldNotifyPackages= */new ArraySet<>(
+                        Collections.singletonList(mMockContext.getPackageName())));
+
+        verify(secondMockListener, times(2)).onOveruse(any());
+
+        mCarWatchdogService.removeResourceOveruseListener(secondMockListener);
+
+        verify(secondMockListener, atLeastOnce()).asBinder();
+        verify(secondMockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(),
+                /* shouldNotifyPackages= */new ArraySet<>(
+                        Collections.singletonList(mMockContext.getPackageName())));
+
+        verifyNoMoreInteractions(firstMockListener);
+        verifyNoMoreInteractions(secondMockListener);
+    }
+
+    @Test
     public void testAddResourceOveruseListenerForSystemThrowsWithInvalidFlag() throws Exception {
         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
         assertThrows(IllegalArgumentException.class, () -> {
@@ -446,9 +524,7 @@
     @Test
     public void testResourceOveruseListenerForSystem() throws Exception {
         int callingUid = Binder.getCallingUid();
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(callingUid, "critical.system.package");
-        injectUidToPackageNameMapping(packageNamesByUid);
+        mPackageNamesByUids.put(callingUid, "critical.system.package");
 
         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
         mCarWatchdogService.addResourceOveruseListenerForSystem(
@@ -466,7 +542,7 @@
 
         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
 
-        verify(mockListener, times(1)).onOveruse(any());
+        verify(mockListener).onOveruse(any());
 
         mCarWatchdogService.removeResourceOveruseListenerForSystem(mockListener);
 
@@ -483,11 +559,12 @@
         mockUmGetAliveUsers(mMockUserManager, 11, 12);
         injectPackageInfos(Arrays.asList("third_party_package", "vendor_package.critical"));
 
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(1103456, "third_party_package");
-        packageNamesByUid.put(1101278, "vendor_package.critical");
-        injectIoOveruseStatsForPackages(packageNamesByUid,
-                new ArraySet<>(Collections.singletonList("third_party_package")));
+        mPackageNamesByUids.put(1103456, "third_party_package");
+        mPackageNamesByUids.put(1101278, "vendor_package.critical");
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(
+                        Collections.singletonList("third_party_package")),
+                /* shouldNotifyPackages= */new ArraySet<>());
 
         UserHandle userHandle = new UserHandle(11);
 
@@ -555,11 +632,12 @@
         mockUmGetAliveUsers(mMockUserManager, 11, 12);
         injectPackageInfos(Arrays.asList("third_party_package", "vendor_package.critical"));
 
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(1103456, "third_party_package");
-        packageNamesByUid.put(1101278, "vendor_package.critical");
-        injectIoOveruseStatsForPackages(packageNamesByUid,
-                new ArraySet<>(Collections.singletonList("third_party_package")));
+        mPackageNamesByUids.put(1103456, "third_party_package");
+        mPackageNamesByUids.put(1101278, "vendor_package.critical");
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(
+                        Collections.singletonList("third_party_package")),
+                /* shouldNotifyPackages= */new ArraySet<>());
 
         mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
                 /* isKillable= */ true);
@@ -893,12 +971,10 @@
         int nonCriticalVndrPkgUid = getUid(2564);
         int thirdPartyPkgUid = getUid(2044);
 
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(criticalSysPkgUid, "critical.system.package");
-        packageNamesByUid.put(nonCriticalSysPkgUid, "non_critical.system.package");
-        packageNamesByUid.put(nonCriticalVndrPkgUid, "non_critical.vendor.package");
-        packageNamesByUid.put(thirdPartyPkgUid, "third_party.package");
-        injectUidToPackageNameMapping(packageNamesByUid);
+        mPackageNamesByUids.put(criticalSysPkgUid, "critical.system.package");
+        mPackageNamesByUids.put(nonCriticalSysPkgUid, "non_critical.system.package");
+        mPackageNamesByUids.put(nonCriticalVndrPkgUid, "non_critical.vendor.package");
+        mPackageNamesByUids.put(thirdPartyPkgUid, "third_party.package");
 
         IResourceOveruseListener mockSystemListener = createMockResourceOveruseListener();
         mCarWatchdogService.addResourceOveruseListenerForSystem(
@@ -943,31 +1019,31 @@
         List<ResourceOveruseStats> expectedStats = new ArrayList<>();
 
         expectedStats.add(constructResourceOveruseStats(criticalSysPkgUid,
-                packageNamesByUid.get(criticalSysPkgUid),
+                mPackageNamesByUids.get(criticalSysPkgUid),
                 packageIoOveruseStats.get(0).ioOveruseStats));
 
         verifyOnOveruseCalled(expectedStats, mockListener);
 
         expectedStats.add(constructResourceOveruseStats(nonCriticalSysPkgUid,
-                packageNamesByUid.get(nonCriticalSysPkgUid),
+                mPackageNamesByUids.get(nonCriticalSysPkgUid),
                 packageIoOveruseStats.get(1).ioOveruseStats));
 
         expectedStats.add(constructResourceOveruseStats(thirdPartyPkgUid,
-                packageNamesByUid.get(thirdPartyPkgUid),
+                mPackageNamesByUids.get(thirdPartyPkgUid),
                 packageIoOveruseStats.get(3).ioOveruseStats));
 
         verifyOnOveruseCalled(expectedStats, mockSystemListener);
 
-        verify(packageManagerService, times(1)).getApplicationEnabledSetting(
-                packageNamesByUid.get(thirdPartyPkgUid), UserHandle.getUserId(thirdPartyPkgUid));
-        verify(packageManagerService, times(1)).setApplicationEnabledSetting(
-                eq(packageNamesByUid.get(thirdPartyPkgUid)), anyInt(), anyInt(),
+        verify(packageManagerService).getApplicationEnabledSetting(
+                mPackageNamesByUids.get(thirdPartyPkgUid), UserHandle.getUserId(thirdPartyPkgUid));
+        verify(packageManagerService).setApplicationEnabledSetting(
+                eq(mPackageNamesByUids.get(thirdPartyPkgUid)), anyInt(), anyInt(),
                 eq(UserHandle.getUserId(thirdPartyPkgUid)), anyString());
 
         List<PackageResourceOveruseAction> expectedActions = Arrays.asList(
-                constructPackageResourceOveruseAction(packageNamesByUid.get(criticalSysPkgUid),
+                constructPackageResourceOveruseAction(mPackageNamesByUids.get(criticalSysPkgUid),
                         criticalSysPkgUid, new int[]{ResourceType.IO}, NOT_KILLED),
-                constructPackageResourceOveruseAction(packageNamesByUid.get(thirdPartyPkgUid),
+                constructPackageResourceOveruseAction(mPackageNamesByUids.get(thirdPartyPkgUid),
                         thirdPartyPkgUid, new int[]{ResourceType.IO}, KILLED));
         verifyActionsTakenOnResourceOveruse(expectedActions);
     }
@@ -987,25 +1063,11 @@
 
     @Test
     public void testResetResourceOveruseStats() throws Exception {
-        SparseArray<String> packageNamesByUid = new SparseArray<>();
-        packageNamesByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
-        packageNamesByUid.put(1101278, "vendor_package.critical");
-        injectUidToPackageNameMapping(packageNamesByUid);
-
-        List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
-                constructPackageIoOveruseStats(
-                        Binder.getCallingUid(), /* shouldNotify= */false,
-                        constructInternalIoOveruseStats(/* killableOnOveruse= */false,
-                                /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
-                                /* writtenBytes= */constructPerStateBytes(100, 200, 300),
-                                /* totalOveruses= */2)),
-                constructPackageIoOveruseStats(
-                        1101278, /* shouldNotify= */false,
-                        constructInternalIoOveruseStats(/* killableOnOveruse= */false,
-                                /* remainingWriteBytes= */constructPerStateBytes(120, 220, 230),
-                                /* writtenBytes= */constructPerStateBytes(3100, 5200, 6300),
-                                /* totalOveruses= */3)));
-        mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+        mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
+        mPackageNamesByUids.put(1101278, "vendor_package.critical");
+        injectIoOveruseStatsForPackages(mPackageNamesByUids,
+                /* killablePackages= */new ArraySet<>(),
+                /* shouldNotifyPackages= */new ArraySet<>());
 
         mWatchdogServiceForSystemImpl.resetResourceOveruseStats(
                 Collections.singletonList(mMockContext.getPackageName()));
@@ -1049,25 +1111,29 @@
                         UidType.APPLICATION, ComponentType.VENDOR,
                         ApplicationCategoryType.OTHERS));
 
-        ArrayMap<String, ApplicationInfo> applicationInfos = new ArrayMap<>(9);
-        applicationInfos.put("system.package.A",
-                constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM, 0));
-        applicationInfos.put("system.package.B",
-                constructApplicationInfo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0));
-        applicationInfos.put("system.package.F",
-                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_PRODUCT));
-        applicationInfos.put("vendor.package.D",
-                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_OEM));
-        applicationInfos.put("vendor.package.E",
-                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_VENDOR));
-        applicationInfos.put("vendor.package.J",
-                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_ODM));
-        applicationInfos.put("third_party.package.C", constructApplicationInfo(0, 0));
-        applicationInfos.put("third_party.package.G", constructApplicationInfo(0, 0));
-        applicationInfos.put("third_party.package.H", constructApplicationInfo(0, 0));
-        applicationInfos.put("third_party.package.I", constructApplicationInfo(0, 0));
+        for (PackageInfo packageInfo : expectedPackageInfos) {
+            mPackageNamesByUids.put(packageInfo.packageIdentifier.uid,
+                    packageInfo.packageIdentifier.name);
+            mSharedPackagesByUids.put(packageInfo.packageIdentifier.uid,
+                    packageInfo.sharedUidPackages.toArray(new String[0]));
+        }
 
-        mockPackageManager(uids, expectedPackageInfos, applicationInfos);
+        mApplicationInfosByPackages.put("system.package.A",
+                constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM, 0));
+        mApplicationInfosByPackages.put("system.package.B",
+                constructApplicationInfo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0));
+        mApplicationInfosByPackages.put("system.package.F",
+                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_PRODUCT));
+        mApplicationInfosByPackages.put("vendor.package.D",
+                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_OEM));
+        mApplicationInfosByPackages.put("vendor.package.E",
+                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_VENDOR));
+        mApplicationInfosByPackages.put("vendor.package.J",
+                constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_ODM));
+        mApplicationInfosByPackages.put("third_party.package.C", constructApplicationInfo(0, 0));
+        mApplicationInfosByPackages.put("third_party.package.G", constructApplicationInfo(0, 0));
+        mApplicationInfosByPackages.put("third_party.package.H", constructApplicationInfo(0, 0));
+        mApplicationInfosByPackages.put("third_party.package.I", constructApplicationInfo(0, 0));
 
         List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
                 uids, new ArrayList<>());
@@ -1092,21 +1158,25 @@
                         new ArrayList<>(), UidType.APPLICATION, ComponentType.THIRD_PARTY,
                         ApplicationCategoryType.OTHERS));
 
-        ArrayMap<String, ApplicationInfo> applicationInfos = new ArrayMap<>(5);
-        applicationInfos.put("vendor.package.D", constructApplicationInfo(0,
+        for (PackageInfo packageInfo : expectedPackageInfos) {
+            mPackageNamesByUids.put(packageInfo.packageIdentifier.uid,
+                    packageInfo.packageIdentifier.name);
+            mSharedPackagesByUids.put(packageInfo.packageIdentifier.uid,
+                    packageInfo.sharedUidPackages.toArray(new String[0]));
+        }
+
+        mApplicationInfosByPackages.put("vendor.package.D", constructApplicationInfo(0,
                 ApplicationInfo.PRIVATE_FLAG_PRODUCT));
-        applicationInfos.put("vendor.pkg.E", constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM,
-                0));
+        mApplicationInfosByPackages.put("vendor.pkg.E",
+                constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM, 0));
         /*
          * A 3p package pretending to be a vendor package because 3p packages won't have the
          * required flags.
          */
-        applicationInfos.put("vendor.package.imposter", constructApplicationInfo(0, 0));
-        applicationInfos.put("third_party.package.F", constructApplicationInfo(0, 0));
-        applicationInfos.put("third_party.package.G", constructApplicationInfo(0, 0));
-        applicationInfos.put("third_party.package.H", constructApplicationInfo(0, 0));
-
-        mockPackageManager(uids, expectedPackageInfos, applicationInfos);
+        mApplicationInfosByPackages.put("vendor.package.imposter", constructApplicationInfo(0, 0));
+        mApplicationInfosByPackages.put("third_party.package.F", constructApplicationInfo(0, 0));
+        mApplicationInfosByPackages.put("third_party.package.G", constructApplicationInfo(0, 0));
+        mApplicationInfosByPackages.put("third_party.package.H", constructApplicationInfo(0, 0));
 
         List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
                 uids, Arrays.asList("vendor.package.", "vendor.pkg."));
@@ -1132,17 +1202,18 @@
                         UidType.APPLICATION, ComponentType.UNKNOWN,
                         ApplicationCategoryType.OTHERS));
 
-        ArrayMap<String, ApplicationInfo> applicationInfos = new ArrayMap<>(3);
-        applicationInfos.put(
-                "vendor.package.D", constructApplicationInfo(0,
-                        ApplicationInfo.PRIVATE_FLAG_VENDOR));
-        applicationInfos.put(
-                "vendor.package.E", constructApplicationInfo(0,
-                        ApplicationInfo.PRIVATE_FLAG_VENDOR));
-        applicationInfos.put(
-                "third_party.package.F", constructApplicationInfo(0, 0));
+        for (PackageInfo packageInfo : expectedPackageInfos) {
+            mPackageNamesByUids.put(packageInfo.packageIdentifier.uid,
+                    packageInfo.packageIdentifier.name);
+            mSharedPackagesByUids.put(packageInfo.packageIdentifier.uid,
+                    packageInfo.sharedUidPackages.toArray(new String[0]));
+        }
 
-        mockPackageManager(uids, expectedPackageInfos, applicationInfos);
+        mApplicationInfosByPackages.put("vendor.package.D", constructApplicationInfo(0,
+                ApplicationInfo.PRIVATE_FLAG_VENDOR));
+        mApplicationInfosByPackages.put("vendor.package.E", constructApplicationInfo(0,
+                ApplicationInfo.PRIVATE_FLAG_VENDOR));
+        mApplicationInfosByPackages.put("third_party.package.F", constructApplicationInfo(0, 0));
 
         List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
                 uids, new ArrayList<>());
@@ -1156,10 +1227,38 @@
         doReturn(mMockBinder).when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
     }
 
+    private void mockPackageManager() throws Exception {
+        mPackageNamesByUids.clear();
+        mSharedPackagesByUids.clear();
+        mApplicationInfosByPackages.clear();
+        when(mMockPackageManager.getNamesForUids(any())).thenAnswer(args -> {
+            int[] uids = args.getArgument(0);
+            String[] packageNames = new String[uids.length];
+            for (int i = 0; i < uids.length; ++i) {
+                packageNames[i] = mPackageNamesByUids.get(uids[i], null);
+            }
+            return packageNames;
+        });
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenAnswer(
+                args -> mSharedPackagesByUids.get(args.getArgument(0), null));
+
+        when(mMockPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenAnswer(
+                args -> {
+                    String packageName = args.getArgument(0);
+                    ApplicationInfo applicationInfo = mApplicationInfosByPackages
+                            .getOrDefault(packageName, /* defaultValue= */ null);
+                    if (applicationInfo == null) {
+                        throw new PackageManager.NameNotFoundException(
+                                "Package " + packageName + " not found exception");
+                    }
+                    return applicationInfo;
+                });
+    }
+
     private void captureDaemonBinderDeathRecipient() throws Exception {
         ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor =
                 ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
-        verify(mMockBinder, timeout(MAX_WAIT_TIME_MS))
+        verify(mMockBinder, timeout(MAX_WAIT_TIME_MS).atLeastOnce())
                 .linkToDeath(deathRecipientCaptor.capture(), anyInt());
         mCarWatchdogDaemonBinderDeathRecipient = deathRecipientCaptor.getValue();
     }
@@ -1185,11 +1284,14 @@
     }
 
     private ICarWatchdogServiceForSystem registerCarWatchdogService() throws Exception {
+        /* Registering to daemon is done on the main thread. To ensure the registration completes
+         * before verification, execute an empty block on the main thread.
+         */
+        CarServiceUtils.runOnMainSync(() -> {});
+
         ArgumentCaptor<ICarWatchdogServiceForSystem> watchdogServiceForSystemImplCaptor =
                 ArgumentCaptor.forClass(ICarWatchdogServiceForSystem.class);
-        // Registering to daemon is done through a message handler. So, a buffer time of 1000ms is
-        // given.
-        verify(mMockCarWatchdogDaemon, timeout(1000)).registerCarWatchdogService(
+        verify(mMockCarWatchdogDaemon, atLeastOnce()).registerCarWatchdogService(
                 watchdogServiceForSystemImplCaptor.capture());
         return watchdogServiceForSystemImplCaptor.getValue();
     }
@@ -1216,26 +1318,14 @@
         return resourceOveruseConfigurationsCaptor.getValue();
     }
 
-    private void injectUidToPackageNameMapping(SparseArray<String> packageNamesByUid) {
-        when(mMockPackageManager.getNamesForUids(any())).thenAnswer(args -> {
-            int[] uids = args.getArgument(0);
-            String[] packageNames = new String[uids.length];
-            for (int i = 0; i < uids.length; ++i) {
-                packageNames[i] = packageNamesByUid.get(uids[i], null);
-            }
-            return packageNames;
-        });
-    }
-
     private void injectIoOveruseStatsForPackages(SparseArray<String> packageNamesByUid,
-            Set<String> killablePackages) throws Exception {
-        injectUidToPackageNameMapping(packageNamesByUid);
+            Set<String> killablePackages, Set<String> shouldNotifyPackages) throws Exception {
         List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>();
         for (int i = 0; i < packageNamesByUid.size(); ++i) {
             String packageName = packageNamesByUid.valueAt(i);
             int uid = packageNamesByUid.keyAt(i);
             packageIoOveruseStats.add(constructPackageIoOveruseStats(uid,
-                    false,
+                    shouldNotifyPackages.contains(packageName),
                     constructInternalIoOveruseStats(killablePackages.contains(packageName),
                             /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
                             /* writtenBytes= */constructPerStateBytes(100, 200, 300),
@@ -1530,30 +1620,6 @@
         return listener;
     }
 
-    private void mockPackageManager(int[] uids, List<PackageInfo> packageInfos,
-            ArrayMap<String, ApplicationInfo> applicationInfos)
-            throws Exception {
-        String[] packageNames = new String[packageInfos.size()];
-        for (int i = 0; i < packageInfos.size(); ++i) {
-            PackageInfo packageInfo = packageInfos.get(i);
-            packageNames[i] = packageInfo.packageIdentifier.name;
-            when(mMockPackageManager.getPackagesForUid(packageInfo.packageIdentifier.uid))
-                    .thenReturn(packageInfo.sharedUidPackages.toArray(new String[0]));
-        }
-        when(mMockPackageManager.getNamesForUids(any())).thenReturn(packageNames);
-        when(mMockPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenAnswer(
-                (InvocationOnMock invocation) -> {
-                    String packageName = invocation.getArgument(0);
-                    ApplicationInfo applicationInfo = applicationInfos
-                            .getOrDefault(packageName, /* defaultValue= */ null);
-                    if (applicationInfo == null) {
-                        throw new PackageManager.NameNotFoundException(
-                                "Package " + packageName + " not found exception");
-                    }
-                    return applicationInfo;
-                });
-    }
-
     private static PackageInfo constructPackageInfo(String packageName, int uid,
             List<String> sharedUidPackages, int uidType, int componentType, int appCategoryType) {
         PackageInfo packageInfo = new PackageInfo();