Merge "Add ClusterHomeServiceUnitTest." into sc-dev
diff --git a/car-internal-lib/Android.bp b/car-internal-lib/Android.bp
index 9d6aef7..2937bd1 100644
--- a/car-internal-lib/Android.bp
+++ b/car-internal-lib/Android.bp
@@ -28,5 +28,6 @@
         "src/com/android/car/internal/SystemConstants.java",
         "src/com/android/car/internal/ICarServiceHelper.aidl",
         "src/com/android/car/internal/ICarSystemServerClient.aidl",
+        "src/com/android/car/internal/testing/ExcludeFromCodeCoverageGeneratedReport.java",
     ],
 }
diff --git a/car-internal-lib/src/com/android/car/internal/SystemConstants.java b/car-internal-lib/src/com/android/car/internal/SystemConstants.java
index 0025ea7..88356f1 100644
--- a/car-internal-lib/src/com/android/car/internal/SystemConstants.java
+++ b/car-internal-lib/src/com/android/car/internal/SystemConstants.java
@@ -15,6 +15,10 @@
  */
 package com.android.car.internal;
 
+import static com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport;
+
 /**
  * Provides common constants for CarService, CarServiceHelperService and other packages.
  */
@@ -22,6 +26,8 @@
 
     public static final String ICAR_SYSTEM_SERVER_CLIENT = "ICarSystemServerClient";
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
+            details = "private constructor")
     private SystemConstants() {
         throw new UnsupportedOperationException("contains only static constants");
     }
diff --git a/car-internal-lib/src/com/android/car/internal/testing/ExcludeFromCodeCoverageGeneratedReport.java b/car-internal-lib/src/com/android/car/internal/testing/ExcludeFromCodeCoverageGeneratedReport.java
new file mode 100644
index 0000000..b13d295
--- /dev/null
+++ b/car-internal-lib/src/com/android/car/internal/testing/ExcludeFromCodeCoverageGeneratedReport.java
@@ -0,0 +1,69 @@
+/*
+ * 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.internal.testing;
+
+import android.annotation.IntDef;
+
+import com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport.Reason;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+// NOTE: it's copied from car-lib but using a different package
+/**
+ * Annotation used to mark code to be excluded from coverage report.
+ */
+@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD})
+public @interface ExcludeFromCodeCoverageGeneratedReport {
+
+    // Reason annotation and its associated constant values
+    int DEPRECATED_CODE = 0;
+    int BOILERPLATE_CODE = 1;
+    int DUMP_INFO = 2;
+    int DEBUGGING_CODE = 3;
+
+    @IntDef(prefix = "REASON_", value = {
+            DEPRECATED_CODE,
+            BOILERPLATE_CODE,
+            DUMP_INFO,
+            DEBUGGING_CODE
+    })
+    @interface Reason { }
+
+    /**
+     * The reason explaining why the code is being excluded from the code coverage report.
+     * <p>
+     * Possible reasons to exclude code from coverage report are:
+     * <p><ul>
+     * <li>{@link ExcludeFromCodeCoverageGeneratedReport#DEPRECATED_CODE} to exclude deprecated
+     * code from coverage report
+     * <li>{@link ExcludeFromCodeCoverageGeneratedReport#BOILERPLATE_CODE} to exclude boilerplate
+     * code like {@link java.lang.Object} methods, {@link android.os.Parcel} methods, etc
+     * <li>{@link ExcludeFromCodeCoverageGeneratedReport#DUMP_INFO} to exclude dump info methods
+     * <li>{@link ExcludeFromCodeCoverageGeneratedReport#DEBUGGING_CODE} to exclude debugging
+     * purpose
+     * code
+     * </ul><p>
+     */
+    @Reason int reason();
+
+    /**
+     * Optional field used to provide extra details about the excluded code (e.g. it can be used to
+     * tag a follow up bug).
+     */
+    String details() default "";
+}
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index 9c11299..84bbc0d 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -86,7 +86,8 @@
     srcs: [
         "src/com/android/car/internal/common/**/*.java",
         "src/com/android/car/internal/common/EventLogTags.logtags",
-    ]
+        "src/com/android/car/internal/ExcludeFromCodeCoverageGeneratedReport.java",
+    ],
 }
 
 java_library {
diff --git a/car-lib/src/android/car/hardware/power/CarPowerPolicy.java b/car-lib/src/android/car/hardware/power/CarPowerPolicy.java
index 99fb245..bbc37eb 100644
--- a/car-lib/src/android/car/hardware/power/CarPowerPolicy.java
+++ b/car-lib/src/android/car/hardware/power/CarPowerPolicy.java
@@ -16,9 +16,12 @@
 
 package android.car.hardware.power;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -186,6 +189,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/hardware/power/CarPowerPolicy.java",
             inputSignatures = "private final @android.annotation.NonNull java.lang.String mPolicyId\nprivate final @android.annotation.NonNull int[] mEnabledComponents\nprivate final @android.annotation.NonNull int[] mDisabledComponents\nclass CarPowerPolicy extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/hardware/power/CarPowerPolicyFilter.java b/car-lib/src/android/car/hardware/power/CarPowerPolicyFilter.java
index 29b8ad6..2fce4b1 100644
--- a/car-lib/src/android/car/hardware/power/CarPowerPolicyFilter.java
+++ b/car-lib/src/android/car/hardware/power/CarPowerPolicyFilter.java
@@ -16,9 +16,12 @@
 
 package android.car.hardware.power;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -165,6 +168,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/hardware/power/CarPowerPolicyFilter.java",
             inputSignatures = "private @android.annotation.NonNull int[] mComponents\nclass CarPowerPolicyFilter extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/input/CustomInputEvent.java b/car-lib/src/android/car/input/CustomInputEvent.java
index fd5412c..c82fb25 100644
--- a/car-lib/src/android/car/input/CustomInputEvent.java
+++ b/car-lib/src/android/car/input/CustomInputEvent.java
@@ -16,11 +16,14 @@
 
 package android.car.input;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -177,6 +180,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public String toString() {
         // You can override field toString logic by defining methods like:
         // String fieldNameToString() { ... }
@@ -190,6 +194,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public boolean equals(@android.annotation.Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
         // boolean fieldNameEquals(CustomInputEvent other) { ... }
@@ -208,6 +213,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public int hashCode() {
         // You can override field hashCode logic by defining methods like:
         // int fieldNameHashCode() { ... }
@@ -232,6 +238,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public int describeContents() {
         return 0;
     }
@@ -311,6 +318,7 @@
                     + ".Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true,"
                     + " genAidl=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {
     }
 
diff --git a/car-lib/src/android/car/input/RotaryEvent.java b/car-lib/src/android/car/input/RotaryEvent.java
index 565f039..27f2eee 100644
--- a/car-lib/src/android/car/input/RotaryEvent.java
+++ b/car-lib/src/android/car/input/RotaryEvent.java
@@ -15,11 +15,14 @@
  */
 package android.car.input;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 import java.util.Arrays;
@@ -80,6 +83,7 @@
     }
 
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public String toString() {
         return new StringBuilder(128)
                 .append("RotaryEvent{")
@@ -170,6 +174,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public boolean equals(@android.annotation.Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
         // boolean fieldNameEquals(RotaryEvent other) { ... }
@@ -188,6 +193,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public int hashCode() {
         // You can override field hashCode logic by defining methods like:
         // int fieldNameHashCode() { ... }
@@ -214,6 +220,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public int describeContents() { return 0; }
 
     /** @hide */
@@ -259,6 +266,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/input/RotaryEvent.java",
             inputSignatures = "private final @android.car.input.CarInputManager.InputTypeEnum int mInputType\nprivate final  boolean mClockwise\nprivate final @android.annotation.NonNull long[] mUptimeMillisForClicks\npublic  int getNumberOfClicks()\npublic  long getUptimeMillisForClick(int)\npublic @java.lang.Override java.lang.String toString()\nclass RotaryEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/watchdog/IoOveruseAlertThreshold.java b/car-lib/src/android/car/watchdog/IoOveruseAlertThreshold.java
index 153e811..a9886ac 100644
--- a/car-lib/src/android/car/watchdog/IoOveruseAlertThreshold.java
+++ b/car-lib/src/android/car/watchdog/IoOveruseAlertThreshold.java
@@ -16,11 +16,14 @@
 
 package android.car.watchdog;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -166,6 +169,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/watchdog/IoOveruseAlertThreshold.java",
             inputSignatures = "private @android.annotation.SuppressLint long mDurationInSeconds\nprivate  long mWrittenBytesPerSecond\nclass IoOveruseAlertThreshold extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/watchdog/IoOveruseConfiguration.java b/car-lib/src/android/car/watchdog/IoOveruseConfiguration.java
index 7dec00c..608c3c3 100644
--- a/car-lib/src/android/car/watchdog/IoOveruseConfiguration.java
+++ b/car-lib/src/android/car/watchdog/IoOveruseConfiguration.java
@@ -16,10 +16,13 @@
 
 package android.car.watchdog;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 import java.util.List;
@@ -414,6 +417,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/watchdog/IoOveruseConfiguration.java",
             inputSignatures = "private @android.annotation.NonNull android.car.watchdog.PerStateBytes mComponentLevelThresholds\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes> mPackageSpecificThresholds\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes> mAppCategorySpecificThresholds\nprivate @android.annotation.NonNull java.util.List<android.car.watchdog.IoOveruseAlertThreshold> mSystemWideThresholds\nclass IoOveruseConfiguration extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genBuilder=true, genHiddenConstDefs=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/watchdog/IoOveruseStats.java b/car-lib/src/android/car/watchdog/IoOveruseStats.java
index acb30db..4b5c480 100644
--- a/car-lib/src/android/car/watchdog/IoOveruseStats.java
+++ b/car-lib/src/android/car/watchdog/IoOveruseStats.java
@@ -16,9 +16,12 @@
 
 package android.car.watchdog;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -414,6 +417,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/watchdog/IoOveruseStats.java",
             inputSignatures = "private  long mStartTime\nprivate  long mDurationInSeconds\nprivate  long mTotalOveruses\nprivate  long mTotalTimesKilled\nprivate  long mTotalBytesWritten\nprivate  boolean mKillableOnOveruse\nprivate @android.annotation.NonNull android.car.watchdog.PerStateBytes mRemainingWriteBytes\nclass IoOveruseStats extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenBuilder=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/watchdog/PackageKillableState.java b/car-lib/src/android/car/watchdog/PackageKillableState.java
index 53eff70..cd9cfda 100644
--- a/car-lib/src/android/car/watchdog/PackageKillableState.java
+++ b/car-lib/src/android/car/watchdog/PackageKillableState.java
@@ -16,11 +16,14 @@
 
 package android.car.watchdog;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -243,6 +246,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/watchdog/PackageKillableState.java",
             inputSignatures = "public static final  int KILLABLE_STATE_YES\npublic static final  int KILLABLE_STATE_NO\npublic static final  int KILLABLE_STATE_NEVER\nprivate @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.UserIdInt int mUserId\nprivate @android.car.watchdog.PackageKillableState.KillableState int mKillableState\nclass PackageKillableState extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/watchdog/PerStateBytes.java b/car-lib/src/android/car/watchdog/PerStateBytes.java
index 421f607..9343f93 100644
--- a/car-lib/src/android/car/watchdog/PerStateBytes.java
+++ b/car-lib/src/android/car/watchdog/PerStateBytes.java
@@ -16,8 +16,11 @@
 
 package android.car.watchdog;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -167,6 +170,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/watchdog/PerStateBytes.java",
             inputSignatures = "private  long mForegroundModeBytes\nprivate  long mBackgroundModeBytes\nprivate  long mGarageModeBytes\nclass PerStateBytes extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/watchdog/ResourceOveruseConfiguration.java b/car-lib/src/android/car/watchdog/ResourceOveruseConfiguration.java
index b179590..03a972a 100644
--- a/car-lib/src/android/car/watchdog/ResourceOveruseConfiguration.java
+++ b/car-lib/src/android/car/watchdog/ResourceOveruseConfiguration.java
@@ -16,6 +16,8 @@
 
 package android.car.watchdog;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -23,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.os.Parcelable;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 import java.lang.annotation.Retention;
@@ -525,6 +528,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/watchdog/ResourceOveruseConfiguration.java",
             inputSignatures = "public static final  int COMPONENT_TYPE_SYSTEM\npublic static final  int COMPONENT_TYPE_VENDOR\npublic static final  int COMPONENT_TYPE_THIRD_PARTY\npublic static final  java.lang.String APPLICATION_CATEGORY_TYPE_MAPS\npublic static final  java.lang.String APPLICATION_CATEGORY_TYPE_MEDIA\nprivate @android.car.watchdog.ResourceOveruseConfiguration.ComponentType int mComponentType\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mSafeToKillPackages\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mVendorPackagePrefixes\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mPackagesToAppCategoryTypes\nprivate @android.annotation.Nullable android.car.watchdog.IoOveruseConfiguration mIoOveruseConfiguration\nclass ResourceOveruseConfiguration extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genBuilder=true, genHiddenConstDefs=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/android/car/watchdog/ResourceOveruseStats.java b/car-lib/src/android/car/watchdog/ResourceOveruseStats.java
index c57acfd..992cff2 100644
--- a/car-lib/src/android/car/watchdog/ResourceOveruseStats.java
+++ b/car-lib/src/android/car/watchdog/ResourceOveruseStats.java
@@ -16,11 +16,14 @@
 
 package android.car.watchdog;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcelable;
 import android.os.UserHandle;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.util.DataClass;
 
 /**
@@ -256,6 +259,7 @@
             sourceFile = "packages/services/Car/car-lib/src/android/car/watchdog/ResourceOveruseStats.java",
             inputSignatures = "private @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull android.os.UserHandle mUserHandle\nprivate @android.annotation.Nullable android.car.watchdog.IoOveruseStats mIoOveruseStats\nclass ResourceOveruseStats extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenBuilder=true)")
     @Deprecated
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private void __metadata() {}
 
 
diff --git a/car-lib/src/com/android/car/internal/common/CommonConstants.java b/car-lib/src/com/android/car/internal/common/CommonConstants.java
index 82b158a..d4d728e 100644
--- a/car-lib/src/com/android/car/internal/common/CommonConstants.java
+++ b/car-lib/src/com/android/car/internal/common/CommonConstants.java
@@ -16,8 +16,12 @@
 
 package com.android.car.internal.common;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.IntDef;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -28,6 +32,7 @@
  */
 public final class CommonConstants {
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private CommonConstants() {
         throw new UnsupportedOperationException("contains only static constants");
     }
diff --git a/car-lib/src/com/android/car/internal/common/UserHelperLite.java b/car-lib/src/com/android/car/internal/common/UserHelperLite.java
index 4b43e06..c4b8516 100644
--- a/car-lib/src/com/android/car/internal/common/UserHelperLite.java
+++ b/car-lib/src/com/android/car/internal/common/UserHelperLite.java
@@ -16,11 +16,15 @@
 
 package com.android.car.internal.common;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 /**
  * Provides user information related helper methods.
  *
@@ -28,6 +32,8 @@
  */
 public final class UserHelperLite {
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
+            details = "private constructor")
     private UserHelperLite() {
         throw new UnsupportedOperationException("contains only static methods");
     }
diff --git a/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java b/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java
index 1d1c399..f3f0475 100644
--- a/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java
+++ b/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java
@@ -19,6 +19,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.content.Intent;
 import android.content.pm.UserInfo;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.os.UserHandle;
@@ -27,6 +28,7 @@
 import org.mockito.ArgumentMatcher;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Provides custom mockito matcher for Android / Car objects.
@@ -51,6 +53,13 @@
     }
 
     /**
+     * Matches an {@link Intent} for the given action and package name.
+     */
+    public static Intent intentFor(String action, String packageName) {
+        return argThat(new IntentMatcher(action, packageName));
+    }
+
+    /**
      * Matches if a {@link VehiclePropValue} has the given {@code prop}.
      */
     public static VehiclePropValue isProperty(int prop) {
@@ -165,6 +174,30 @@
         }
     }
 
+    private static final class IntentMatcher implements ArgumentMatcher<Intent> {
+
+        private final String mAction;
+        private final String mPackageName;
+
+        private IntentMatcher(String action, String packageName) {
+            mAction = Objects.requireNonNull(action, "action cannot be null");
+            mPackageName = Objects.requireNonNull(packageName, "packageName cannot be null");
+        }
+
+        @Override
+        public boolean matches(Intent argument) {
+            Log.v(TAG, "IntentMatcher: argument=" + argument + ", this=" + this);
+
+            return argument != null && mAction.equals(argument.getAction())
+                    && mPackageName.equals(argument.getPackage());
+        }
+
+        @Override
+        public String toString() {
+            return "intentFor(action=" + mAction + ", pkg=" + mPackageName + ')';
+        }
+    }
+
     private CarArgumentMatchers() {
         throw new UnsupportedOperationException("contains only static methods");
     }
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 6745012..8b75bcb 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -307,18 +307,11 @@
     <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/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index f675d4e..d7c566c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -22,6 +22,8 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Enable multi-user. -->
     <bool name="config_enableMultiUserUI">true</bool>
+    <!--  Maximum number of supported users -->
+    <integer name="config_multiuserMaximumUsers">4</integer>
     <!-- Maximum number of users we allow to be running at a time.
          For automotive, background user will be immediately stopped upon user switching but
          up to this many users can be running in garage mode.
diff --git a/cpp/evs/sampleDriver/bufferCopy.cpp b/cpp/evs/sampleDriver/bufferCopy.cpp
index d9578e6..098af61 100644
--- a/cpp/evs/sampleDriver/bufferCopy.cpp
+++ b/cpp/evs/sampleDriver/bufferCopy.cpp
@@ -123,14 +123,27 @@
 void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
         reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+    // Converts YUY2ToARGB (little endian).  Please note that libyuv uses the
+    // little endian while we're using the big endian in RGB format names.
+    const auto dstStrideInBytes = pDesc->stride * 4;  // 4-byte per pixel
     auto result = libyuv::YUY2ToARGB((const uint8_t*)imgData,
                                      imgStride,             // input stride in bytes
                                      tgt,
-                                     (pDesc->stride << 2),  // output stride in bytes
+                                     dstStrideInBytes,      // output stride in bytes
                                      pDesc->width,
                                      pDesc->height);
     if (result) {
-        LOG(ERROR) << "Failed to convert YUYV to ARGB.";
+        LOG(ERROR) << "Failed to convert YUYV to BGRA.";
+        return;
+    }
+
+    // Swaps R and B pixels to convert BGRA to RGBA in place.
+    // TODO(b/190783702): Consider allocating an extra space to store ARGB data
+    //                    temporarily if below operation is too slow.
+    result = libyuv::ABGRToARGB(tgt, dstStrideInBytes, tgt, dstStrideInBytes,
+                                pDesc->width, pDesc->height);
+    if (result) {
+        LOG(ERROR) << "Failed to convert BGRA to RGBA.";
     }
 }
 
diff --git a/cpp/powerpolicy/server/carpowerpolicyd.xml b/cpp/powerpolicy/server/carpowerpolicyd.xml
index e8df893..0d2462f 100644
--- a/cpp/powerpolicy/server/carpowerpolicyd.xml
+++ b/cpp/powerpolicy/server/carpowerpolicyd.xml
@@ -16,6 +16,7 @@
 <manifest version="1.0" type="framework">
     <hal format="aidl">
         <name>android.frameworks.automotive.powerpolicy</name>
+        <version>1</version>
         <interface>
             <name>ICarPowerPolicyServer</name>
             <instance>default</instance>
diff --git a/cpp/watchdog/server/carwatchdogd.xml b/cpp/watchdog/server/carwatchdogd.xml
index c0c8933..c7adc27 100644
--- a/cpp/watchdog/server/carwatchdogd.xml
+++ b/cpp/watchdog/server/carwatchdogd.xml
@@ -16,6 +16,7 @@
 <manifest version="1.0" type="framework">
     <hal format="aidl">
         <name>android.automotive.watchdog</name>
+        <version>3</version>
         <interface>
             <name>ICarWatchdog</name>
             <instance>default</instance>
diff --git a/service/Android.bp b/service/Android.bp
index 1bc18eb..7d24ac6 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -106,6 +106,10 @@
         "src/com/android/car/Utils.java",
     ],
 
+    static_libs: [
+        "com.android.car.internal.common",
+    ],
+
     product_variables: {
             pdk: {
                 enabled: false,
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 8f90480..d3724dd 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -859,10 +859,10 @@
          android:description="@string/car_permission_desc_set_car_vendor_category_10"/>
 
     <!-- Allows an application to receive Car input events.
-         <p>Protection level: signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.car.permission.CAR_MONITOR_INPUT"
-                android:protectionLevel="signature"
+                android:protectionLevel="signature|privileged"
                 android:label="@string/car_permission_label_monitor_input"
                 android:description="@string/car_permission_desc_monitor_input"/>
 
diff --git a/service/jni/evs/EvsServiceContext.cpp b/service/jni/evs/EvsServiceContext.cpp
index f338eef..b0cc129 100644
--- a/service/jni/evs/EvsServiceContext.cpp
+++ b/service/jni/evs/EvsServiceContext.cpp
@@ -119,8 +119,13 @@
     }
 
     if (isCameraOpened()) {
-        LOG(DEBUG) << "Camera " << id << " is has opened already.";
-        return true;
+        if (!strcmp(id, mCameraIdInUse)) {
+            LOG(DEBUG) << "Camera " << id << " is has opened already.";
+            return true;
+        } else {
+            // Close a current camera device.
+            mService->closeCamera(mCamera);
+        }
     }
 
     sp<IEvsCamera> camera = IEvsCamera::castFrom(mService->openCamera(id));
@@ -140,6 +145,7 @@
         std::lock_guard<std::mutex> lock(mLock);
         mCamera = camera;
         mStreamHandler = streamHandler;
+        mCameraIdInUse = id;
     }
 
     return true;
diff --git a/service/jni/evs/EvsServiceContext.h b/service/jni/evs/EvsServiceContext.h
index d96eadb..84c0012 100644
--- a/service/jni/evs/EvsServiceContext.h
+++ b/service/jni/evs/EvsServiceContext.h
@@ -169,6 +169,9 @@
     // Bookkeeps descriptors of received frame buffers.
     std::map<int, hardware::automotive::evs::V1_1::BufferDesc> mBufferRecords GUARDED_BY(mLock);
 
+    // A name of the camera device currently in use.
+    const char* mCameraIdInUse;
+
     // Service name for EVS enumerator
     static const char* kServiceName;
 
diff --git a/service/src/com/android/car/CanBusErrorNotifier.java b/service/src/com/android/car/CanBusErrorNotifier.java
deleted file mode 100644
index e4770af..0000000
--- a/service/src/com/android/car/CanBusErrorNotifier.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2015 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;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.os.Build;
-import android.util.Log;
-import android.util.Slog;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Class used to notify user about CAN bus failure.
- */
-final class CanBusErrorNotifier {
-    private static final String TAG = CarLog.tagFor(CanBusErrorNotifier.class);
-    private static final int NOTIFICATION_ID = 1;
-    private static final boolean IS_RELEASE_BUILD = "user".equals(Build.TYPE);
-
-    private final Context mContext;
-    private final NotificationManager mNotificationManager;
-
-    // Contains a set of objects that reported failure. The notification will be hidden only when
-    // this set is empty (all reported objects are in love and peace with the vehicle).
-    @GuardedBy("this")
-    private final Set<Object> mReportedObjects = new HashSet<>();
-
-    CanBusErrorNotifier(Context context) {
-        mNotificationManager = (NotificationManager) context.getSystemService(
-                Context.NOTIFICATION_SERVICE);
-        mContext = context;
-    }
-
-    public void removeFailureReport(Object sender) {
-        setCanBusFailure(false, sender);
-    }
-
-    public void reportFailure(Object sender) {
-        setCanBusFailure(true, sender);
-    }
-
-    private void setCanBusFailure(boolean failed, Object sender) {
-        boolean shouldShowNotification;
-        synchronized (this) {
-            boolean changed = failed
-                    ? mReportedObjects.add(sender) : mReportedObjects.remove(sender);
-
-            if (!changed) {
-                return;
-            }
-
-            shouldShowNotification = !mReportedObjects.isEmpty();
-        }
-
-        if (Log.isLoggable(TAG, Log.INFO)) {
-            Slog.i(TAG, "Changing CAN bus failure state to " + shouldShowNotification);
-        }
-
-        if (shouldShowNotification) {
-            showNotification();
-        } else {
-            hideNotification();
-        }
-    }
-
-    private void showNotification() {
-        if (IS_RELEASE_BUILD) {
-            // TODO: for user, we should show message to take car to the dealer. bug:32096297
-            return;
-        }
-        Notification notification =
-                new Notification.Builder(mContext, NotificationChannel.DEFAULT_CHANNEL_ID)
-                        .setContentTitle(mContext.getString(R.string.car_can_bus_failure))
-                        .setContentText(mContext.getString(R.string.car_can_bus_failure_desc))
-                        .setSmallIcon(R.drawable.car_ic_error)
-                        .setOngoing(true)
-                        .build();
-        mNotificationManager.notify(TAG, NOTIFICATION_ID, notification);
-    }
-
-    private void hideNotification() {
-        if (IS_RELEASE_BUILD) {
-            // TODO: for user, we should show message to take car to the dealer. bug:32096297
-            return;
-        }
-        mNotificationManager.cancel(TAG, NOTIFICATION_ID);
-    }
-}
diff --git a/service/src/com/android/car/CarBugreportManagerService.java b/service/src/com/android/car/CarBugreportManagerService.java
index 2be403d..67eec21 100644
--- a/service/src/com/android/car/CarBugreportManagerService.java
+++ b/service/src/com/android/car/CarBugreportManagerService.java
@@ -42,6 +42,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
@@ -86,6 +87,7 @@
     private static final int SOCKET_CONNECTION_RETRY_DELAY_IN_MS = 5000;
 
     private final Context mContext;
+    private final boolean mIsUserBuild;
     private final Object mLock = new Object();
 
     private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
@@ -100,7 +102,14 @@
      * @param context the context
      */
     public CarBugreportManagerService(Context context) {
+        // Per https://source.android.com/setup/develop/new-device, user builds are debuggable=0
+        this(context, !Build.IS_DEBUGGABLE);
+    }
+
+    @VisibleForTesting
+    CarBugreportManagerService(Context context, boolean isUserBuild) {
         mContext = context;
+        mIsUserBuild = isUserBuild;
     }
 
     @Override
@@ -186,8 +195,7 @@
 
     /** Checks only on user builds. */
     private void ensureTheCallerIsDesignatedBugReportApp() {
-        if (Build.IS_DEBUGGABLE) {
-            // Per https://source.android.com/setup/develop/new-device, user builds are debuggable=0
+        if (!mIsUserBuild) {
             return;
         }
         String defaultAppPkgName = mContext.getString(R.string.config_car_bugreport_application);
diff --git a/service/src/com/android/car/CarLog.java b/service/src/com/android/car/CarLog.java
index 23644a3..d629b50 100644
--- a/service/src/com/android/car/CarLog.java
+++ b/service/src/com/android/car/CarLog.java
@@ -16,6 +16,10 @@
 
 package com.android.car;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 /**
  * Helper class for class tags for CarService.
  */
@@ -49,4 +53,10 @@
         if (tag.matches(MATCHER)) return tag;
         return PREFIX + tag;
     }
+
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
+            details = "private constructor")
+    private CarLog() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
 }
diff --git a/service/src/com/android/car/CarService.java b/service/src/com/android/car/CarService.java
index 6a90f9c..7aa2cca 100644
--- a/service/src/com/android/car/CarService.java
+++ b/service/src/com/android/car/CarService.java
@@ -54,28 +54,11 @@
 
     private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
 
-    private CanBusErrorNotifier mCanBusErrorNotifier;
     private ICarImpl mICarImpl;
     private IVehicle mVehicle;
 
     private String mVehicleInterfaceName;
 
-    // If 10 crashes of Vehicle HAL occurred within 10 minutes then thrown an exception in
-    // Car Service.
-    private final CrashTracker mVhalCrashTracker = new CrashTracker(
-            10,  // Max crash count.
-            10 * 60 * 1000,  // 10 minutes - sliding time window.
-            () -> {
-                if (IS_USER_BUILD) {
-                    Slog.e(CarLog.TAG_SERVICE, "Vehicle HAL keeps crashing, notifying user...");
-                    mCanBusErrorNotifier.reportFailure(CarService.this);
-                } else {
-                    throw new RuntimeException(
-                            "Vehicle HAL crashed too many times in a given time frame");
-                }
-            }
-    );
-
     private final VehicleDeathRecipient mVehicleDeathRecipient = new VehicleDeathRecipient();
 
     @Override
@@ -84,8 +67,6 @@
                 Trace.TRACE_TAG_SYSTEM_SERVER, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
         initTiming.traceBegin("CarService.onCreate");
 
-        mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
-
         initTiming.traceBegin("getVehicle");
         mVehicle = getVehicle();
         initTiming.traceEnd();
@@ -107,7 +88,6 @@
         mICarImpl = new ICarImpl(this,
                 mVehicle,
                 SystemInterface.Builder.defaultSystemInterface(this).build(),
-                mCanBusErrorNotifier,
                 mVehicleInterfaceName);
         mICarImpl.init();
 
@@ -129,7 +109,6 @@
         EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
         Slog.i(CarLog.TAG_SERVICE, "Service onDestroy");
         mICarImpl.release();
-        mCanBusErrorNotifier.removeFailureReport(this);
 
         if (mVehicle != null) {
             try {
@@ -176,10 +155,6 @@
             vehicle = getVehicle();
         }
 
-        if (vehicle != null) {
-            mCanBusErrorNotifier.removeFailureReport(this);
-        }
-
         return vehicle;
     }
 
@@ -202,34 +177,8 @@
         @Override
         public void serviceDied(long cookie) {
             EventLog.writeEvent(EventLogTags.CAR_SERVICE_VHAL_DIED, cookie);
-            if (RESTART_CAR_SERVICE_WHEN_VHAL_CRASH) {
-                Slog.wtf(CarLog.TAG_SERVICE, "***Vehicle HAL died. Car service will restart***");
-                Process.killProcess(Process.myPid());
-                return;
-            }
-
-            Slog.wtf(CarLog.TAG_SERVICE, "***Vehicle HAL died.***");
-
-            try {
-                mVehicle.unlinkToDeath(this);
-            } catch (RemoteException e) {
-                Slog.e(CarLog.TAG_SERVICE, "Failed to unlinkToDeath", e); // Log and continue.
-            }
-            mVehicle = null;
-
-            mVhalCrashTracker.crashDetected();
-
-            Slog.i(CarLog.TAG_SERVICE,
-                    "Trying to reconnect to Vehicle HAL: " + mVehicleInterfaceName);
-            mVehicle = getVehicleWithTimeout(WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS);
-            if (mVehicle == null) {
-                throw new IllegalStateException("Failed to reconnect to Vehicle HAL");
-            }
-
-            linkToDeath(mVehicle, this);
-
-            Slog.i(CarLog.TAG_SERVICE, "Notifying car service Vehicle HAL reconnected...");
-            mICarImpl.vehicleHalReconnected(mVehicle);
+            Slog.wtf(CarLog.TAG_SERVICE, "***Vehicle HAL died. Car service will restart***");
+            Process.killProcess(Process.myPid());
         }
     }
 
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index dcc9371..1df0b63 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -90,6 +90,7 @@
 
 import com.android.car.am.FixedActivityService;
 import com.android.car.audio.CarAudioService;
+import com.android.car.evs.CarEvsService;
 import com.android.car.garagemode.GarageModeService;
 import com.android.car.hal.InputHalService;
 import com.android.car.hal.UserHalService;
@@ -179,6 +180,9 @@
     private static final String DRIVING_STATE_PARK = "park";
     private static final String DRIVING_STATE_REVERSE = "reverse";
 
+    private static final String COMMAND_SET_REARVIEW_CAMERA_ID = "set-rearview-camera-id";
+    private static final String COMMAND_GET_REARVIEW_CAMERA_ID = "get-rearview-camera-id";
+
     private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
             android.Manifest.permission.CREATE_USERS,
             android.Manifest.permission.MANAGE_USERS
@@ -336,6 +340,7 @@
     private final GarageModeService mGarageModeService;
     private final CarUserService mCarUserService;
     private final CarOccupantZoneService mCarOccupantZoneService;
+    private final CarEvsService mCarEvsService;
     private long mKeyDownTime;
 
     CarShellCommand(Context context,
@@ -351,7 +356,8 @@
             SystemInterface systemInterface,
             GarageModeService garageModeService,
             CarUserService carUserService,
-            CarOccupantZoneService carOccupantZoneService) {
+            CarOccupantZoneService carOccupantZoneService,
+            CarEvsService carEvsService) {
         mContext = context;
         mHal = hal;
         mCarAudioService = carAudioService;
@@ -366,6 +372,7 @@
         mGarageModeService = garageModeService;
         mCarUserService = carUserService;
         mCarOccupantZoneService = carOccupantZoneService;
+        mCarEvsService = carEvsService;
     }
 
     @Override
@@ -566,6 +573,15 @@
         pw.printf("\t%s [%s] [%s]\n", COMMAND_POWER_OFF, POWER_OFF_SKIP_GARAGEMODE,
                 POWER_OFF_SHUTDOWN);
         pw.println("\t  Powers off the car.");
+
+        pw.printf("\t%s <CAMERA_ID>\n", COMMAND_SET_REARVIEW_CAMERA_ID);
+        pw.println("\t  Configures a target camera device CarEvsService to use.");
+        pw.println("\t  If CAMEAR_ID is \"default\", this command will configure CarEvsService ");
+        pw.println("\t  to use its default camera device.");
+
+        pw.printf("\t%s\n", COMMAND_GET_REARVIEW_CAMERA_ID);
+        pw.println("\t  Gets the name of the camera device CarEvsService is using for " +
+                "the rearview.");
     }
 
     private static int showInvalidArguments(IndentingPrintWriter pw) {
@@ -882,6 +898,12 @@
             case COMMAND_POWER_OFF:
                 powerOff(args, writer);
                 break;
+            case COMMAND_SET_REARVIEW_CAMERA_ID:
+                setRearviewCameraId(args, writer);
+                break;
+            case COMMAND_GET_REARVIEW_CAMERA_ID:
+                getRearviewCameraId(writer);
+                break;
 
             default:
                 writer.println("Unknown command: \"" + cmd + "\"");
@@ -2029,6 +2051,25 @@
 
     }
 
+    // Set a target camera device for the rearview
+    private void setRearviewCameraId(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 2) {
+            showInvalidArguments(writer);
+            return;
+        }
+
+        if (!mCarEvsService.setRearviewCameraIdFromCommand(args[1])) {
+            writer.println("Failed to set CarEvsService rearview camera device id.");
+        } else {
+            writer.printf("CarEvsService is set to use %s.\n", args[1]);
+        }
+    }
+
+    private void getRearviewCameraId(IndentingPrintWriter writer) {
+        writer.printf("CarEvsService is using %s for the rearview.\n",
+                mCarEvsService.getRearviewCameraIdFromCommand());
+    }
+
     // Check if the given property is global
     private static boolean isPropertyAreaTypeGlobal(@Nullable String property) {
         if (property == null) {
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index e2c2b08..68af541 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -159,15 +159,15 @@
     private final ICarSystemServerClientImpl mICarSystemServerClientImpl;
 
     public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
-            CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
-        this(serviceContext, vehicle, systemInterface, errorNotifier, vehicleInterfaceName,
+            String vehicleInterfaceName) {
+        this(serviceContext, vehicle, systemInterface, vehicleInterfaceName,
                 /* carUserService= */ null, /* carWatchdogService= */ null,
                 /* powerPolicyDaemon= */ null);
     }
 
     @VisibleForTesting
     ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
-            CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,
+            String vehicleInterfaceName,
             @Nullable CarUserService carUserService,
             @Nullable CarWatchdogService carWatchdogService,
             @Nullable ICarPowerPolicySystemNotification powerPolicyDaemon) {
@@ -844,7 +844,7 @@
         return new CarShellCommand(mContext, mHal, mCarAudioService, mCarPackageManagerService,
                 mCarProjectionService, mCarPowerManagementService, mFixedActivityService,
                 mFeatureController, mCarInputService, mCarNightService, mSystemInterface,
-                mGarageModeService, mCarUserService, mCarOccupantZoneService);
+                mGarageModeService, mCarUserService, mCarOccupantZoneService, mCarEvsService);
     }
 
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
diff --git a/service/src/com/android/car/PerUserCarService.java b/service/src/com/android/car/PerUserCarService.java
index ee4dafe..6a9291a 100644
--- a/service/src/com/android/car/PerUserCarService.java
+++ b/service/src/com/android/car/PerUserCarService.java
@@ -76,7 +76,7 @@
 
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
             mPerUserCarDevicePolicyService = PerUserCarDevicePolicyService.getInstance(context);
-            mPerUserCarDevicePolicyService.registerBroadcastReceiver();
+            mPerUserCarDevicePolicyService.onCreate();
         } else if (DBG) {
             Slogf.d(TAG, "Not setting PerUserCarDevicePolicyService because device doesn't have %s",
                     PackageManager.FEATURE_DEVICE_ADMIN);
diff --git a/service/src/com/android/car/SparseArrayStream.java b/service/src/com/android/car/SparseArrayStream.java
index cbe2ca3..574f107 100644
--- a/service/src/com/android/car/SparseArrayStream.java
+++ b/service/src/com/android/car/SparseArrayStream.java
@@ -15,9 +15,13 @@
  */
 package com.android.car;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.util.Pair;
 import android.util.SparseArray;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
@@ -37,4 +41,10 @@
         return IntStream.range(0, array.size()).mapToObj(
             i -> new Pair<>(array.keyAt(i), array.valueAt(i)));
     }
+
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
+            details = "private constructor")
+    private SparseArrayStream() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
 }
diff --git a/service/src/com/android/car/Utils.java b/service/src/com/android/car/Utils.java
index 41ab67b..c6f5ef9 100644
--- a/service/src/com/android/car/Utils.java
+++ b/service/src/com/android/car/Utils.java
@@ -15,6 +15,8 @@
  */
 package com.android.car;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -23,6 +25,8 @@
 import android.bluetooth.BluetoothProfile;
 import android.util.SparseArray;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -140,7 +144,7 @@
      * A specific service in CarService can choose to use a circular buffer of N records to keep
      * track of the last N transitions.
      */
-    public static class TransitionLog {
+    public static final class TransitionLog {
         private String mServiceName; // name of the service or tag
         private Object mFromState; // old state
         private Object mToState; // new state
@@ -166,8 +170,9 @@
 
         @Override
         public String toString() {
-            return timeToLog(mTimestampMs) + " " + mServiceName + ": " + (mExtra != null ? mExtra
-                    : "") + " changed from " + mFromState + " to " + mToState;
+            return timeToLog(mTimestampMs) + " " + mServiceName + ": "
+                    + (mExtra != null ? mExtra + " " : "")
+                    + "changed from " + mFromState + " to " + mToState;
         }
     }
 
@@ -278,4 +283,9 @@
         return outputStream.toByteArray();
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
+            details = "private constructor")
+    private Utils() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
 }
diff --git a/service/src/com/android/car/admin/NewUserDisclaimerActivity.java b/service/src/com/android/car/admin/NewUserDisclaimerActivity.java
index 4101c34..8a186a4 100644
--- a/service/src/com/android/car/admin/NewUserDisclaimerActivity.java
+++ b/service/src/com/android/car/admin/NewUserDisclaimerActivity.java
@@ -30,6 +30,7 @@
 import com.android.car.CarLog;
 import com.android.car.R;
 import com.android.car.admin.ui.ManagedDeviceTextView;
+import com.android.internal.annotations.VisibleForTesting;
 
 // TODO(b/171603586): STOPSHIP move UI related activities to CarSettings
 /**
@@ -65,6 +66,11 @@
         // and/or integrate it with UserNoticeService
     }
 
+    @VisibleForTesting
+    Button getAcceptButton() {
+        return mAcceptButton;
+    }
+
     private void accept() {
         if (DEBUG) Slog.d(TAG, "user accepted");
 
@@ -72,13 +78,8 @@
         finish();
     }
 
-    private static Intent newIntent(Context context) {
-        return new Intent(context, NewUserDisclaimerActivity.class);
-    }
-
     static void showNotification(Context context) {
-        PendingIntent pendingIntent = PendingIntent.getActivity(context, NOTIFICATION_ID,
-                newIntent(context), PendingIntent.FLAG_IMMUTABLE, null);
+        PendingIntent pendingIntent = getPendingIntent(context, /* extraFlags= */ 0);
 
         Notification notification = NotificationHelper
                 .newNotificationBuilder(context, NotificationManager.IMPORTANCE_DEFAULT)
@@ -104,7 +105,13 @@
                     + context.getUserId());
         }
         context.getSystemService(NotificationManager.class).cancel(NOTIFICATION_ID);
-        PendingIntent.getActivity(context, NOTIFICATION_ID, newIntent(context),
-                PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT).cancel();
+        getPendingIntent(context, PendingIntent.FLAG_UPDATE_CURRENT).cancel();
+    }
+
+    @VisibleForTesting
+    static PendingIntent getPendingIntent(Context context, int extraFlags) {
+        return PendingIntent.getActivity(context, NOTIFICATION_ID,
+                new Intent(context, NewUserDisclaimerActivity.class),
+                PendingIntent.FLAG_IMMUTABLE | extraFlags);
     }
 }
diff --git a/service/src/com/android/car/admin/PerUserCarDevicePolicyService.java b/service/src/com/android/car/admin/PerUserCarDevicePolicyService.java
index 4373a74..50ff4f7 100644
--- a/service/src/com/android/car/admin/PerUserCarDevicePolicyService.java
+++ b/service/src/com/android/car/admin/PerUserCarDevicePolicyService.java
@@ -16,6 +16,7 @@
 package com.android.car.admin;
 
 import static com.android.car.admin.CarDevicePolicyService.DEBUG;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.IntDef;
 import android.app.admin.DevicePolicyManager;
@@ -28,12 +29,14 @@
 import android.util.Slog;
 
 import com.android.car.CarLog;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
-// TODO(b/175057848) add unit tests
 /**
  * User-specific {@code CarDevicePolicyManagerService}.
  */
@@ -92,6 +95,8 @@
      * Gests the singleton instance, creating it if necessary.
      */
     public static PerUserCarDevicePolicyService getInstance(Context context) {
+        Objects.requireNonNull(context, "context cannot be null");
+
         synchronized (SLOCK) {
             if (sInstance == null) {
                 sInstance = new PerUserCarDevicePolicyService(context.getApplicationContext());
@@ -102,14 +107,15 @@
         }
     }
 
-    private PerUserCarDevicePolicyService(Context context) {
+    @VisibleForTesting
+    PerUserCarDevicePolicyService(Context context) {
         mContext = context;
     }
 
     /**
-     * Register a broadcast receiver to receive the proper events.
+     * Callback for when the service is created.
      */
-    public void registerBroadcastReceiver() {
+    public void onCreate() {
         if (DEBUG) Slog.d(TAG, "registering BroadcastReceiver");
 
         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
@@ -130,6 +136,7 @@
     /**
      * Dump its contents.
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter pw) {
         synchronized (SLOCK) {
             pw.printf("mNewUserDisclaimerStatus: %s\n",
@@ -166,7 +173,16 @@
         }
     }
 
-    private String newUserDisclaimerStatusToString(@NewUserDisclaimerStatus int status) {
+    @VisibleForTesting
+    @NewUserDisclaimerStatus
+    int getNewUserDisclaimerStatus() {
+        synchronized (SLOCK) {
+            return mNewUserDisclaimerStatus;
+        }
+    }
+
+    @VisibleForTesting
+    static String newUserDisclaimerStatusToString(@NewUserDisclaimerStatus int status) {
         return DebugUtils.constantToString(PerUserCarDevicePolicyService.class,
                 PREFIX_NEW_USER_DISCLAIMER_STATUS, status);
     }
diff --git a/service/src/com/android/car/cluster/ClusterHomeService.java b/service/src/com/android/car/cluster/ClusterHomeService.java
index 0baa793..b032d93 100644
--- a/service/src/com/android/car/cluster/ClusterHomeService.java
+++ b/service/src/com/android/car/cluster/ClusterHomeService.java
@@ -21,6 +21,7 @@
 import static com.android.car.hal.ClusterHalService.DISPLAY_OFF;
 import static com.android.car.hal.ClusterHalService.DISPLAY_ON;
 import static com.android.car.hal.ClusterHalService.DONT_CARE;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.app.ActivityOptions;
 import android.car.Car;
@@ -54,6 +55,7 @@
 import com.android.car.R;
 import com.android.car.am.FixedActivityService;
 import com.android.car.hal.ClusterHalService;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.server.utils.Slogf;
 
 /**
@@ -173,6 +175,7 @@
     }
 
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter writer) {
         // TODO: record the latest states from both sides
     }
diff --git a/service/src/com/android/car/cluster/ClusterNavigationService.java b/service/src/com/android/car/cluster/ClusterNavigationService.java
index 28e5a65..de6aa89 100644
--- a/service/src/com/android/car/cluster/ClusterNavigationService.java
+++ b/service/src/com/android/car/cluster/ClusterNavigationService.java
@@ -15,9 +15,10 @@
  */
 package com.android.car.cluster;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.car.Car;
 import android.car.CarAppFocusManager;
-import android.car.cluster.renderer.IInstrumentCluster;
 import android.car.cluster.renderer.IInstrumentClusterNavigation;
 import android.car.navigation.CarNavigationInstrumentCluster;
 import android.content.Context;
@@ -33,6 +34,7 @@
 import com.android.car.CarLog;
 import com.android.car.CarServiceBase;
 import com.android.car.ICarImpl;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.Objects;
@@ -117,6 +119,7 @@
     }
 
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter writer) {
         writer.println("**" + getClass().getSimpleName() + "**");
         synchronized (mLock) {
@@ -155,8 +158,6 @@
         if (appType != CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION) {
             return;
         }
-
-        IInstrumentCluster service;
         ContextOwner requester = new ContextOwner(uid, pid);
         ContextOwner newOwner = acquire ? requester : NO_OWNER;
         ClusterNavigationServiceCallback callback;
diff --git a/service/src/com/android/car/cluster/InstrumentClusterService.java b/service/src/com/android/car/cluster/InstrumentClusterService.java
index a36c898..4737b21 100644
--- a/service/src/com/android/car/cluster/InstrumentClusterService.java
+++ b/service/src/com/android/car/cluster/InstrumentClusterService.java
@@ -18,6 +18,8 @@
 import static android.car.cluster.renderer.InstrumentClusterRenderingService.EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER;
 import static android.car.settings.CarSettings.Global.DISABLE_INSTRUMENTATION_SERVICE;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.annotation.SystemApi;
 import android.app.ActivityOptions;
 import android.car.cluster.IInstrumentClusterManagerCallback;
@@ -52,6 +54,7 @@
 import com.android.car.R;
 import com.android.car.am.FixedActivityService;
 import com.android.car.cluster.ClusterNavigationService.ContextOwner;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -296,6 +299,7 @@
     }
 
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter writer) {
         writer.println("**" + getClass().getSimpleName() + "**");
         synchronized (mLock) {
diff --git a/service/src/com/android/car/evs/CarEvsService.java b/service/src/com/android/car/evs/CarEvsService.java
index 764fb08..b9d19eb 100644
--- a/service/src/com/android/car/evs/CarEvsService.java
+++ b/service/src/com/android/car/evs/CarEvsService.java
@@ -50,6 +50,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleGear;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -151,6 +152,8 @@
         }
     }
 
+    private static final String COMMAND_TO_USE_DEFAULT_CAMERA = "default";
+
     private final Context mContext;
     private final EvsHalService mEvsHalService;
     private final CarPropertyService mPropertyService;
@@ -523,6 +526,12 @@
     // EVS_SERVICE_REQUEST.
     private boolean mUseGearSelection = true;
 
+    // When this is set, CarEvsService will attempt to open a camera device the user sets.
+    private boolean mUseCameraIdOverride = false;
+
+    // This is a device name to be used when mUseCameraIdOverride is true.
+    private String mCameraIdOverride;
+
     private void setSessionToken(IBinder token) {
         synchronized (mLock) {
             mSessionToken = token;
@@ -960,6 +969,54 @@
         }
     }
 
+    /**
+     * Sets a camera device for the rearview.
+     *
+     * <p>Requires {@link android.car.Car.PERMISSION_USE_CAR_EVS_CAMERA} permissions to access.
+     *
+     * @param id A string identifier of a target camera device.
+     * @return This method return a false if this runs in a release build; otherwise, this returns
+     *         true.
+     */
+    public boolean setRearviewCameraIdFromCommand(@NonNull String id) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_EVS_CAMERA);
+        Objects.requireNonNull(id);
+
+        if (!Build.IS_DEBUGGABLE) {
+            // This method is not allowed in the release build.
+            return false;
+        }
+
+        if (id.equalsIgnoreCase(COMMAND_TO_USE_DEFAULT_CAMERA)) {
+            mUseCameraIdOverride = false;
+            Slog.i(TAG_EVS, "CarEvsService is set to use the default device for the rearview.");
+        } else {
+            mCameraIdOverride = id;
+            mUseCameraIdOverride = true;
+            Slog.i(TAG_EVS, "CarEvsService is set to use " + id + " for the rearview.");
+        }
+
+        return true;
+    }
+
+    /**
+     * Gets an identifier of a current camera device for the rearview.
+     *
+     * <p>Requires {@link android.car.Car.PERMISSION_MONITOR_CAR_EVS_STATUS} permissions to
+     * access.
+     *
+     * @return A string identifier of current rearview camera device.
+     */
+    @NonNull
+    public String getRearviewCameraIdFromCommand() {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_MONITOR_CAR_EVS_STATUS);
+        if (mUseCameraIdOverride) {
+            return mCameraIdOverride;
+        } else {
+            return mContext.getString(R.string.config_evsRearviewCameraId);
+        }
+    }
+
     /** Handles client disconnections; may request to stop a video stream. */
     private void handleClientDisconnected(ICarEvsStreamCallback callback) {
         // If the last stream client is disconnected before it stops a video stream, request to stop
@@ -995,8 +1052,14 @@
             return false;
         }
 
-        if (!nativeOpenCamera(mNativeEvsServiceObj,
-                mContext.getString(R.string.config_evsRearviewCameraId))) {
+        String cameraId;
+        if (mUseCameraIdOverride) {
+            cameraId = mCameraIdOverride;
+        } else {
+            cameraId = mContext.getString(R.string.config_evsRearviewCameraId);
+        }
+
+        if (!nativeOpenCamera(mNativeEvsServiceObj, cameraId)) {
             Slog.e(TAG_EVS, "Failed to open a target camera device");
             return false;
         }
diff --git a/service/src/com/android/car/user/CarUserNoticeService.java b/service/src/com/android/car/user/CarUserNoticeService.java
index a96478b..8148867 100644
--- a/service/src/com/android/car/user/CarUserNoticeService.java
+++ b/service/src/com/android/car/user/CarUserNoticeService.java
@@ -18,6 +18,8 @@
 
 import static android.car.hardware.power.CarPowerManager.CarPowerStateListener;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -53,6 +55,7 @@
 import com.android.car.CarLog;
 import com.android.car.CarServiceBase;
 import com.android.car.R;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -425,6 +428,7 @@
     }
 
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter writer) {
         synchronized (mLock) {
             if (mServiceIntent == null) {
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index de5739a..e61419b 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -22,6 +22,7 @@
 
 import static com.android.car.PermissionHelper.checkHasAtLeastOnePermissionGranted;
 import static com.android.car.PermissionHelper.checkHasDumpPermissionGranted;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -98,6 +99,7 @@
 import com.android.car.CarUxRestrictionsManagerService;
 import com.android.car.R;
 import com.android.car.hal.UserHalService;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.ICarServiceHelper;
 import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
 import com.android.car.internal.common.EventLogTags;
@@ -351,6 +353,7 @@
     }
 
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(@NonNull IndentingPrintWriter writer) {
         checkHasDumpPermissionGranted("dump()");
 
diff --git a/service/src/com/android/car/user/InitialUserSetter.java b/service/src/com/android/car/user/InitialUserSetter.java
index 1d35f93..29406db 100644
--- a/service/src/com/android/car/user/InitialUserSetter.java
+++ b/service/src/com/android/car/user/InitialUserSetter.java
@@ -17,6 +17,8 @@
 
 import static android.car.userlib.UserHalHelper.userFlagsToString;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -39,6 +41,7 @@
 import android.util.TimingsTraceLog;
 
 import com.android.car.CarLog;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.common.UserHelperLite;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
@@ -663,6 +666,7 @@
     /**
      * Dumps it state.
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(@NonNull PrintWriter writer) {
         writer.println("InitialUserSetter");
         String indent = "  ";
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarSettingsTest.java b/tests/android_car_api_test/src/android/car/apitest/CarSettingsTest.java
new file mode 100644
index 0000000..a3070f0
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarSettingsTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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 android.car.apitest;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.annotation.UserIdInt;
+import android.car.settings.CarSettings;
+import android.content.ContentResolver;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+@SmallTest
+public final class CarSettingsTest extends CarApiTestBase {
+
+    private static final String TAG = CarSettingsTest.class.getSimpleName();
+    private static final String SCOPE_GLOBAL = "Global";
+    private static final String SCOPE_SECURE = "Secure";
+
+    private final HashMap<String, String> mSettings = new HashMap<>();
+    private final @UserIdInt int mUserId = UserHandle.USER_CURRENT;
+
+    private final ContentResolver mContentResolver;
+
+    public CarSettingsTest() throws Exception {
+        mContentResolver = getContext().getContentResolver();
+    }
+
+    @Test
+    public void testCarSettingsNames() throws Exception {
+        loadSettingNames();
+
+        boolean isAllSettingsReadable = checkAllSettingsReadable();
+
+        assertWithMessage("car settings readable").that(isAllSettingsReadable).isTrue();
+    }
+
+    private void loadSettingNames() {
+        mSettings.put(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, SCOPE_GLOBAL);
+        mSettings.put(CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, SCOPE_GLOBAL);
+        mSettings.put(CarSettings.Global.DISABLE_INSTRUMENTATION_SERVICE, SCOPE_GLOBAL);
+        mSettings.put(CarSettings.Global.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE, SCOPE_GLOBAL);
+        mSettings.put(CarSettings.Global.LAST_ACTIVE_USER_ID, SCOPE_GLOBAL);
+        mSettings.put(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID, SCOPE_GLOBAL);
+        mSettings.put(CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL,
+                SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES, SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER, SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS, SCOPE_SECURE);
+
+        mSettings.put(CarSettings.Secure.KEY_BLUETOOTH_A2DP_SINK_DEVICES, SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_BLUETOOTH_PAN_DEVICES, SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_BLUETOOTH_HFP_CLIENT_DEVICES, SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_BLUETOOTH_MAP_CLIENT_DEVICES, SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_BLUETOOTH_PBAP_CLIENT_DEVICES, SCOPE_SECURE);
+        mSettings.put(CarSettings.Secure.KEY_BLUETOOTH_PROFILES_INHIBITED, SCOPE_SECURE);
+    }
+
+    private boolean checkAllSettingsReadable() throws Exception {
+        Iterator<Map.Entry<String, String>> settingEntrys = mSettings.entrySet().iterator();
+        while (settingEntrys.hasNext()) {
+            Map.Entry<String, String> entry = settingEntrys.next();
+            String name = entry.getKey();
+            String scope = entry.getValue();
+            switch (scope) {
+                case SCOPE_GLOBAL:
+                    Settings.Global.getString(mContentResolver, name);
+                    break;
+                case SCOPE_SECURE:
+                    Settings.Secure.getStringForUser(mContentResolver, name, mUserId);
+                    break;
+                default:
+                    Log.e(TAG, "unsupported scope: " + scope);
+                    return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java b/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
index 8aeea95..cb15747 100644
--- a/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
@@ -96,7 +96,9 @@
 
     @After
     public void tearDown() throws Exception {
-        mEvsManager.stopVideoStream();
+        if (mEvsManager != null) {
+            mEvsManager.stopVideoStream();
+        }
     }
 
     @Test
diff --git a/tests/carservice_test/src/com/android/car/ICarImplTest.java b/tests/carservice_test/src/com/android/car/ICarImplTest.java
index 574b8ed..c0ba62a 100644
--- a/tests/carservice_test/src/com/android/car/ICarImplTest.java
+++ b/tests/carservice_test/src/com/android/car/ICarImplTest.java
@@ -165,7 +165,7 @@
         doThrow(new NullPointerException()).when(mContext).getDataDir();
 
         ICarImpl carImpl = new ICarImpl(mContext, mMockVehicle, mFakeSystemInterface,
-                /* errorNotifier= */ null, "MockedCar", /* carUserService= */ null,
+                "MockedCar", /* carUserService= */ null,
                 mCarWatchdogService, new MockedCarTestBase.FakeCarPowerPolicyDaemon());
         carImpl.init();
         Car mCar = new Car(mContext, carImpl, /* handler= */ null);
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index 9794b19..4119b8c 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -232,7 +232,7 @@
         // This should be done here as feature property is accessed inside the constructor.
         initMockedHal();
         mCarImpl = new ICarImpl(mMockedCarTestContext, mMockedVehicleHal, mFakeSystemInterface,
-                /* errorNotifier= */ null , "MockedCar", mCarUserService, mCarWatchdogService,
+                "MockedCar", mCarUserService, mCarWatchdogService,
                 mPowerPolicyDaemon);
 
         spyOnBeforeCarImplInit();
diff --git a/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java b/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java
index c1b45d3..cd9adfb 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java
@@ -60,6 +60,15 @@
     }
 
     @Test
+    public void testInitAndRelease() {
+        mService.init();
+        mService.release();
+
+        verify(mMockController).init();
+        verify(mMockController).release();
+    }
+
+    @Test
     public void testDump_shouldSucceed() {
         when(mMockController.isGarageModeActive()).thenReturn(true);
 
@@ -68,4 +77,33 @@
         List<String> strings = mCaptorString.getAllValues();
         assertThat(strings.get(0)).isEqualTo("GarageModeInProgress true");
     }
+
+    @Test
+    public void testIsGarageModeActive_true() {
+        when(mMockController.isGarageModeActive()).thenReturn(true);
+
+        assertThat(mService.isGarageModeActive()).isTrue();
+    }
+
+    @Test
+    public void testIsGarageModeActive_false() {
+        when(mMockController.isGarageModeActive()).thenReturn(false);
+
+        assertThat(mService.isGarageModeActive()).isFalse();
+    }
+
+    @Test
+    public void testForceStartGarageMode() {
+        mService.forceStartGarageMode();
+
+        verify(mMockController).initiateGarageMode(null);
+    }
+
+    @Test
+    public void testStopAndResetGarageMode() {
+        mService.stopAndResetGarageMode();
+
+        verify(mMockController).resetGarageMode();
+    }
+
 }
