Snap for 10447354 from c6fa931bc8db866072cd6e6026eeddbbdc5817cb to mainline-wifi-release

Change-Id: I9486e0e2d7ea5817a8e9e6e4ce8faac45daaea38
diff --git a/hostsidetests/packageinstaller/Android.bp b/hostsidetests/packageinstaller/Android.bp
index b1bc038..2c5a469 100644
--- a/hostsidetests/packageinstaller/Android.bp
+++ b/hostsidetests/packageinstaller/Android.bp
@@ -21,7 +21,10 @@
     defaults: ["cts_defaults"],
     srcs: ["src/**/*.java"],
     libs: ["cts-tradefed", "tradefed", "truth-prebuilt"],
-    data: [":CtsRootRollbackManagerHostTestHelperApp"],
+    data: [
+        ":CtsRootPackageInstallerTestCases",
+        ":CtsRootRollbackManagerHostTestHelperApp",
+    ],
     test_suites: ["cts_root", "general-tests"],
 }
 
diff --git a/tests/bluetooth/Android.bp b/tests/bluetooth/Android.bp
new file mode 100644
index 0000000..6e117f1
--- /dev/null
+++ b/tests/bluetooth/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CtsRootBluetoothTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "ctstestrunner-axt",
+        "bluetooth-test-util-lib",
+        "compatibility-device-util-axt",
+        "PlatformProperties",
+        "statsd-helper",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "statsdprotonano",
+    ],
+    srcs: ["src/**/*.java"],
+    // Allows access to system apis
+    platform_apis: true,
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts_root",
+        "general-tests",
+        "mts-bluetooth",
+    ],
+    min_sdk_version: "UpsideDownCake",
+}
diff --git a/tests/bluetooth/AndroidManifest.xml b/tests/bluetooth/AndroidManifest.xml
new file mode 100644
index 0000000..0b93c20
--- /dev/null
+++ b/tests/bluetooth/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.bluetooth.cts_root">
+
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.bluetooth.cts_root"
+                     android:label="CTS root tests of Bluetooth component"/>
+
+</manifest>
+
diff --git a/tests/bluetooth/AndroidTest.xml b/tests/bluetooth/AndroidTest.xml
new file mode 100644
index 0000000..87be477
--- /dev/null
+++ b/tests/bluetooth/AndroidTest.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+<configuration description="Runs Bluetooth CTS root tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="bluetooth" />
+    <!-- Instant apps cannot hold android.permission.BLUETOOTH which makes BT tests irrelevant -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="CtsRootBluetoothTestCases.apk"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="setenforce 0" />
+        <option name="run-command" value="cmd bluetooth_manager enable" />
+        <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
+        <option name="teardown-command" value="cmd bluetooth_manager disable" />
+        <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+        <option name="teardown-command" value="setenforce 1" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.bluetooth.cts_root"/>
+    </test>
+
+    <!-- Only run Cts Tests in MTS if the Bluetooth Mainline module is installed. -->
+    <object type="module_controller"
+            class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.android.btservices" />
+        <option name="mainline-module-package-name" value="com.google.android.btservices" />
+    </object>
+</configuration>
diff --git a/tests/bluetooth/OWNERS b/tests/bluetooth/OWNERS
new file mode 100644
index 0000000..f5f3106
--- /dev/null
+++ b/tests/bluetooth/OWNERS
@@ -0,0 +1,5 @@
+siyuanh@google.com
+muhammadfalam@google.com
+sattiraju@google.com
+girardier@google.com
+sungsoo@google.com
diff --git a/tests/bluetooth/TEST_MAPPING b/tests/bluetooth/TEST_MAPPING
new file mode 100644
index 0000000..324c0b1
--- /dev/null
+++ b/tests/bluetooth/TEST_MAPPING
@@ -0,0 +1,29 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsRootBluetoothTestCases",
+      "options": [
+        {
+          // TODO(b/275847929)
+          "exclude-filter": "android.bluetooth.cts_root.BluetoothCddRootTest#test_C_12_1_Bluetooth5Requirements"
+        }
+      ]
+    }
+  ],
+  "hwasan-postsubmit": [
+    {
+      "name": "CtsRootBluetoothTestCases"
+    }
+  ],
+  "kernel-presubmit": [
+    {
+      "name": "CtsRootBluetoothTestCases",
+      "options": [
+        {
+          // TODO(b/275847929)
+          "exclude-filter": "android.bluetooth.cts_root.BluetoothCddRootTest#test_C_12_1_Bluetooth5Requirements"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/bluetooth/src/android/bluetooth/cts_root/BluetoothCddRootTest.java b/tests/bluetooth/src/android/bluetooth/cts_root/BluetoothCddRootTest.java
new file mode 100644
index 0000000..41e8433
--- /dev/null
+++ b/tests/bluetooth/src/android/bluetooth/cts_root/BluetoothCddRootTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 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.bluetooth.cts_root;
+
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+import static android.Manifest.permission.BLUETOOTH_SCAN;
+import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.PACKAGE_USAGE_STATS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.cts.BTAdapterUtils;
+import android.bluetooth.cts.TestUtils;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.CddTest;
+import com.android.helpers.StatsdHelper;
+import com.android.os.nano.AtomsProto;
+import com.android.os.nano.StatsLog;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Test cases that can only run in rooted environments
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BluetoothCddRootTest {
+    private static final String TAG = BluetoothCddRootTest.class.getSimpleName();
+    private static final int BLUETOOTH_CORE_SPECIFICATION_4_2 = 0x08;
+    private static final int BLUETOOTH_CORE_SPECIFICATION_5_0 = 0x09;
+    private static final int BLUETOOTH_LOCAL_VERSION_REPORTED_ATOM_ID = 530;
+    // Some devices need some extra time after entering STATE_OFF
+    private static final int BLUETOOTH_TOGGLE_DELAY_MS = 2000;
+
+    private Context mContext;
+    private boolean mHasBluetooth;
+    private BluetoothAdapter mAdapter;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mHasBluetooth = TestUtils.hasBluetooth();
+        Assume.assumeTrue(mHasBluetooth);
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT,
+                BLUETOOTH_PRIVILEGED, BLUETOOTH_SCAN, DUMP, PACKAGE_USAGE_STATS);
+        assertThat(TestUtils.getAdoptedShellPermissions()).containsAtLeast(BLUETOOTH_CONNECT,
+                BLUETOOTH_PRIVILEGED, BLUETOOTH_SCAN, DUMP, PACKAGE_USAGE_STATS);
+        mAdapter = TestUtils.getBluetoothAdapterOrDie();
+        if (mAdapter.isEnabled()) {
+            assertThat(BTAdapterUtils.disableAdapter(mAdapter, mContext)).isTrue();
+            try {
+                Thread.sleep(BLUETOOTH_TOGGLE_DELAY_MS);
+            } catch (InterruptedException ignored) { }
+        }
+    }
+
+    @After
+    public void tearDown() {
+        if (!mHasBluetooth) {
+            return;
+        }
+        if (mAdapter != null && mAdapter.getState() != BluetoothAdapter.STATE_OFF) {
+            if (mAdapter.getState() == BluetoothAdapter.STATE_ON) {
+                assertThat(BTAdapterUtils.disableAdapter(mAdapter, mContext)).isTrue();
+            }
+            try {
+                Thread.sleep(BLUETOOTH_TOGGLE_DELAY_MS);
+            } catch (InterruptedException ignored) { }
+        }
+        mAdapter = null;
+        TestUtils.dropPermissionAsShellUid();
+    }
+
+    @CddTest(requirements = {"7.4.3/C-1-1"})
+    @Test
+    public void test_C_1_1_VrHighPerformance() {
+        Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE));
+        assertThat(mHasBluetooth).isTrue();
+        AtomsProto.BluetoothLocalVersionsReported version = getBluetoothVersion();
+        assertThat(version.hciVersion).isAtLeast(BLUETOOTH_CORE_SPECIFICATION_4_2);
+        assertThat(TestUtils.isBleSupported(mContext)).isTrue();
+        // TODO: Enforce LE data length extension
+    }
+
+    @CddTest(requirements = {"7.4.3/H-1-1"})
+    @Test
+    public void test_H_1_1_AshaRequirements() {
+        Assume.assumeTrue(mHasBluetooth);
+        Assume.assumeTrue("Skip 7.4.3/H-1-1 test for non-BLE devices",
+                TestUtils.isBleSupported(mContext));
+        Assume.assumeFalse("Skip 7.4.3/H-1-1 test for automotive devices",
+                TestUtils.isAutomotive(mContext));
+        Assume.assumeFalse("Skip 7.4.3/H-1-1 test for watch devices",
+                TestUtils.isWatch(mContext));
+        Assume.assumeFalse("Skip 7.4.3/H-1-1 test for TV devices",
+                TestUtils.isTv(mContext));
+        AtomsProto.BluetoothLocalVersionsReported version = getBluetoothVersion();
+        Assume.assumeTrue(version.hciVersion >= BLUETOOTH_CORE_SPECIFICATION_5_0);
+        assertThat(BTAdapterUtils.enableAdapter(mAdapter, mContext)).isTrue();
+        assertThat(mAdapter.getSupportedProfiles()).contains(BluetoothProfile.HEARING_AID);
+        TestUtils.BluetoothCtsServiceConnector connector =
+                new TestUtils.BluetoothCtsServiceConnector(TAG,
+                        BluetoothProfile.HEARING_AID, mAdapter, mContext);
+        try {
+            assertThat(connector.openProfileProxyAsync()).isTrue();
+            assertThat(connector.waitForProfileConnect()).isTrue();
+            assertThat(connector.getProfileProxy()).isNotNull();
+        } finally {
+            connector.closeProfileProxy();
+        }
+    }
+
+    @CddTest(requirements = {"7.4.3/C-12-1"})
+    @Test
+    public void test_C_12_1_Bluetooth5Requirements() {
+        Assume.assumeTrue(mHasBluetooth);
+        AtomsProto.BluetoothLocalVersionsReported version = getBluetoothVersion();
+        if (version.hciVersion >= BLUETOOTH_CORE_SPECIFICATION_5_0) {
+            // Assert LMP Version is larger than or equal to HCI version
+            assertThat(version.lmpVersion).isAtLeast(version.hciVersion);
+            assertThat(mAdapter.isLe2MPhySupported()).isTrue();
+            assertThat(mAdapter.isLeCodedPhySupported()).isTrue();
+            assertThat(mAdapter.isLeExtendedAdvertisingSupported()).isTrue();
+            assertThat(mAdapter.isLePeriodicAdvertisingSupported()).isTrue();
+            assertThat(mAdapter.isMultipleAdvertisementSupported()).isTrue();
+            // TODO: Enforce number of advertisement supported
+            // TODO: Enforce number of concurrent LE-ACL connections supported
+        }
+    }
+
+    /**
+     * Get Bluetooth version information. Bluetooth is enabled after this method call.
+     *
+     * Requires ROOT access on the running Android device
+     *
+     * @return Bluetooth version proto
+     */
+    private AtomsProto.BluetoothLocalVersionsReported getBluetoothVersion() {
+        Set<String> permissionsAdopted = TestUtils.getAdoptedShellPermissions();
+        String[] permissionArray = permissionsAdopted.toArray(String[]::new);
+        if (mAdapter.isEnabled()) {
+            assertThat(BTAdapterUtils.disableAdapter(mAdapter, mContext)).isTrue();
+            try {
+                Thread.sleep(BLUETOOTH_TOGGLE_DELAY_MS);
+            } catch (InterruptedException ignored) { }
+        }
+        StatsdHelper statsdHelper = new StatsdHelper();
+        // Requires root to enable metrics
+        assertThat(statsdHelper.addEventConfig(
+                List.of(BLUETOOTH_LOCAL_VERSION_REPORTED_ATOM_ID))).isTrue();
+        assertThat(BTAdapterUtils.enableAdapter(mAdapter, mContext)).isTrue();
+        List<StatsLog.EventMetricData> metrics = statsdHelper.getEventMetrics();
+        AtomsProto.BluetoothLocalVersionsReported summaryAtom =
+                new AtomsProto.BluetoothLocalVersionsReported();
+        // When multiple atoms are reported use the maximum value of HCI version
+        // They should really all be the same
+        int i = 0;
+        for (StatsLog.EventMetricData data : metrics) {
+            AtomsProto.BluetoothLocalVersionsReported atom =
+                    data.atom.getBluetoothLocalVersionsReported();
+            if (atom == null) {
+                continue;
+            }
+            Log.i("BluetoothCddRootTest", "[" + i + "] HCI version is " + atom.hciVersion
+                    + ", LMP version is " + atom.lmpVersion);
+            assertThat(atom.lmpManufacturerName).isGreaterThan(0);
+            assertThat(atom.lmpVersion).isGreaterThan(0);
+            assertThat(atom.hciVersion).isGreaterThan(0);
+            if (atom.hciVersion > summaryAtom.hciVersion) {
+                summaryAtom.lmpManufacturerName = atom.lmpManufacturerName;
+                summaryAtom.lmpVersion = atom.lmpVersion;
+                summaryAtom.lmpSubversion = atom.lmpSubversion;
+                summaryAtom.hciVersion = atom.hciVersion;
+                summaryAtom.hciRevision = atom.hciRevision;
+            }
+            i++;
+        }
+        TestUtils.dropPermissionAsShellUid();
+        TestUtils.adoptPermissionAsShellUid(permissionArray);
+        return summaryAtom;
+    }
+}
diff --git a/tests/bugreport/Android.bp b/tests/bugreport/Android.bp
new file mode 100644
index 0000000..3f49763
--- /dev/null
+++ b/tests/bugreport/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CtsRootBugreportTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "compatibility-device-util-axt",
+        "truth-prebuilt",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    data: [":ctsroot-bugreport-artifacts"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "test_current",
+    test_suites: [
+        "cts_root",
+        "general-tests",
+    ],
+}
+
+filegroup {
+  name: "ctsroot-bugreport-artifacts",
+  srcs: ["config/test-sysconfig.xml"],
+}
diff --git a/tests/bugreport/AndroidManifest.xml b/tests/bugreport/AndroidManifest.xml
new file mode 100644
index 0000000..b29094b
--- /dev/null
+++ b/tests/bugreport/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+           package="android.bugreport.cts_root">
+    <uses-permission android:name="android.permission.DUMP" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.bugreport.cts_root" />
+
+</manifest>
diff --git a/tests/bugreport/AndroidTest.xml b/tests/bugreport/AndroidTest.xml
new file mode 100644
index 0000000..968bdde
--- /dev/null
+++ b/tests/bugreport/AndroidTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<configuration description="Bugreport Manager CTS Root tests">
+    <option name="test-suite-tag" value="cts_root" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsRootBugreportTestCases.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+            <option name="push-file" key="test-sysconfig.xml" value="/system/etc/sysconfig/allow-br-from-tests.xml" />
+            <option name="cleanup" value="true" />
+            <option name="remount-system" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.bugreport.cts_root" />
+    </test>
+</configuration>
diff --git a/tests/bugreport/OWNERS b/tests/bugreport/OWNERS
new file mode 100644
index 0000000..fca58a6
--- /dev/null
+++ b/tests/bugreport/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 153446
+gavincorkery@google.com
+nandana@google.com
diff --git a/tests/bugreport/TEST_MAPPING b/tests/bugreport/TEST_MAPPING
new file mode 100644
index 0000000..c37dda4
--- /dev/null
+++ b/tests/bugreport/TEST_MAPPING
@@ -0,0 +1,17 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsRootBugreportTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "CtsRootBugreportTestCases"
+    }
+  ]
+}
diff --git a/tests/bugreport/config/test-sysconfig.xml b/tests/bugreport/config/test-sysconfig.xml
new file mode 100644
index 0000000..ddf840a
--- /dev/null
+++ b/tests/bugreport/config/test-sysconfig.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- WARNING: This is a test config. -->
+<config>
+  <bugreport-whitelisted package="android.bugreport.cts_root" />
+</config>
\ No newline at end of file
diff --git a/tests/bugreport/src/android/bugreport/cts_root/BugreportManagerTest.java b/tests/bugreport/src/android/bugreport/cts_root/BugreportManagerTest.java
new file mode 100644
index 0000000..e85de59
--- /dev/null
+++ b/tests/bugreport/src/android/bugreport/cts_root/BugreportManagerTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2023 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.bugreport.cts_root;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.os.BugreportManager;
+import android.os.BugreportManager.BugreportCallback;
+import android.os.BugreportParams;
+import android.os.ParcelFileDescriptor;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Device-side tests for Bugreport Manager API.
+ *
+ * <p>These tests require root to allowlist the test package to use the BugreportManager APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public class BugreportManagerTest {
+
+    private Context mContext;
+    private BugreportManager mBugreportManager;
+
+    @Rule
+    public TestName name = new TestName();
+
+    private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mBugreportManager = mContext.getSystemService(BugreportManager.class);
+        // Kill current bugreport, so that it does not interfere with future bugreports.
+        runShellCommand("setprop ctl.stop bugreportd");
+    }
+
+    @After
+    public void tearDown() {
+        // Kill current bugreport, so that it does not interfere with future bugreports.
+        runShellCommand("setprop ctl.stop bugreportd");
+    }
+
+    @LargeTest
+    @Test
+    public void testRetrieveBugreportConsentGranted() throws Exception {
+        File bugreportFile = createTempFile("bugreport_" + name.getMethodName(), ".zip");
+        File startBugreportFile = createTempFile("startbugreport", ".zip");
+        CountDownLatch latch = new CountDownLatch(1);
+        BugreportCallbackImpl callback = new BugreportCallbackImpl(latch);
+        mBugreportManager.startBugreport(parcelFd(startBugreportFile), null,
+                new BugreportParams(
+                        BugreportParams.BUGREPORT_MODE_INTERACTIVE,
+                        BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT),
+                mContext.getMainExecutor(), callback);
+        latch.await(4, TimeUnit.MINUTES);
+        assertThat(callback.isSuccess()).isTrue();
+        // No data should be passed to the FD used to call startBugreport.
+        assertThat(startBugreportFile.length()).isEqualTo(0);
+        String bugreportFileLocation = callback.getBugreportFile();
+        waitForDumpstateServiceToStop();
+
+
+
+        // Trying to retrieve an unknown bugreport should fail
+        latch = new CountDownLatch(1);
+        callback = new BugreportCallbackImpl(latch);
+        File bugreportFile2 = createTempFile("bugreport2_" + name.getMethodName(), ".zip");
+        mBugreportManager.retrieveBugreport(
+                "unknown/file.zip", parcelFd(bugreportFile2),
+                mContext.getMainExecutor(), callback);
+        assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
+        assertThat(callback.getErrorCode()).isEqualTo(
+                BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
+
+        // A bugreport was previously generated for this caller. When the consent dialog is invoked
+        // and accepted, the bugreport files should be passed to the calling package.
+        ParcelFileDescriptor bugreportFd = parcelFd(bugreportFile);
+        assertThat(bugreportFd).isNotNull();
+        latch = new CountDownLatch(1);
+        mBugreportManager.retrieveBugreport(bugreportFileLocation, bugreportFd,
+                mContext.getMainExecutor(), new BugreportCallbackImpl(latch));
+        shareConsentDialog(ConsentReply.ALLOW);
+        assertThat(latch.await(1, TimeUnit.MINUTES)).isTrue();
+        assertThat(bugreportFile.length()).isGreaterThan(0);
+    }
+
+
+    @LargeTest
+    @Test
+    public void testRetrieveBugreportConsentDenied() throws Exception {
+        File bugreportFile = createTempFile("bugreport_" + name.getMethodName(), ".zip");
+
+        // User denies consent, therefore no data should be passed back to the bugreport file.
+        CountDownLatch latch = new CountDownLatch(1);
+        BugreportCallbackImpl callback = new BugreportCallbackImpl(latch);
+        mBugreportManager.startBugreport(parcelFd(new File("/dev/null")),
+                null, new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE,
+                BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT),
+                mContext.getMainExecutor(), callback);
+        latch.await(4, TimeUnit.MINUTES);
+        assertThat(callback.isSuccess()).isTrue();
+        String bugreportFileLocation = callback.getBugreportFile();
+        waitForDumpstateServiceToStop();
+
+        latch = new CountDownLatch(1);
+        ParcelFileDescriptor bugreportFd = parcelFd(bugreportFile);
+        assertThat(bugreportFd).isNotNull();
+        mBugreportManager.retrieveBugreport(
+                bugreportFileLocation,
+                bugreportFd,
+                mContext.getMainExecutor(),
+                callback);
+        shareConsentDialog(ConsentReply.DENY);
+        latch.await(1, TimeUnit.MINUTES);
+        assertThat(callback.getErrorCode()).isEqualTo(
+                BugreportCallback.BUGREPORT_ERROR_USER_DENIED_CONSENT);
+        assertThat(bugreportFile.length()).isEqualTo(0);
+
+        // Since consent has already been denied, this call should fail because consent cannot
+        // be requested twice for the same bugreport.
+        latch = new CountDownLatch(1);
+        callback = new BugreportCallbackImpl(latch);
+        mBugreportManager.retrieveBugreport(bugreportFileLocation, parcelFd(bugreportFile),
+                mContext.getMainExecutor(), callback);
+        latch.await(1, TimeUnit.MINUTES);
+        assertThat(callback.getErrorCode()).isEqualTo(
+                BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
+    }
+
+    private ParcelFileDescriptor parcelFd(File file) throws Exception {
+        return ParcelFileDescriptor.open(file,
+            ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
+    }
+
+    private static File createTempFile(String prefix, String extension) throws Exception {
+        final File f = File.createTempFile(prefix, extension);
+        f.setReadable(true, true);
+        f.setWritable(true, true);
+
+        f.deleteOnExit();
+        return f;
+    }
+
+    private static final class BugreportCallbackImpl extends BugreportCallback {
+        private int mErrorCode = -1;
+        private boolean mSuccess = false;
+        private String mBugreportFile;
+        private final Object mLock = new Object();
+
+        private final CountDownLatch mLatch;
+
+        BugreportCallbackImpl(CountDownLatch latch) {
+            mLatch = latch;
+        }
+
+        @Override
+        public void onError(int errorCode) {
+            synchronized (mLock) {
+                mErrorCode = errorCode;
+                mLatch.countDown();
+            }
+        }
+
+        @Override
+        public void onFinished(String bugreportFile) {
+            synchronized (mLock) {
+                mBugreportFile = bugreportFile;
+                mLatch.countDown();
+                mSuccess =  true;
+            }
+        }
+
+        @Override
+        public void onFinished() {
+            synchronized (mLock) {
+                mLatch.countDown();
+                mSuccess = true;
+            }
+        }
+
+        public int getErrorCode() {
+            synchronized (mLock) {
+                return mErrorCode;
+            }
+        }
+
+        public boolean isSuccess() {
+            synchronized (mLock) {
+                return mSuccess;
+            }
+        }
+
+        public String getBugreportFile() {
+            synchronized (mLock) {
+                return mBugreportFile;
+            }
+        }
+    }
+
+    private enum ConsentReply {
+        ALLOW,
+        DENY,
+        TIMEOUT
+    }
+
+    /*
+     * Ensure the consent dialog is shown and take action according to <code>consentReply<code/>.
+     * It will fail if the dialog is not shown when <code>ignoreNotFound<code/> is false.
+     */
+    private void shareConsentDialog(@NonNull ConsentReply consentReply) throws Exception {
+        final UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        // Unlock before finding/clicking an object.
+        device.wakeUp();
+        device.executeShellCommand("wm dismiss-keyguard");
+
+        final BySelector consentTitleObj = By.res("android", "alertTitle");
+        if (!device.wait(Until.hasObject(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)) {
+            fail("The consent dialog is not found");
+        }
+        if (consentReply.equals(ConsentReply.TIMEOUT)) {
+            return;
+        }
+        final BySelector selector;
+        if (consentReply.equals(ConsentReply.ALLOW)) {
+            selector = By.res("android", "button1");
+        } else { // ConsentReply.DENY
+            selector = By.res("android", "button2");
+        }
+        final UiObject2 btnObj = device.findObject(selector);
+        assertThat(btnObj).isNotNull();
+        btnObj.click();
+
+        assertThat(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)).isTrue();
+    }
+
+
+    /** Waits for the dumpstate service to stop, for up to 5 seconds. */
+    private void waitForDumpstateServiceToStop() throws Exception {
+        int pollingIntervalMillis = 100;
+        int numPolls = 50;
+        Method method = Class.forName("android.os.ServiceManager").getMethod(
+                "getService", String.class);
+        while (numPolls-- > 0) {
+            // If getService() returns null, the service has stopped.
+            if (method.invoke(null, "dumpstate") == null) {
+                return;
+            }
+            Thread.sleep(pollingIntervalMillis);
+        }
+        fail("Dumpstate did not stop within 5 seconds");
+    }
+}
diff --git a/tests/packagewatchdog/OWNERS b/tests/packagewatchdog/OWNERS
index 0342627..b929d27 100644
--- a/tests/packagewatchdog/OWNERS
+++ b/tests/packagewatchdog/OWNERS
@@ -1,4 +1,4 @@
-# Bug component: 557916
-gavincorkery@google.com
-wangchun@google.com
-olilan@google.com
\ No newline at end of file
+# Bug component: 1306443
+ancr@google.com
+harshitmahajan@google.com
+wangchun@google.com
\ No newline at end of file
diff --git a/tests/packagewatchdog/src/android/packagewatchdog/cts_root/PackageWatchdogTest.java b/tests/packagewatchdog/src/android/packagewatchdog/cts_root/PackageWatchdogTest.java
index 8f425bc..d8b9b42 100644
--- a/tests/packagewatchdog/src/android/packagewatchdog/cts_root/PackageWatchdogTest.java
+++ b/tests/packagewatchdog/src/android/packagewatchdog/cts_root/PackageWatchdogTest.java
@@ -251,13 +251,13 @@
         TestObserver(String name, CountDownLatch latch) {
             mName = name;
             mLatch = latch;
-            mImpact = PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
+            mImpact = PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
         }
 
         TestObserver(String name) {
             mName = name;
             mLatch = new CountDownLatch(1);
-            mImpact = PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
+            mImpact = PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
         }
 
         public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason,