Merge changes I279e0627,Ica2f5654 into sc-dev

* changes:
  Added unit tests for NewUserDisclaimerActivity
  Added unit tests for PerUserCarDevicePolicyService
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/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_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/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/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/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/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/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index e2c2b08..78ff99d 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) {
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/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_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");
+    }
+}