diff --git a/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java b/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
index 499a95f..6133baf 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
@@ -98,10 +98,12 @@
         ArrayList<Integer> userToStartInBackground = new ArrayList<>(Arrays.asList(101, 102, 103));
         when(mCarUserService.startAllBackgroundUsersInGarageMode())
                 .thenReturn(userToStartInBackground);
-        mGarageMode.enterGarageMode(/* future= */ null);
+
         CountDownLatch latch = new CountDownLatch(3); // 3 for three users
         mockCarUserServiceStopUserCall(getEventListener(), latch);
 
+        mGarageMode.enterGarageMode(/* future= */ null);
+
         mGarageMode.cancel();
 
         waitForHandlerThreadToFinish(latch);
diff --git a/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java b/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
index a9e678f..5cb55c3 100644
--- a/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
@@ -34,6 +34,7 @@
 import android.car.input.RotaryEvent;
 import android.hardware.automotive.vehicle.V2_0.VehicleDisplay;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.os.SystemClock;
 import android.util.Log;
 import android.util.Pair;
 import android.view.KeyEvent;
@@ -50,6 +51,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -264,6 +266,50 @@
     }
 
     @Test
+    public void testInjectKeyEvent_mainDisplay() throws Exception {
+        int r = mCarInputManager.requestInputEventCapture(
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        KeyEvent keyEvent = newKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
+
+        mCarInputManager.injectKeyEvent(keyEvent, CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+
+        mCallback0.waitForKeyEvent();
+        assertThat(mCallback0.getkeyEvents()).containsExactly(
+                new Pair<>(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                        Collections.singletonList(keyEvent)));
+    }
+
+    @Test
+    public void testInjectKeyEvent_instrumentClusterDisplay() throws Exception {
+        int r = mCarInputManager.requestInputEventCapture(
+                CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        KeyEvent keyEvent = newKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
+
+        mCarInputManager.injectKeyEvent(keyEvent,
+                CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER);
+
+        mCallback0.waitForKeyEvent();
+        assertThat(mCallback0.getkeyEvents()).containsExactly(
+                new Pair<>(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
+                        Collections.singletonList(keyEvent)));
+    }
+
+    private static KeyEvent newKeyEvent(int action, int code) {
+        long currentTime = SystemClock.uptimeMillis();
+        return new KeyEvent(/* downTime= */ currentTime,
+                /* eventTime= */ currentTime, action, code,
+                /* repeat= */ 0);
+    }
+
+    @Test
     public void testFailWithFullCaptureHigherPriority() {
         CarInputManager carInputManager0 = createAnotherCarInputManager();
         int r = carInputManager0.requestInputEventCapture(
diff --git a/tests/carservice_unit_test/src/android/car/util/concurrent/AndroidAsyncFutureTest.java b/tests/carservice_unit_test/src/android/car/util/concurrent/AndroidAsyncFutureTest.java
new file mode 100644
index 0000000..85b8d5e
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/util/concurrent/AndroidAsyncFutureTest.java
@@ -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.
+ */
+package android.car.util.concurrent;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.android.internal.infra.AndroidFuture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
+
+public final class AndroidAsyncFutureTest {
+
+    @Mock
+    private AndroidFuture<Integer> mFuture;
+
+    private MockitoSession mMockSession;
+
+    private AndroidAsyncFuture<Integer> mAndroidAsyncFuture;
+
+    @Before
+    public void setupMocks() {
+        mMockSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        mAndroidAsyncFuture = new AndroidAsyncFuture<Integer>(mFuture);
+    }
+
+    @After
+    public void tearDown() {
+        mMockSession.finishMocking();
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        Integer input = 0;
+        when(mFuture.get()).thenReturn(input);
+
+        Integer result = mAndroidAsyncFuture.get();
+
+        assertThat(result).isEqualTo(input);
+        verify(mFuture).get();
+    }
+
+    @Test
+    public void testGetWithTimeout() throws Exception {
+        long timeout = 100;
+        TimeUnit timeUnit = TimeUnit.SECONDS;
+        Integer input = 0;
+        when(mFuture.get(timeout, timeUnit)).thenReturn(input);
+
+        Integer result = mAndroidAsyncFuture.get(timeout, timeUnit);
+
+        assertThat(result).isEqualTo(input);
+        verify(mFuture).get(timeout, timeUnit);
+    }
+
+    @Test
+    public void testWhenCompleteAsync() throws Exception {
+        Executor executor = (a) -> {};
+        BiConsumer<Integer, Throwable> biConsumer = (l, m) -> {};
+
+        AsyncFuture asyncFuture = mAndroidAsyncFuture.whenCompleteAsync(biConsumer, executor);
+
+        assertThat(asyncFuture).isEqualTo(mAndroidAsyncFuture);
+        verify(mFuture).whenCompleteAsync(biConsumer, executor);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarBugreportManagerServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarBugreportManagerServiceTest.java
new file mode 100644
index 0000000..7662bf6
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/CarBugreportManagerServiceTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.car.ICarBugreportCallback;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.ParcelFileDescriptor;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Unit tests for {@link CarBugreportManagerService}.
+ *
+ * <p>Run {@code atest CarServiceUnitTest:CarBugreportManagerServiceTest}.
+ */
+@SmallTest
+@RunWith(MockitoJUnitRunner.class)
+public class CarBugreportManagerServiceTest {
+    private static final boolean DUMPSTATE_DRY_RUN = true;
+
+    @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+    private CarBugreportManagerService mService;
+
+    @Mock private Context mMockContext;
+    @Mock private Resources mMockResources;
+    @Mock private PackageManager mMockPackageManager;
+    @Mock private ICarBugreportCallback mMockCallback;
+    @Mock private ParcelFileDescriptor mMockOutput;
+    @Mock private ParcelFileDescriptor mMockExtraOutput;
+
+    @Before
+    public void setUp() {
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+    }
+
+    @After
+    public void tearDown() {
+        if (mService != null) {
+            mService.release();
+        }
+    }
+
+    @Test
+    public void test_requestBugreport_failsIfNotDesignatedAppOnUserBuild() {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+                .thenReturn(PackageManager.SIGNATURE_MATCH);
+        when(mMockPackageManager.getNameForUid(anyInt())).thenReturn("current_app_name");
+        when(mMockResources.getString(
+                R.string.config_car_bugreport_application)).thenReturn("random_app_name");
+
+        SecurityException expected =
+                expectThrows(SecurityException.class,
+                        () -> mService.requestBugreport(mMockOutput, mMockExtraOutput,
+                                mMockCallback, DUMPSTATE_DRY_RUN));
+
+        assertThat(expected).hasMessageThat().contains(
+                "Caller current_app_name is not a designated bugreport app");
+    }
+
+    @Test
+    public void test_requestBugreport_failsIfNotSignedWithPlatformKeys() {
+        mService = new CarBugreportManagerService(mMockContext);
+        mService.init();
+        when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+                .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManager.getNameForUid(anyInt())).thenReturn("current_app_name");
+
+        SecurityException expected =
+                expectThrows(SecurityException.class,
+                        () -> mService.requestBugreport(mMockOutput, mMockExtraOutput,
+                                mMockCallback, DUMPSTATE_DRY_RUN));
+
+        assertThat(expected).hasMessageThat().contains(
+                "Caller current_app_name does not have the right signature");
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
index 21da1d6..2e90523 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
@@ -17,6 +17,7 @@
 package com.android.car;
 
 import static android.car.CarOccupantZoneManager.DisplayTypeEnum;
+import static android.car.input.CustomInputEvent.INPUT_CODE_F1;
 
 import static com.android.compatibility.common.util.SystemUtil.eventually;
 
@@ -36,6 +37,7 @@
 import static org.mockito.Mockito.ignoreStubs;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
@@ -44,6 +46,10 @@
 import android.bluetooth.BluetoothProfile;
 import android.car.CarOccupantZoneManager;
 import android.car.CarProjectionManager;
+import android.car.input.CarInputManager;
+import android.car.input.CustomInputEvent;
+import android.car.input.ICarInputCallback;
+import android.car.input.RotaryEvent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -57,7 +63,6 @@
 import android.os.UserHandle;
 import android.service.voice.VoiceInteractionSession;
 import android.telecom.TelecomManager;
-import android.view.Display;
 import android.view.KeyEvent;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -68,6 +73,7 @@
 
 import com.google.common.collect.Range;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -120,6 +126,108 @@
         when(mShouldCallButtonEndOngoingCallSupplier.getAsBoolean()).thenReturn(false);
     }
 
+    @After
+    public void tearDown() {
+        if (mCarInputService != null) {
+            mCarInputService.release();
+        }
+    }
+
+    @Test
+    public void testOnRotaryEvent_injectingRotaryNavigationEvent() {
+        RotaryEvent event = new RotaryEvent(
+                /* inputType= */ CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
+                /* clockwise= */ true,
+                /* uptimeMillisForClicks= */ new long[]{1, 1});
+        when(mCaptureController.onRotaryEvent(
+                same(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(event))).thenReturn(true);
+        when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(true);
+
+        mCarInputService.onRotaryEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+
+        // Since mCaptureController processed RotaryEvent, then no KeyEvent was generated or
+        // processed
+        verify(mCarOccupantZoneService, never()).getDisplayIdForDriver(anyInt());
+        verify(mCaptureController, never()).onKeyEvent(anyInt(), any(KeyEvent.class));
+        verify(mDefaultMainListener, never()).onKeyEvent(any(KeyEvent.class));
+    }
+
+    @Test
+    public void testOnRotaryEvent_injectingRotaryVolumeEvent() {
+        RotaryEvent event = new RotaryEvent(
+                /* inputType= */ CarInputManager.INPUT_TYPE_ROTARY_VOLUME,
+                /* clockwise= */ true,
+                /* uptimeMillisForClicks= */ new long[]{1, 1});
+        when(mCaptureController.onRotaryEvent(
+                same(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(event))).thenReturn(false);
+        when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(true);
+
+        mCarInputService.onRotaryEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+
+        // Since mCaptureController processed RotaryEvent, then KeyEvent was generated or
+        // processed
+        int numberOfGeneratedKeyEvents = 4;
+        verify(mCarOccupantZoneService, times(numberOfGeneratedKeyEvents)).getDisplayIdForDriver(
+                eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
+        verify(mCaptureController, times(numberOfGeneratedKeyEvents)).onKeyEvent(anyInt(),
+                any(KeyEvent.class));
+        verify(mDefaultMainListener, never()).onKeyEvent(any(KeyEvent.class));
+    }
+
+    @Test
+    public void testOnRotaryEvent_injectingRotaryNavigation_notConsumedByCaptureController() {
+        RotaryEvent event = new RotaryEvent(
+                /* inputType= */ CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
+                /* clockwise= */ true,
+                /* uptimeMillisForClicks= */ new long[]{1, 1});
+        when(mCaptureController.onRotaryEvent(
+                same(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(event))).thenReturn(false);
+
+        mCarInputService.onRotaryEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+
+        // Since mCaptureController processed RotaryEvent, then KeyEvent was generated or
+        // processed
+        int numberOfGeneratedKeyEvents = 4;
+        verify(mCarOccupantZoneService, times(numberOfGeneratedKeyEvents)).getDisplayIdForDriver(
+                eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
+        verify(mCaptureController, times(numberOfGeneratedKeyEvents)).onKeyEvent(anyInt(),
+                any(KeyEvent.class));
+        verify(mDefaultMainListener, times(numberOfGeneratedKeyEvents)).onKeyEvent(
+                any(KeyEvent.class));
+    }
+
+    @Test
+    public void testRequestInputEventCapture_delegatesToCaptureController() {
+        ICarInputCallback callback = mock(ICarInputCallback.class);
+        int[] inputTypes = new int[]{CarInputManager.INPUT_TYPE_CUSTOM_INPUT_EVENT};
+        int requestFlags = CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT;
+        mCarInputService.requestInputEventCapture(callback,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN, inputTypes, requestFlags);
+
+        verify(mCaptureController).requestInputEventCapture(same(callback),
+                eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(inputTypes), eq(requestFlags));
+    }
+
+    @Test
+    public void testOnCustomInputEvent_delegatesToCaptureController() {
+        CustomInputEvent event = new CustomInputEvent(INPUT_CODE_F1,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN, /* repeatCounter= */ 1);
+
+        mCarInputService.onCustomInputEvent(event);
+
+        verify(mCaptureController).onCustomInputEvent(same(event));
+    }
+
+    @Test
+    public void testReleaseInputEventCapture_delegatesToCaptureController() {
+        ICarInputCallback callback = mock(ICarInputCallback.class);
+        mCarInputService.releaseInputEventCapture(callback,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+
+        verify(mCaptureController).releaseInputEventCapture(same(callback),
+                eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
+    }
+
     @Test
     public void ensureBluetoothAdapterWasInitialized() {
         eventually(() -> verify(mBluetoothAdapter).getProfileProxy(same(mContext),
@@ -570,7 +678,6 @@
         KeyEvent event = new KeyEvent(/* downTime= */ currentTime,
                 /* eventTime= */ currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER,
                 /* repeat= */ 0);
-
         event.setDisplayId(android.view.Display.INVALID_DISPLAY);
 
         injectKeyEventAndVerify(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
@@ -585,7 +692,7 @@
         KeyEvent event = new KeyEvent(/* downTime= */ currentTime,
                 /* eventTime= */ currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER,
                 /* repeat= */ 0);
-        event.setDisplayId(android.view.Display.DEFAULT_DISPLAY);
+        event.setDisplayId(android.view.Display.INVALID_DISPLAY);
 
         injectKeyEventAndVerify(event, CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER);
 
@@ -594,20 +701,17 @@
     }
 
     private void injectKeyEventAndVerify(KeyEvent event, @DisplayTypeEnum int displayType) {
-        // Arrange
         doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(
                 android.Manifest.permission.INJECT_EVENTS);
-
         int someDisplayId = Integer.MAX_VALUE;
         when(mCarOccupantZoneService.getDisplayIdForDriver(anyInt())).thenReturn(someDisplayId);
-
         assertThat(event.getDisplayId()).isNotEqualTo(someDisplayId);
 
-        // Act
         mCarInputService.injectKeyEvent(event, displayType);
 
-        // Assert display id was updated as expected
-        assertThat(event.getDisplayId()).isEqualTo(someDisplayId);
+        verify(mCarOccupantZoneService).getDisplayIdForDriver(displayType);
+        assertWithMessage("Event's display id not updated as expected").that(
+                event.getDisplayId()).isEqualTo(someDisplayId);
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/PermissionHelperTest.java b/tests/carservice_unit_test/src/com/android/car/PermissionHelperTest.java
new file mode 100644
index 0000000..d8ff974
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/PermissionHelperTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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;
+
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.testng.Assert.expectThrows;
+
+import android.app.ActivityManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.os.Binder;
+import android.util.Log;
+
+import org.junit.Test;
+
+public final class PermissionHelperTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = PermissionHelperTest.class.getSimpleName();
+    private static final String MESSAGE = "D'OH!";
+
+    private static final int UID = Binder.getCallingUid();
+
+    private static final String PERMISSION1 = "LicenseToKill";
+    private static final String PERMISSION2 = "LicenseToLove";
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(ActivityManager.class);
+    }
+
+    @Test
+    public void testHasAtLeastOnePermission_none() {
+        mockPermission(PERMISSION1, PERMISSION_DENIED);
+        mockPermission(PERMISSION2, PERMISSION_DENIED);
+
+        assertWithMessage("has at least %s", PERMISSION2).that(
+                PermissionHelper.hasAtLeastOnePermissionGranted(UID, PERMISSION1, PERMISSION2))
+                .isFalse();
+    }
+
+    @Test
+    public void testHasAtLeastOnePermission_one() {
+        mockPermission(PERMISSION1, PERMISSION_DENIED);
+        mockPermission(PERMISSION2, PERMISSION_GRANTED);
+
+        assertWithMessage("has at least %s", PERMISSION2).that(
+                PermissionHelper.hasAtLeastOnePermissionGranted(UID, PERMISSION1, PERMISSION2))
+                .isTrue();
+    }
+
+    @Test
+    public void testHasAtLeastOnePermission_both() {
+        mockPermission(PERMISSION1, PERMISSION_GRANTED);
+        mockPermission(PERMISSION2, PERMISSION_GRANTED);
+
+        assertWithMessage("has at least %s", PERMISSION2).that(
+                PermissionHelper.hasAtLeastOnePermissionGranted(UID, PERMISSION1, PERMISSION2))
+                .isTrue();
+    }
+
+    @Test
+    public void testCheckHasAtLeastOnePermission_none() {
+        mockPermission(PERMISSION1, PERMISSION_DENIED);
+        mockPermission(PERMISSION2, PERMISSION_DENIED);
+
+        SecurityException exception = expectThrows(SecurityException.class, () -> PermissionHelper
+                .checkHasAtLeastOnePermissionGranted(MESSAGE, PERMISSION1, PERMISSION2));
+
+        assertExceptionMessageContains(exception, MESSAGE);
+    }
+
+    @Test
+    public void testCheckHasAtLeastOnePermissionGranted_one() {
+        mockPermission(PERMISSION1, PERMISSION_DENIED);
+        mockPermission(PERMISSION2, PERMISSION_GRANTED);
+
+        PermissionHelper.checkHasAtLeastOnePermissionGranted(MESSAGE, PERMISSION1, PERMISSION2);
+    }
+
+    @Test
+    public void testCheckHasAtLeastOnePermissionGranted_both() {
+        mockPermission(PERMISSION1, PERMISSION_DENIED);
+        mockPermission(PERMISSION2, PERMISSION_GRANTED);
+
+        PermissionHelper.checkHasAtLeastOnePermissionGranted(MESSAGE, PERMISSION1, PERMISSION2);
+    }
+
+    @Test
+    public void testCheckHasDumpPermissionGranted_notGranted() {
+        mockPermission(android.Manifest.permission.DUMP, PERMISSION_DENIED);
+
+        SecurityException exception = expectThrows(SecurityException.class,
+                () -> PermissionHelper.checkHasDumpPermissionGranted(MESSAGE));
+
+        assertExceptionMessageContains(exception, MESSAGE);
+        assertExceptionMessageContains(exception, android.Manifest.permission.DUMP);
+    }
+
+    @Test
+    public void testCheckHasDumpPermissionGranted_granted() {
+        mockPermission(android.Manifest.permission.DUMP, PERMISSION_GRANTED);
+
+        PermissionHelper.checkHasDumpPermissionGranted(MESSAGE);
+    }
+
+    private void assertExceptionMessageContains(Exception exception, String subString) {
+        assertWithMessage("exception (%s) message", exception).that(exception.getMessage())
+                .contains(subString);
+    }
+
+    private void mockPermission(String permission, int value) {
+        Log.d(TAG, "mockHasPermissions(): uid=" + UID + ", permission=" + permission
+                + ", granted=" + (value == PERMISSION_GRANTED));
+
+        doReturn(value).when(() -> ActivityManager.checkComponentPermission(eq(permission),
+                eq(UID), anyInt(), anyBoolean()));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/SparseArrayStreamTest.java b/tests/carservice_unit_test/src/com/android/car/SparseArrayStreamTest.java
new file mode 100644
index 0000000..3016027
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/SparseArrayStreamTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.util.stream.Collectors.toList;
+
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+
+import java.util.List;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public final class SparseArrayStreamTest {
+
+    @Test
+    public void testKeyStream() {
+        SparseArray<String> array = createSparseStringArray();
+        ImmutableList<Integer> expected = ImmutableList.of(5, 20, 1000);
+
+        IntStream actual = SparseArrayStream.keyStream(array);
+
+        assertContainsExactlyInOrder(actual.boxed(), expected);
+    }
+
+    @Test
+    public void testKeyStream_empty() {
+        assertContainsExactlyInOrder(
+                SparseArrayStream.keyStream(new SparseArray<String>()).boxed(), ImmutableList.of());
+    }
+
+    @Test
+    public void testValueStream() {
+        SparseArray<String> array = createSparseStringArray();
+        ImmutableList<String> expected = ImmutableList.of("five", "twenty", "thousand");
+
+        Stream<String> actual = SparseArrayStream.valueStream(array);
+
+        assertContainsExactlyInOrder(actual, expected);
+    }
+
+    @Test
+    public void testValueStream_empty() {
+        assertContainsExactlyInOrder(
+                SparseArrayStream.valueStream(new SparseArray<String>()), ImmutableList.of());
+    }
+
+    @Test
+    public void testPairStream() {
+        SparseArray<String> array = createSparseStringArray();
+        ImmutableList<Pair<Integer, String>> expected = ImmutableList.of(
+                new Pair<>(5, "five"), new Pair<>(20, "twenty"), new Pair<>(1000, "thousand"));
+
+        Stream<Pair<Integer, String>> actual = SparseArrayStream.pairStream(array);
+
+        assertContainsExactlyInOrder(actual, expected);
+    }
+
+    @Test
+    public void testPairStream_empty() {
+        assertContainsExactlyInOrder(
+                SparseArrayStream.pairStream(new SparseArray<String>()), ImmutableList.of());
+    }
+
+    private static SparseArray<String> createSparseStringArray() {
+        SparseArray<String> array = new SparseArray<>();
+        array.put(5, "five");
+        array.put(20, "twenty");
+        array.put(1000, "thousand");
+
+        return array;
+    }
+
+    private static <T> void assertContainsExactlyInOrder(Stream<T> actual, List<T> expected) {
+        // TODO: Use Truth8 StreamSubject when it becomes available.
+        assertThat(actual.collect(toList())).containsExactlyElementsIn(expected).inOrder();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsGetAdapterStateNameTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsGetAdapterStateNameTest.java
new file mode 100644
index 0000000..c536e9a
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/UtilsGetAdapterStateNameTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothAdapter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UtilsGetAdapterStateNameTest {
+
+    private final int mState;
+    private final String mName;
+
+    public UtilsGetAdapterStateNameTest(int state, String name) {
+        mState = state;
+        mName = name;
+    }
+
+    @Test
+    public void testGetAdapterStateName() {
+        String result = Utils.getAdapterStateName(mState);
+
+        assertThat(result).contains(String.valueOf(mState));
+        assertThat(result).ignoringCase().contains(mName);
+    }
+
+    @Parameterized.Parameters
+    public static Collection provideParams() {
+        return Arrays.asList(
+            new Object[][] {
+                {BluetoothAdapter.STATE_ON, "on"},
+                {BluetoothAdapter.STATE_OFF, "off"},
+                {BluetoothAdapter.STATE_TURNING_ON, "turning on"},
+                {BluetoothAdapter.STATE_TURNING_OFF, "turning off"},
+                {9, "unknown"},
+                {14, "unknown"}
+            });
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsGetBondStateNameTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsGetBondStateNameTest.java
new file mode 100644
index 0000000..9a89e59
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/UtilsGetBondStateNameTest.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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothDevice;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UtilsGetBondStateNameTest {
+
+    private final int mState;
+    private final String mName;
+
+    public UtilsGetBondStateNameTest(int state, String name) {
+        mState = state;
+        mName = name;
+    }
+
+    @Test
+    public void testGetBondStateName() {
+        String result = Utils.getBondStateName(mState);
+
+        assertThat(result).contains(String.valueOf(mState));
+        assertThat(result).ignoringCase().contains(mName);
+    }
+
+    @Parameterized.Parameters
+    public static Collection provideParams() {
+        return Arrays.asList(
+            new Object[][] {
+                {BluetoothDevice.BOND_BONDED, "bonded"},
+                {BluetoothDevice.BOND_BONDING, "bonding"},
+                {BluetoothDevice.BOND_NONE, "unbonded"},
+                {9, "unknown"},
+                {13, "unknown"}
+            });
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsGetConnectionStateNameTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsGetConnectionStateNameTest.java
new file mode 100644
index 0000000..74bfffb
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/UtilsGetConnectionStateNameTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothAdapter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UtilsGetConnectionStateNameTest {
+
+    private final int mState;
+    private final String mName;
+
+    public UtilsGetConnectionStateNameTest(int state, String name) {
+        mState = state;
+        mName = name;
+    }
+
+    @Test
+    public void testGetConnectionStateName() {
+        String result = Utils.getConnectionStateName(mState);
+
+        assertThat(result).contains(String.valueOf(mState));
+        assertThat(result).ignoringCase().contains(mName);
+    }
+
+    @Parameterized.Parameters
+    public static Collection provideParams() {
+        return Arrays.asList(
+            new Object[][] {
+                {BluetoothAdapter.STATE_CONNECTED, "connected"},
+                {BluetoothAdapter.STATE_DISCONNECTED, "disconnected"},
+                {BluetoothAdapter.STATE_CONNECTING, "connecting"},
+                {BluetoothAdapter.STATE_DISCONNECTING, "disconnecting"},
+                {-1, "unknown"},
+                {4, "unknown"}
+            });
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsGetProfileNameTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsGetProfileNameTest.java
new file mode 100644
index 0000000..54220b3
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/UtilsGetProfileNameTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothProfile;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UtilsGetProfileNameTest {
+
+    private final int mProfile;
+    private final String mName;
+
+    public UtilsGetProfileNameTest(int profile, String name) {
+        mProfile = profile;
+        mName = name;
+    }
+
+    @Test
+    public void testGetProfileName() {
+        String result = Utils.getProfileName(mProfile);
+
+        assertThat(result).contains(String.valueOf(mProfile));
+        assertThat(result).ignoringCase().contains(mName);
+    }
+
+    @Parameterized.Parameters
+    public static Collection provideParams() {
+        return Arrays.asList(
+            new Object[][] {
+                {BluetoothProfile.HEADSET, "HFP Server"},
+                {BluetoothProfile.A2DP, "A2DP Source"},
+                {BluetoothProfile.HEALTH, "HDP"},
+                {BluetoothProfile.HID_HOST, "HID Host"},
+                {BluetoothProfile.PAN, "PAN"},
+                {BluetoothProfile.PBAP, "PBAP Server"},
+                {BluetoothProfile.GATT, "GATT Client"},
+                {BluetoothProfile.GATT_SERVER, "GATT Server"},
+                {BluetoothProfile.MAP, "MAP Server"},
+                {BluetoothProfile.SAP, "SAP"},
+                {BluetoothProfile.A2DP_SINK, "A2DP Sink"},
+                {BluetoothProfile.AVRCP_CONTROLLER, "AVRCP Controller"},
+                {BluetoothProfile.AVRCP, "AVRCP Target"},
+                {BluetoothProfile.HEADSET_CLIENT, "HFP Client"},
+                {BluetoothProfile.PBAP_CLIENT, "PBAP Client"},
+                {BluetoothProfile.MAP_CLIENT, "MAP Client"},
+                {BluetoothProfile.HID_DEVICE, "HID Device"},
+                {BluetoothProfile.OPP, "OPP"},
+                {BluetoothProfile.HEARING_AID, "Hearing Aid"},
+                {0, "unknown"},
+                {22, "unknown"}
+            });
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsGetProfilePriorityNameTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsGetProfilePriorityNameTest.java
new file mode 100644
index 0000000..4ed8175
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/UtilsGetProfilePriorityNameTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothProfile;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UtilsGetProfilePriorityNameTest {
+
+    private final int mPriority;
+    private final String mName;
+
+    public UtilsGetProfilePriorityNameTest(int priority, String name) {
+        mPriority = priority;
+        mName = name;
+    }
+
+    @Test
+    public void testGetProfilePriorityName() {
+        String result = Utils.getProfilePriorityName(mPriority);
+
+        assertThat(result).contains(String.valueOf(mPriority));
+        assertThat(result).ignoringCase().contains(mName);
+    }
+
+    @Parameterized.Parameters
+    public static Collection provideParams() {
+        return Arrays.asList(
+            new Object[][] {
+                // Any value >= PRIORITY_AUTO_CONNECT maps to "PRIORITY_AUTO_CONNECT".
+                {1001, "PRIORITY_AUTO_CONNECT"},
+                {BluetoothProfile.PRIORITY_AUTO_CONNECT, "PRIORITY_AUTO_CONNECT"},
+                // PRIORITY_AUTO_CONNECT > value >= PRIORITY_ON maps to "PRIORITY_ON".
+                {999, "PRIORITY_ON"},
+                {BluetoothProfile.PRIORITY_ON, "PRIORITY_ON"},
+                // PRIORITY_ON > value >= PRIORITY_OFF mpas to "PRIORITY_OFF".
+                {99, "PRIORITY_OFF"},
+                {BluetoothProfile.PRIORITY_OFF, "PRIORITY_OFF"},
+                // value < PRIORITY_OFF maps to "PRIORITY_UNDEFINED".
+                {BluetoothProfile.PRIORITY_UNDEFINED, "PRIORITY_UNDEFINED"},
+                {-2, "PRIORITY_UNDEFINED"}
+            });
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsTest.java
new file mode 100644
index 0000000..16285b4
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/UtilsTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
+import android.text.TextUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.UUID;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class UtilsTest {
+
+    @Mock
+    private BluetoothDevice mMockBluetoothDevice;
+
+    @Test
+    public void testGetDeviceDebugInfo() {
+        when(mMockBluetoothDevice.getName()).thenReturn("deviceName");
+        when(mMockBluetoothDevice.getAddress()).thenReturn("deviceAddress");
+
+        assertThat(Utils.getDeviceDebugInfo(mMockBluetoothDevice))
+            .isEqualTo("(name = deviceName, addr = deviceAddress)");
+    }
+
+    @Test
+    public void testGetDeviceDebugInfo_nullDevice() {
+        assertThat(Utils.getDeviceDebugInfo(null)).isEqualTo("(null)");
+    }
+
+    @Test
+    public void testTransitionLogToString() {
+        Utils.TransitionLog transitionLog =
+                new Utils.TransitionLog("serviceName", "state1", "state2", 1623777864000L);
+        String result = transitionLog.toString();
+
+        assertThat(result).startsWith("06-15 17:24:24");
+        assertThat(result).contains("serviceName:");
+        assertThat(result).contains("from state1 to state2");
+    }
+
+    @Test
+    public void testTransitionLogToString_withExtra() {
+        Utils.TransitionLog transitionLog =
+                new Utils.TransitionLog("serviceName", "state1", "state2", 1623777864000L, "extra");
+        String result = transitionLog.toString();
+
+        assertThat(result).startsWith("06-15 17:24:24");
+        assertThat(result).contains("serviceName:");
+        assertThat(result).contains("extra");
+        assertThat(result).contains("from state1 to state2");
+    }
+
+    @Test
+    public void testLongToBytes() {
+        long longValue = 1234567890L;
+        byte[] expected = new byte[] {0, 0, 0, 0, 73, -106, 2, -46};
+
+        assertThat(Utils.longToBytes(longValue)).isEqualTo(expected);
+    }
+
+    @Test
+    public void testBytesToLong() {
+        byte[] bytes = new byte[] {0, 0, 0, 0, 73, -106, 2, -46};
+        long expected = 1234567890L;
+
+        assertThat(Utils.bytesToLong(bytes)).isEqualTo(expected);
+    }
+
+    @Test
+    public void testByteArrayToHexString() {
+        assertThat(Utils.byteArrayToHexString(new byte[] {0, 1, 2, -3})).isEqualTo("000102fd");
+    }
+
+    @Test
+    public void testUuidToBytes() {
+        UUID uuid = new UUID(123456789L, 987654321L);
+        byte[] expected = new byte[] {0, 0, 0, 0, 7, 91, -51, 21, 0, 0, 0, 0, 58, -34, 104, -79};
+
+        assertThat(Utils.uuidToBytes(uuid)).isEqualTo(expected);
+    }
+
+    @Test
+    public void testBytesToUUID() {
+        byte[] bytes = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, -9, -8, -7, -6, -5, -4, -3};
+        UUID expected = new UUID(72623859790382856L, 718316418130246909L);
+
+        assertThat(Utils.bytesToUUID(bytes).getLeastSignificantBits())
+                .isEqualTo(718316418130246909L);
+        assertThat(Utils.bytesToUUID(bytes).getMostSignificantBits()).isEqualTo(72623859790382856L);
+        assertThat(Utils.bytesToUUID(bytes)).isEqualTo(expected);
+    }
+
+    @Test
+    public void testBytesToUUID_invalidLength() {
+        byte[] bytes = new byte[] {0};
+
+        assertThat(Utils.bytesToUUID(bytes)).isNull();
+    }
+
+    @Test
+    public void testGenerateRandomNumberString() {
+        String result = Utils.generateRandomNumberString(25);
+
+        assertThat(result).hasLength(25);
+        assertThat(TextUtils.isDigitsOnly(result)).isTrue();
+    }
+
+    @Test
+    public void testConcatByteArrays() {
+        byte[] bytes1 = new byte[] {1, 2, 3};
+        byte[] bytes2 = new byte[] {4, 5, 6};
+        Byte[] expected = new Byte[] {1, 2, 3, 4, 5, 6};
+
+        assertThat(Utils.concatByteArrays(bytes1, bytes2)).asList()
+                .containsExactlyElementsIn(expected).inOrder();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/NewUserDisclaimerActivityTest.java b/tests/carservice_unit_test/src/com/android/car/admin/NewUserDisclaimerActivityTest.java
new file mode 100644
index 0000000..b1e8b72
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/admin/NewUserDisclaimerActivityTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.admin;
+
+import static android.app.Notification.EXTRA_TEXT;
+import static android.app.Notification.EXTRA_TITLE;
+import static android.app.Notification.FLAG_ONGOING_EVENT;
+
+import static com.android.car.admin.NotificationHelper.CHANNEL_ID_DEFAULT;
+import static com.android.car.admin.NotificationHelper.NEW_USER_DISCLAIMER_NOTIFICATION_ID;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.UiAutomation;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import android.widget.Button;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.car.R;
+import com.android.car.admin.ui.ManagedDeviceTextView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.util.concurrent.CountDownLatch;
+
+@RunWith(AndroidJUnit4.class)
+public final class NewUserDisclaimerActivityTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = NewUserDisclaimerActivityTest.class.getSimpleName();
+
+    private static final long TIMEOUT_MS = 1_000;
+
+    private final Context mRealContext = InstrumentationRegistry.getInstrumentation()
+            .getContext();
+
+    private final UiAutomation mUiAutomation =
+            InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+    // NOTE: Cannot launch activity automatically as we need to mock
+    // PerUserCarDevicePolicyService.getInstance() first
+    @Rule
+    public ActivityTestRule<NewUserDisclaimerActivity> mActivityRule = new ActivityTestRule(
+            NewUserDisclaimerActivity.class,  /* initialTouchMode= */ false,
+            /* launchActivity= */ false);
+
+    private NewUserDisclaimerActivity mActivity;
+
+    private Context mSpiedContext;
+
+    @Mock
+    private PerUserCarDevicePolicyService mService;
+
+    @Mock
+    private NotificationManager mNotificationManager;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(PerUserCarDevicePolicyService.class);
+    }
+
+    @Before
+    public void setFixtures() {
+        Log.v(TAG, "setFixtures(): mocking PerUserCarDevicePolicyService.getInstance()");
+        doReturn(mService).when(() -> PerUserCarDevicePolicyService.getInstance(any()));
+        mSpiedContext = spy(mRealContext);
+
+        when(mSpiedContext.getSystemService(NotificationManager.class))
+                .thenReturn(mNotificationManager);
+
+        Log.v(TAG, "setFixtures(): launching activitiy");
+        mActivity = mActivityRule.launchActivity(/* intent= */ null);
+
+        // It's called onResume()
+        verify(mService).setShown();
+    }
+
+    @Test
+    public void testAccept() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        mActivity.runOnUiThread(() -> {
+            mActivity.onCreate(/* savedInstanceState= */ null);
+            Button button = mActivity.getAcceptButton();
+            Log.d(TAG, "Clicking accept button: " + button);
+            button.performClick();
+            latch.countDown();
+        });
+        JavaMockitoHelper.await(latch, TIMEOUT_MS);
+
+        verify(mService).setAcknowledged();
+        assertWithMessage("activity is finishing").that(mActivity.isFinishing()).isTrue();
+    }
+
+    @Test
+    public void testShowNotification() {
+        NewUserDisclaimerActivity.showNotification(mSpiedContext);
+
+        ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
+        verify(mNotificationManager).notify(eq(NEW_USER_DISCLAIMER_NOTIFICATION_ID),
+                captor.capture());
+
+        Notification notification = captor.getValue();
+        assertWithMessage("notification").that(notification).isNotNull();
+        assertNotificationContents(notification);
+    }
+
+    @Test
+    public void testCancelNotification() throws Exception {
+        PendingIntent pendingIntent = NewUserDisclaimerActivity.getPendingIntent(mSpiedContext,
+                /* extraFlags = */ 0);
+        CountDownLatch cancelLatch = new CountDownLatch(1);
+        pendingIntent.registerCancelListener(pi -> cancelLatch.countDown());
+
+        NewUserDisclaimerActivity.cancelNotification(mSpiedContext);
+
+        verify(mNotificationManager).cancel(NEW_USER_DISCLAIMER_NOTIFICATION_ID);
+
+        // Assert pending intent was canceled (latch is counted down by the CancelListener)
+        JavaMockitoHelper.await(cancelLatch, TIMEOUT_MS);
+    }
+
+    private void assertNotificationContents(Notification notification) {
+        assertWithMessage("notification icon").that(notification.getSmallIcon()).isNotNull();
+        assertWithMessage("notification channel").that(notification.getChannelId())
+                .isEqualTo(CHANNEL_ID_DEFAULT);
+        assertWithMessage("notification flags has FLAG_ONGOING_EVENT")
+                .that(notification.flags & FLAG_ONGOING_EVENT).isEqualTo(FLAG_ONGOING_EVENT);
+
+        assertWithMessage("notification content pending intent")
+                .that(notification.contentIntent)
+                .isNotNull();
+        assertWithMessage("notification content pending intent is immutable")
+                .that(notification.contentIntent.isImmutable()).isTrue();
+        // Need android.permission.GET_INTENT_SENDER_INTENT to get the Intent
+        Intent intent;
+        mUiAutomation.adoptShellPermissionIdentity();
+        try {
+            intent = notification.contentIntent.getIntent();
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+        assertWithMessage("content intent").that(intent).isNotNull();
+        assertWithMessage("content intent component").that(intent.getComponent())
+                .isEqualTo(mActivity.getComponentName());
+
+        assertWithMessage("notification extras").that(notification.extras).isNotNull();
+        assertWithMessage("value of extra %s", EXTRA_TITLE)
+                .that(notification.extras.getString(EXTRA_TITLE))
+                .isEqualTo(mRealContext.getString(R.string.new_user_managed_notification_title));
+        assertWithMessage("value of extra %s", EXTRA_TEXT)
+                .that(notification.extras.getString(EXTRA_TEXT))
+                .isEqualTo(ManagedDeviceTextView.getManagedDeviceText(mRealContext));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
index c4c481f..8610265 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
@@ -30,7 +30,6 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
-
 @RunWith(MockitoJUnitRunner.class)
 public final class NotificationHelperTest {
 
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperValidImportanceTest.java b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperValidImportanceTest.java
index daefcaf..7997954 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperValidImportanceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperValidImportanceTest.java
@@ -62,7 +62,7 @@
     @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
-    private Context mRealContext = InstrumentationRegistry.getInstrumentation().getContext();
+    private final Context mRealContext = InstrumentationRegistry.getInstrumentation().getContext();
 
     private Context mSpiedContext;
 
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/PerUserCarDevicePolicyServiceTest.java b/tests/carservice_unit_test/src/com/android/car/admin/PerUserCarDevicePolicyServiceTest.java
new file mode 100644
index 0000000..796afd5
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/admin/PerUserCarDevicePolicyServiceTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.admin;
+
+import static android.app.admin.DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER;
+
+import static com.android.car.admin.PerUserCarDevicePolicyService.NEW_USER_DISCLAIMER_STATUS_ACKED;
+import static com.android.car.admin.PerUserCarDevicePolicyService.NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED;
+import static com.android.car.admin.PerUserCarDevicePolicyService.NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT;
+import static com.android.car.admin.PerUserCarDevicePolicyService.NEW_USER_DISCLAIMER_STATUS_RECEIVED;
+import static com.android.car.admin.PerUserCarDevicePolicyService.NEW_USER_DISCLAIMER_STATUS_SHOWN;
+import static com.android.car.admin.PerUserCarDevicePolicyService.newUserDisclaimerStatusToString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.app.admin.DevicePolicyManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.car.admin.PerUserCarDevicePolicyService.NewUserDisclaimerStatus;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+public final class PerUserCarDevicePolicyServiceTest extends AbstractExtendedMockitoTestCase {
+
+    @Mock
+    private Context mContext;
+
+    private PerUserCarDevicePolicyService mInstance;
+
+    @Mock
+    private DevicePolicyManager mDpm;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(NewUserDisclaimerActivity.class);
+    }
+
+    @Before
+    public void setFixtures() {
+        when(mContext.getApplicationContext()).thenReturn(mContext);
+        when(mContext.getSystemService(DevicePolicyManager.class)).thenReturn(mDpm);
+
+        mInstance = new PerUserCarDevicePolicyService(mContext);
+        assertStatusString(NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED);
+    }
+
+    @Test
+    public void testGetInstance() {
+        PerUserCarDevicePolicyService instance1 = PerUserCarDevicePolicyService
+                .getInstance(mContext);
+        assertWithMessage("getInstance()#1").that(instance1).isNotNull();
+        assertWithMessage("getInstance()#1").that(instance1).isNotSameInstanceAs(mInstance);
+
+        PerUserCarDevicePolicyService instance2 = PerUserCarDevicePolicyService
+                .getInstance(mContext);
+        assertWithMessage("getInstance()#2").that(instance2).isNotNull();
+        assertWithMessage("getInstance()#2").that(instance2).isNotSameInstanceAs(mInstance);
+
+        assertWithMessage("getInstance()#2").that(instance2).isSameInstanceAs(instance1);
+        assertWithMessage("getInstance()#1").that(instance1).isSameInstanceAs(instance2);
+    }
+
+    @Test
+    public void testGetInstance_nullContext() {
+        NullPointerException exception = expectThrows(NullPointerException.class,
+                () -> PerUserCarDevicePolicyService.getInstance(null));
+        assertWithMessage("exception message").that(exception.getMessage()).contains("context");
+    }
+
+    @Test
+    public void testCreateAndDestroy() {
+        BroadcastReceiver receiver = callOnCreate();
+
+        callOnDestroy(receiver);
+    }
+
+    @Test
+    public void testShowWhenIntentReceived() {
+        doAnswer((inv) -> {
+            assertStatusString(NEW_USER_DISCLAIMER_STATUS_RECEIVED);
+            return null;
+        }).when(() -> NewUserDisclaimerActivity.showNotification(any()));
+        BroadcastReceiver receiver  = callOnCreate();
+
+        sendShowNewUserDisclaimerBroadcast(receiver);
+
+        assertStatusString(NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT);
+        verify(() -> NewUserDisclaimerActivity.showNotification(mContext));
+    }
+
+    @Test
+    public void testSetShown() {
+        mInstance.setShown();
+
+        assertStatusString(NEW_USER_DISCLAIMER_STATUS_SHOWN);
+    }
+
+    @Test
+    public void testSetAcknowledged() {
+        doNothing().when(() -> NewUserDisclaimerActivity.cancelNotification(any()));
+
+        mInstance.setAcknowledged();
+
+        assertStatusString(NEW_USER_DISCLAIMER_STATUS_ACKED);
+        verify(() -> NewUserDisclaimerActivity.cancelNotification(mContext));
+
+        verify(mDpm).resetNewUserDisclaimer();
+    }
+
+    private BroadcastReceiver callOnCreate() {
+        ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+        mInstance.onCreate();
+
+        verify(mContext).registerReceiver(captor.capture(), any());
+        BroadcastReceiver receiver = captor.getValue();
+        assertWithMessage("BroadcastReceiver captured on onCreate()").that(receiver).isNotNull();
+
+        return receiver;
+    }
+
+    private void callOnDestroy(BroadcastReceiver receiver) {
+        mInstance.onDestroy();
+
+        verify(mContext).unregisterReceiver(receiver);
+    }
+
+    private void sendShowNewUserDisclaimerBroadcast(BroadcastReceiver receiver) {
+        receiver.onReceive(mContext, new Intent(ACTION_SHOW_NEW_USER_DISCLAIMER));
+    }
+
+    private void assertStatusString(@NewUserDisclaimerStatus int expectedStatus) {
+        int actualStatus = mInstance.getNewUserDisclaimerStatus();
+        assertWithMessage("newUserDisclaimerStatus (%s=%s, %s=%s)",
+                expectedStatus, newUserDisclaimerStatusToString(expectedStatus),
+                actualStatus, newUserDisclaimerStatusToString(actualStatus))
+                        .that(actualStatus).isEqualTo(expectedStatus);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceIdsTest.java b/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceIdsTest.java
index e128b19..814ccba 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceIdsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceIdsTest.java
@@ -16,6 +16,9 @@
 
 package com.android.car.hal;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import android.car.Car;
 import android.car.VehicleHvacFanDirection;
 import android.car.VehiclePropertyIds;
@@ -29,10 +32,9 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.car.internal.PropertyPermissionMapping;
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 
-import com.google.common.truth.Truth;
-
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -50,7 +52,7 @@
     public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     private PropertyHalServiceIds mPropertyHalServiceIds;
-
+    private PropertyPermissionMapping mPermissionMapping;
     private static final String TAG = PropertyHalServiceIdsTest.class.getSimpleName();
     private static final int VENDOR_PROPERTY_1 = 0x21e01111;
     private static final int VENDOR_PROPERTY_2 = 0x21e01112;
@@ -92,6 +94,7 @@
     @Before
     public void setUp() {
         mPropertyHalServiceIds = new PropertyHalServiceIds();
+        mPermissionMapping = new PropertyPermissionMapping();
         // set up read permission and write permission to VENDOR_PROPERTY_1
         CONFIG_ARRAY.add(VENDOR_PROPERTY_1);
         CONFIG_ARRAY.add(VehicleVendorPermission.PERMISSION_DEFAULT);
@@ -117,14 +120,18 @@
      */
     @Test
     public void checkPermissionForSystemProperty() {
-        Assert.assertEquals(Car.PERMISSION_CAR_ENGINE_DETAILED,
-                mPropertyHalServiceIds.getReadPermission(VehiclePropertyIds.ENGINE_OIL_LEVEL));
-        Assert.assertNull(
-                mPropertyHalServiceIds.getWritePermission(VehiclePropertyIds.ENGINE_OIL_LEVEL));
-        Assert.assertEquals(Car.PERMISSION_CONTROL_CAR_CLIMATE,
-                mPropertyHalServiceIds.getReadPermission(VehiclePropertyIds.HVAC_FAN_SPEED));
-        Assert.assertEquals(Car.PERMISSION_CONTROL_CAR_CLIMATE,
-                mPropertyHalServiceIds.getWritePermission(VehiclePropertyIds.HVAC_FAN_SPEED));
+        assertThat(mPropertyHalServiceIds.getReadPermission(VehiclePropertyIds.ENGINE_OIL_LEVEL))
+                .isEqualTo(Car.PERMISSION_CAR_ENGINE_DETAILED);
+        assertThat(mPropertyHalServiceIds.getWritePermission(VehiclePropertyIds.ENGINE_OIL_LEVEL))
+                .isNull();
+        assertThat(mPropertyHalServiceIds.getReadPermission(VehiclePropertyIds.HVAC_FAN_SPEED))
+                .isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE);
+        assertThat(mPropertyHalServiceIds.getWritePermission(VehiclePropertyIds.HVAC_FAN_SPEED))
+                .isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE);
+        assertThat(mPermissionMapping.getReadPermission(VehiclePropertyIds.HVAC_FAN_SPEED))
+                .isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE);
+        assertThat(mPermissionMapping.getWritePermission(VehiclePropertyIds.HVAC_FAN_SPEED))
+                .isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE);
     }
     /**
      * Test {@link PropertyHalServiceIds#customizeVendorPermission(List)}
@@ -133,28 +140,31 @@
     public void checkPermissionForVendorProperty() {
         // test insert a valid config
         mPropertyHalServiceIds.customizeVendorPermission(CONFIG_ARRAY);
+        assertThat(mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_1))
+                .isEqualTo(Car.PERMISSION_VENDOR_EXTENSION);
+        assertThat(mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_1)).isNull();
 
-        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
-                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_1));
-        Assert.assertNull(mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_1));
+        assertThat(mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_2))
+                .isEqualTo(android.car.hardware.property
+                        .VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE);
+        assertThat(mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_2))
+                .isEqualTo(android.car.hardware.property
+                        .VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE);
 
-        Assert.assertEquals(android.car.hardware.property
-                        .VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE,
-                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_2));
-        Assert.assertEquals(android.car.hardware.property
-                        .VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE,
-                mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_2));
+        assertThat(mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_3))
+                .isEqualTo(android.car.hardware.property
+                        .VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO);
+        assertThat(mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_3))
+                .isEqualTo(Car.PERMISSION_VENDOR_EXTENSION);
 
-        Assert.assertEquals(android.car.hardware.property
-                        .VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO,
-                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_3));
-        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
-                mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_3));
-
-        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
-                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_4));
-        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
-                mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_4));
+        assertThat(mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_4))
+                .isEqualTo(Car.PERMISSION_VENDOR_EXTENSION);
+        assertThat(mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_4))
+                .isEqualTo(Car.PERMISSION_VENDOR_EXTENSION);
+        assertThat(mPermissionMapping.getReadPermission(VENDOR_PROPERTY_4))
+                .isEqualTo(Car.PERMISSION_VENDOR_EXTENSION);
+        assertThat(mPermissionMapping.getWritePermission(VENDOR_PROPERTY_4))
+                .isEqualTo(Car.PERMISSION_VENDOR_EXTENSION);
 
         // test insert invalid config
         try {
@@ -171,10 +181,12 @@
     @Test
     public void checkVendorPropertyId() {
         for (int vendorProp : VENDOR_PROPERTY_IDS) {
-            Assert.assertTrue(mPropertyHalServiceIds.isSupportedProperty(vendorProp));
+            assertWithMessage("Property does not exist.").that(
+                    mPropertyHalServiceIds.isSupportedProperty(vendorProp)).isTrue();
         }
         for (int systemProp : SYSTEM_PROPERTY_IDS) {
-            Assert.assertTrue(mPropertyHalServiceIds.isSupportedProperty(systemProp));
+            assertWithMessage("Property does not exist.").that(
+                    mPropertyHalServiceIds.isSupportedProperty(systemProp)).isTrue();
         }
     }
 
@@ -183,14 +195,11 @@
      */
     @Test
     public void testPayload() {
-        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_VALID_VALUE)).isTrue();
-        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_EXTRA_VALUE)).isFalse();
-        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_INVALID_VALUE)).isFalse();
-        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_INVALID_TYPE_VALUE))
-                .isFalse();
-
-        Truth.assertThat(mPropertyHalServiceIds.checkPayload(HVAC_FAN_DIRECTIONS_VALID)).isTrue();
-        Truth.assertThat(mPropertyHalServiceIds.checkPayload(HVAC_FAN_DIRECTIONS_INVALID))
-                .isFalse();
+        assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_VALID_VALUE)).isTrue();
+        assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_EXTRA_VALUE)).isFalse();
+        assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_INVALID_VALUE)).isFalse();
+        assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_INVALID_TYPE_VALUE)).isFalse();
+        assertThat(mPropertyHalServiceIds.checkPayload(HVAC_FAN_DIRECTIONS_VALID)).isTrue();
+        assertThat(mPropertyHalServiceIds.checkPayload(HVAC_FAN_DIRECTIONS_INVALID)).isFalse();
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
index 6384d69..1ad6b7e 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
@@ -560,6 +560,29 @@
         assertThat(listenerAudio.getCurrentPowerPolicy()).isNull();
     }
 
+    /**
+     * This test case increases the code coverage to cover methods
+     * {@code describeContents()} and {@code newArray()}. They are public APIs
+     * can not be marked out as BOILERPLATE_CODE.
+     */
+    @Test
+    public void testParcelableCreation() throws Exception {
+        grantPowerPolicyPermission();
+
+        CarPowerPolicy policy = mService.getCurrentPowerPolicy();
+        assertThat(policy.describeContents()).isEqualTo(0);
+
+        CarPowerPolicy[] policies = CarPowerPolicy.CREATOR.newArray(1);
+        assertThat(policies.length).isEqualTo(1);
+
+        CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
+                .setComponents(PowerComponent.AUDIO).build();
+        assertThat(filterAudio.describeContents()).isEqualTo(0);
+
+        CarPowerPolicyFilter[] filters = CarPowerPolicyFilter.CREATOR.newArray(1);
+        assertThat(filters.length).isEqualTo(1);
+    }
+
     private void suspendAndResume() throws Exception {
         Log.d(TAG, "suspend()");
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
index a8b1362..1828c01 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
@@ -40,6 +40,7 @@
 import android.car.watchdog.ICarWatchdogService;
 import android.car.watchdog.ICarWatchdogServiceCallback;
 import android.car.watchdog.IResourceOveruseListener;
+import android.car.watchdog.IoOveruseAlertThreshold;
 import android.car.watchdog.IoOveruseConfiguration;
 import android.car.watchdog.IoOveruseStats;
 import android.car.watchdog.PackageKillableState;
@@ -68,6 +69,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -476,6 +478,80 @@
                 .isEqualTo(null);
     }
 
+    @Test
+    public void testIoOveruseAlertThresholdToStringAndDescribeContent() {
+        IoOveruseAlertThreshold ioOveruseAlertThreshold = new IoOveruseAlertThreshold(1, 2);
+        int content = ioOveruseAlertThreshold.describeContents();
+        String string = ioOveruseAlertThreshold.toString();
+
+        assertThat(content).isEqualTo(0);
+        assertThat(string).isEqualTo(
+                "IoOveruseAlertThreshold { durationInSeconds = 1, writtenBytesPerSecond = 2 }");
+    }
+
+    @Test
+    public void testIoOveruseConfigurationToStringAndDescribeContent() {
+        PerStateBytes expectedPerStateBytes = new PerStateBytes(6666666, 7777777, 8888888);
+        IoOveruseConfiguration ioOveruseConfiguration = new IoOveruseConfiguration.Builder(
+                expectedPerStateBytes,
+                new HashMap<>(), new HashMap<>(), new ArrayList<>()).build();
+        int content = ioOveruseConfiguration.describeContents();
+        String string = ioOveruseConfiguration.toString();
+
+        assertThat(content).isEqualTo(0);
+        assertThat(string)
+                .isEqualTo("IoOveruseConfiguration { componentLevelThresholds = "
+                        + expectedPerStateBytes
+                        + ", packageSpecificThresholds = {}, appCategorySpecificThresholds = {}, "
+                        + "systemWideThresholds = [] }");
+    }
+
+    @Test
+    public void testIoOveruseStatsDescribeContent() {
+        IoOveruseStats ioOveruseStats =
+                new IoOveruseStats.Builder(0, 10).setStartTime(1).setDurationInSeconds(5).build();
+        int content = ioOveruseStats.describeContents();
+
+        assertThat(content).isEqualTo(0);
+    }
+
+    @Test
+    public void testPackageKillableStateToStringAndDescribeContent() {
+        PackageKillableState packageKillableState = new PackageKillableState("packageName", 10, 1);
+        int content = packageKillableState.describeContents();
+        String string = packageKillableState.toString();
+
+        assertThat(content).isEqualTo(0);
+        assertThat(string).isEqualTo(
+                "PackageKillableState { packageName = packageName, userId = 10, "
+                        + "killableState = "
+                        + PackageKillableState.killableStateToString(1)
+                        + " }");
+    }
+
+    @Test
+    public void testResourceOveruseConfigurationToStringAndDescribeContent() {
+        ResourceOveruseConfiguration resourceOveruseConfiguration =
+                new ResourceOveruseConfiguration.Builder(
+                    ResourceOveruseConfiguration.COMPONENT_TYPE_SYSTEM, new ArrayList<>(),
+                    new ArrayList<>(), new HashMap<>())
+                .addPackagesToAppCategoryTypes("key", "value")
+                .addSafeToKillPackages("safeToKillApp")
+                .addVendorPackagePrefixes("vendorPackagePrefix")
+                .build();
+        int content = resourceOveruseConfiguration.describeContents();
+        String string = resourceOveruseConfiguration.toString();
+
+        assertThat(content).isEqualTo(0);
+        assertThat(string)
+                .isEqualTo("ResourceOveruseConfiguration { componentType = "
+                        + ResourceOveruseConfiguration.componentTypeToString(
+                                ResourceOveruseConfiguration.COMPONENT_TYPE_SYSTEM)
+                        + ", safeToKillPackages = [safeToKillApp], vendorPackagePrefixes = "
+                        + "[vendorPackagePrefix], packagesToAppCategoryTypes = {key=value}, "
+                        + "ioOveruseConfiguration = null }");
+    }
+
     private ICarWatchdogServiceCallback registerClient(
             CarWatchdogManager.CarWatchdogClientCallback client) throws Exception {
         mCarWatchdogManager.registerClient(mExecutor, client, TIMEOUT_CRITICAL);