[automerger skipped] Strictly deprecate IRPC test mode key generation am: 18a1915f04 -s ours

am skip reason: Merged-In I5709a0b1cd77eb28e677f64bb781fad58d91570a with SHA-1 f2ae193680 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/hardware/interfaces/+/22851513

Change-Id: Ia49e937a76f731ade2d609ce1ad07d54a2011d38
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/automotive/ivn_android_device/impl/default/Android.bp b/automotive/ivn_android_device/impl/default/Android.bp
new file mode 100644
index 0000000..98c1f58
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/Android.bp
@@ -0,0 +1,58 @@
+/*
+ * 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"],
+}
+
+cc_library {
+    name: "IvnAndroidDeviceService",
+    vendor_available: true,
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    srcs: [
+        "src/IvnAndroidDeviceService.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.automotive.ivn-V1-ndk",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libjsoncpp",
+        "liblog",
+        "libutils",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.automotive.ivn@V1-default-service",
+    vendor: true,
+    relative_install_path: "hw",
+    local_include_dirs: ["include"],
+    srcs: ["src/IvnAndroidDeviceImpl.cpp"],
+    whole_static_libs: ["IvnAndroidDeviceService"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libjsoncpp",
+        "liblog",
+        "libutils",
+    ],
+    required: ["Prebuilt_IvnAndroidDeviceServiceDefaultConfig_JSON"],
+    vintf_fragments: ["ivn-default-service.xml"],
+    init_rc: ["ivn-default-service.rc"],
+}
diff --git a/automotive/ivn_android_device/impl/default/config/Android.bp b/automotive/ivn_android_device/impl/default/config/Android.bp
new file mode 100644
index 0000000..03c4d1b
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/config/Android.bp
@@ -0,0 +1,32 @@
+/*
+ * 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"],
+}
+
+filegroup {
+    name: "IvnAndroidDeviceServiceDefaultConfig_Json",
+    srcs: ["DefaultConfig.json"],
+}
+
+prebuilt_etc {
+    name: "Prebuilt_IvnAndroidDeviceServiceDefaultConfig_JSON",
+    filename_from_src: true,
+    src: "DefaultConfig.json",
+    sub_dir: "automotive/IvnConfig/",
+    vendor: true,
+}
diff --git a/automotive/ivn_android_device/impl/default/config/DefaultConfig.json b/automotive/ivn_android_device/impl/default/config/DefaultConfig.json
new file mode 100644
index 0000000..45663e2
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/config/DefaultConfig.json
@@ -0,0 +1,61 @@
+{
+    "MyDeviceId": 0,
+    "Devices": [
+        {
+            "DeviceId": 0,
+            "OccupantZones": [
+                {
+                    "ZoneId": 0,
+                    "OccupantType": "DRIVER",
+                    "Seat": 1,
+                    "Comments": "Occupant zone for driver and FRONT_LEFT seat"
+                },
+                {
+                    "ZoneId": 1,
+                    "OccupantType": "FRONT_PASSENGER",
+                    "Seat": 4,
+                    "Comments": "Occupant zone for FRONT_RIGHT passenger"
+                }
+            ],
+            "EndpointInfo": {
+                "IpAddress": "10.10.10.1",
+                "PortNumber": 1234,
+                "BrandName": "MyBrand",
+                "DeviceName": "MyDevice",
+                "ProductName": "MyProduct",
+                "ManufacturerName": "MyCompany",
+                "ModelName": "MyModel",
+                "SerialNumber": "Serial1234"
+            },
+            "Comments": "Device for front row"
+        },
+        {
+            "DeviceId": 1,
+            "OccupantZones": [
+                {
+                    "ZoneId": 2,
+                    "OccupantType": "REAR_PASSENGER",
+                    "Seat": 16
+                },
+                {
+                    "ZoneId": 3,
+                    "OccupantType": "REAR_PASSENGER",
+                    "Seat": 64
+                }
+            ],
+            "EndpointInfo": {
+                "IpAddress": "10.10.10.2",
+                "PortNumber": 2345,
+                "BrandName": "MyBrand",
+                "DeviceName": "MyDevice",
+                "ProductName": "MyProduct",
+                "ManufacturerName": "MyCompany",
+                "ModelName": "MyModel",
+                "SerialNumber": "Serial2345"
+            },
+            "Comments": "Device for back row"
+        }
+    ],
+    "Comment":
+            "This simulates a vehicle with two Android devices, one for front row, one for back row"
+}
diff --git a/automotive/ivn_android_device/impl/default/include/IvnAndroidDeviceService.h b/automotive/ivn_android_device/impl/default/include/IvnAndroidDeviceService.h
new file mode 100644
index 0000000..c0cc9fe
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/include/IvnAndroidDeviceService.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/ivn/BnIvnAndroidDevice.h>
+#include <aidl/android/hardware/automotive/ivn/EndpointInfo.h>
+#include <aidl/android/hardware/automotive/ivn/OccupantZoneInfo.h>
+#include <android/binder_auto_utils.h>
+#include <vector>
+
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace ivn {
+
+struct DeviceInfo {
+    std::vector<aidl::android::hardware::automotive::ivn::OccupantZoneInfo> occupantZones;
+    aidl::android::hardware::automotive::ivn::EndpointInfo endpointInfo;
+};
+
+class IvnAndroidDeviceService
+    : public aidl::android::hardware::automotive::ivn::BnIvnAndroidDevice {
+  public:
+    explicit IvnAndroidDeviceService(std::string_view configPath);
+
+    // Initialize the service, returns true on success.
+    bool init();
+
+    ndk::ScopedAStatus getMyDeviceId(int* deviceId) override;
+
+    ndk::ScopedAStatus getOtherDeviceIds(std::vector<int>* deviceIds) override;
+
+    ndk::ScopedAStatus getDeviceIdForOccupantZone(int zoneId, int* deviceId) override;
+
+    ndk::ScopedAStatus getOccupantZonesForDevice(
+            int androidDeviceId,
+            std::vector<aidl::android::hardware::automotive::ivn::OccupantZoneInfo>* occupantZones)
+            override;
+
+    ndk::ScopedAStatus getMyEndpointInfo(
+            aidl::android::hardware::automotive::ivn::EndpointInfo* endpointInfo) override;
+
+    ndk::ScopedAStatus getEndpointInfoForDevice(
+            int androidDeviceId,
+            aidl::android::hardware::automotive::ivn::EndpointInfo* endpointInfo) override;
+
+  private:
+    int mMyDeviceId;
+    std::unordered_map<int, DeviceInfo> mDeviceInfoById;
+    std::string_view mConfigPath;
+};
+
+}  // namespace ivn
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/ivn_android_device/impl/default/ivn-default-service.rc b/automotive/ivn_android_device/impl/default/ivn-default-service.rc
new file mode 100644
index 0000000..070b259
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/ivn-default-service.rc
@@ -0,0 +1,4 @@
+service vendor.ivn-default /vendor/bin/hw/android.hardware.automotive.ivn@V1-default-service
+    class hal
+    user vehicle_network
+    group system inet
diff --git a/automotive/ivn_android_device/impl/default/ivn-default-service.xml b/automotive/ivn_android_device/impl/default/ivn-default-service.xml
new file mode 100644
index 0000000..481bc0a
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/ivn-default-service.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.automotive.ivn</name>
+        <version>1</version>
+        <fqname>IIvnAndroidDevice/default</fqname>
+    </hal>
+</manifest>
diff --git a/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceImpl.cpp b/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceImpl.cpp
new file mode 100644
index 0000000..fdf6776
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceImpl.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IvnAndroidDeviceImpl"
+
+#include "IvnAndroidDeviceService.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <stdlib.h>
+
+constexpr char SERVICE_NAME[] = "android.hardware.automotive.ivn.IIvnAndroidDevice/default";
+constexpr char DEFAULT_CONFIG_DIR[] = "/vendor/etc/automotive/IvnConfig/DefaultConfig.json";
+
+int main(int /* argc */, char* /* argv */[]) {
+    LOG(INFO) << "Registering IvnAndroidDeviceService as service...";
+    auto service =
+            ndk::SharedRefBase::make<android::hardware::automotive::ivn::IvnAndroidDeviceService>(
+                    DEFAULT_CONFIG_DIR);
+    if (!service->init()) {
+        LOG(ERROR) << "Failed to init IvnAndroidDeviceService";
+        exit(1);
+    }
+
+    binder_exception_t err = AServiceManager_addService(service->asBinder().get(), SERVICE_NAME);
+    if (err != EX_NONE) {
+        LOG(ERROR) << "Failed to register IvnAndroidDeviceService service, exception: " << err;
+        exit(1);
+    }
+
+    if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+        LOG(ERROR) << "Failed to set thread pool max thread count";
+        exit(1);
+    }
+    ABinderProcess_startThreadPool();
+
+    LOG(INFO) << "IvnAndroidDeviceService Ready";
+
+    ABinderProcess_joinThreadPool();
+
+    LOG(ERROR) << "IvnAndroidDeviceService init failed! Should not reach here";
+
+    return 0;
+}
diff --git a/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceService.cpp b/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceService.cpp
new file mode 100644
index 0000000..71454d5
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/src/IvnAndroidDeviceService.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#include "IvnAndroidDeviceService.h"
+
+#include <aidl/android/hardware/automotive/ivn/ConnectProtocol.h>
+#include <aidl/android/hardware/automotive/ivn/HardwareIdentifiers.h>
+#include <aidl/android/hardware/automotive/ivn/OccupantType.h>
+#include <android-base/logging.h>
+#include <android/binder_status.h>
+#include <json/json.h>
+
+#include <fstream>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace ivn {
+
+namespace {
+
+using ::aidl::android::hardware::automotive::ivn::ConnectProtocol;
+using ::aidl::android::hardware::automotive::ivn::EndpointInfo;
+using ::aidl::android::hardware::automotive::ivn::HardwareIdentifiers;
+using ::aidl::android::hardware::automotive::ivn::OccupantType;
+using ::aidl::android::hardware::automotive::ivn::OccupantZoneInfo;
+using ::ndk::ScopedAStatus;
+
+constexpr int IVN_ERROR_GENERIC = -1;
+
+}  // namespace
+
+IvnAndroidDeviceService::IvnAndroidDeviceService(std::string_view configPath) {
+    mConfigPath = configPath;
+}
+
+bool IvnAndroidDeviceService::init() {
+    std::ifstream configStream(mConfigPath);
+    if (!configStream) {
+        LOG(ERROR) << "couldn't open " << mConfigPath << " for parsing.";
+        return false;
+    }
+    Json::CharReaderBuilder builder;
+    Json::Value root;
+    std::string errs;
+    if (!Json::parseFromStream(builder, configStream, &root, &errs)) {
+        LOG(ERROR) << "Failed to parse config JSON stream, error: " << errs;
+        return false;
+    }
+    if (!root.isObject()) {
+        LOG(ERROR) << "Root must be an object";
+        return false;
+    }
+    if (!root.isMember("MyDeviceId")) {
+        LOG(ERROR) << "Must contain 'MyDeviceId' field";
+        return false;
+    }
+    mMyDeviceId = root["MyDeviceId"].asInt();
+    if (!root.isMember("Devices") || !root["Devices"].isArray()) {
+        LOG(ERROR) << "Must contain 'Devices' field as array";
+        return false;
+    }
+    Json::Value& devices = root["Devices"];
+    for (unsigned int i = 0; i < devices.size(); i++) {
+        Json::Value& device = devices[i];
+        int deviceId = device["DeviceId"].asInt();
+        DeviceInfo deviceInfo = {};
+        Json::Value& occupantZones = device["OccupantZones"];
+        for (unsigned int j = 0; j < occupantZones.size(); j++) {
+            Json::Value& occupantZone = occupantZones[j];
+            int zoneId = occupantZone["ZoneId"].asInt();
+            std::string occupantTypeStr = occupantZone["OccupantType"].asString();
+            int seat = occupantZone["Seat"].asInt();
+            OccupantType occupantType;
+            if (occupantTypeStr == "DRIVER") {
+                occupantType = OccupantType::DRIVER;
+            } else if (occupantTypeStr == "FRONT_PASSENGER") {
+                occupantType = OccupantType::FRONT_PASSENGER;
+            } else if (occupantTypeStr == "REAR_PASSENGER") {
+                occupantType = OccupantType::REAR_PASSENGER;
+            } else {
+                LOG(ERROR) << "Unknown occupant type: " << occupantTypeStr;
+                return false;
+            }
+            OccupantZoneInfo occupantZoneInfo = {
+                    .zoneId = zoneId, .occupantType = occupantType, .seat = seat};
+            deviceInfo.occupantZones.push_back(std::move(occupantZoneInfo));
+        }
+        Json::Value& ep = device["EndpointInfo"];
+        EndpointInfo endpointInfo = {};
+        endpointInfo.connectProtocol = ConnectProtocol::TCP_IP;
+        endpointInfo.ipAddress = ep["IpAddress"].asString();
+        endpointInfo.portNumber = ep["PortNumber"].asInt();
+        HardwareIdentifiers hardwareId = {};
+        if (ep.isMember("BrandName")) {
+            hardwareId.brandName = ep["BrandName"].asString();
+        }
+        if (ep.isMember("DeviceName")) {
+            hardwareId.deviceName = ep["DeviceName"].asString();
+        }
+        if (ep.isMember("ProductName")) {
+            hardwareId.productName = ep["ProductName"].asString();
+        }
+        if (ep.isMember("ManufacturerName")) {
+            hardwareId.manufacturerName = ep["ManufacturerName"].asString();
+        }
+        if (ep.isMember("ModelName")) {
+            hardwareId.modelName = ep["ModelName"].asString();
+        }
+        if (ep.isMember("SerialNumber")) {
+            hardwareId.serialNumber = ep["SerialNumber"].asString();
+        }
+        endpointInfo.hardwareId = hardwareId;
+        deviceInfo.endpointInfo = endpointInfo;
+        mDeviceInfoById[deviceId] = deviceInfo;
+    }
+    if (mDeviceInfoById.find(mMyDeviceId) == mDeviceInfoById.end()) {
+        LOG(ERROR) << "My device ID is not in the device info list";
+        return false;
+    }
+    return true;
+}
+
+ScopedAStatus IvnAndroidDeviceService::getMyDeviceId(int* deviceId) {
+    *deviceId = mMyDeviceId;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus IvnAndroidDeviceService::getOtherDeviceIds(std::vector<int>* deviceIds) {
+    deviceIds->clear();
+    for (const auto& [deviceId, _] : mDeviceInfoById) {
+        if (deviceId == mMyDeviceId) {
+            continue;
+        }
+        deviceIds->push_back(deviceId);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus IvnAndroidDeviceService::getDeviceIdForOccupantZone(int zoneId, int* outDeviceId) {
+    for (const auto& [deviceId, deviceInfo] : mDeviceInfoById) {
+        for (const auto& occupantZoneInfo : deviceInfo.occupantZones) {
+            if (occupantZoneInfo.zoneId == zoneId) {
+                *outDeviceId = deviceId;
+                return ScopedAStatus::ok();
+            }
+        }
+    }
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(IVN_ERROR_GENERIC,
+                                                              "Occupant zone not found");
+}
+
+ScopedAStatus IvnAndroidDeviceService::getOccupantZonesForDevice(
+        int androidDeviceId, std::vector<OccupantZoneInfo>* occupantZones) {
+    if (mDeviceInfoById.find(androidDeviceId) == mDeviceInfoById.end()) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(IVN_ERROR_GENERIC,
+                                                                  "Android device ID not found");
+    }
+    for (const auto& occupantZoneInfo : mDeviceInfoById[androidDeviceId].occupantZones) {
+        occupantZones->push_back(occupantZoneInfo);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus IvnAndroidDeviceService::getMyEndpointInfo(EndpointInfo* endpointInfo) {
+    *endpointInfo = mDeviceInfoById[mMyDeviceId].endpointInfo;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus IvnAndroidDeviceService::getEndpointInfoForDevice(int androidDeviceId,
+                                                                EndpointInfo* endpointInfo) {
+    if (mDeviceInfoById.find(androidDeviceId) == mDeviceInfoById.end()) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(IVN_ERROR_GENERIC,
+                                                                  "Android device ID not found");
+    }
+    *endpointInfo = mDeviceInfoById[androidDeviceId].endpointInfo;
+    return ScopedAStatus::ok();
+}
+
+}  // namespace ivn
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/ivn_android_device/impl/default/test/Android.bp b/automotive/ivn_android_device/impl/default/test/Android.bp
new file mode 100644
index 0000000..a100575
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/test/Android.bp
@@ -0,0 +1,42 @@
+/*
+ * 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"],
+}
+
+cc_test {
+    name: "IvnAndroidDeviceServiceUnitTest",
+    vendor: true,
+    srcs: ["*.cpp"],
+    whole_static_libs: [
+        "IvnAndroidDeviceService",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libjsoncpp",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "libgtest",
+    ],
+    data: [
+        ":IvnAndroidDeviceServiceDefaultConfig_Json",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/automotive/ivn_android_device/impl/default/test/IvnAndroidDeviceServiceUnittest.cpp b/automotive/ivn_android_device/impl/default/test/IvnAndroidDeviceServiceUnittest.cpp
new file mode 100644
index 0000000..bc8e69f
--- /dev/null
+++ b/automotive/ivn_android_device/impl/default/test/IvnAndroidDeviceServiceUnittest.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include "IvnAndroidDeviceService.h"
+
+#include <aidl/android/hardware/automotive/ivn/OccupantType.h>
+#include <aidl/android/hardware/automotive/ivn/OccupantZoneInfo.h>
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace ivn {
+
+using ::aidl::android::hardware::automotive::ivn::OccupantType;
+using ::aidl::android::hardware::automotive::ivn::OccupantZoneInfo;
+using ::ndk::ScopedAStatus;
+
+class IvnAndroidDeviceServiceUnitTest : public ::testing::Test {
+  public:
+    virtual void SetUp() override {
+        mService = ndk::SharedRefBase::make<IvnAndroidDeviceService>(
+                android::base::GetExecutableDirectory() + "/DefaultConfig.json");
+        mService->init();
+    }
+
+    std::shared_ptr<IvnAndroidDeviceService> mService;
+};
+
+TEST_F(IvnAndroidDeviceServiceUnitTest, TestGetMyDeviceId) {
+    int deviceId = -1;
+
+    ScopedAStatus status = mService->getMyDeviceId(&deviceId);
+
+    ASSERT_TRUE(status.isOk());
+    ASSERT_EQ(deviceId, 0);
+}
+
+TEST_F(IvnAndroidDeviceServiceUnitTest, TestGetOtherDeviceIds) {
+    std::vector<int> deviceIds;
+
+    ScopedAStatus status = mService->getOtherDeviceIds(&deviceIds);
+
+    ASSERT_TRUE(status.isOk());
+    ASSERT_EQ(deviceIds, std::vector<int>({1}));
+}
+
+TEST_F(IvnAndroidDeviceServiceUnitTest, TestGetDeviceIdForOccupantZone) {
+    int deviceId = -1;
+
+    ScopedAStatus status = mService->getDeviceIdForOccupantZone(/*zoneId=*/0, &deviceId);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(deviceId, 0);
+
+    status = mService->getDeviceIdForOccupantZone(/*zoneId=*/1, &deviceId);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(deviceId, 0);
+
+    status = mService->getDeviceIdForOccupantZone(/*zoneId=*/2, &deviceId);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(deviceId, 1);
+
+    status = mService->getDeviceIdForOccupantZone(/*zoneId=*/3, &deviceId);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(deviceId, 1);
+
+    status = mService->getDeviceIdForOccupantZone(/*zoneId=*/4, &deviceId);
+
+    ASSERT_FALSE(status.isOk());
+}
+
+TEST_F(IvnAndroidDeviceServiceUnitTest, TestGetOccupantZonesForDevice) {
+    std::vector<OccupantZoneInfo> occupantZones;
+
+    ScopedAStatus status =
+            mService->getOccupantZonesForDevice(/*androidDeviceId=*/0, &occupantZones);
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(occupantZones.size(), 2);
+    if (occupantZones.size() == 2) {
+        EXPECT_EQ(occupantZones[0].zoneId, 0);
+        EXPECT_EQ(occupantZones[0].occupantType, OccupantType::DRIVER);
+        EXPECT_EQ(occupantZones[0].seat, 1);
+        EXPECT_EQ(occupantZones[1].zoneId, 1);
+        EXPECT_EQ(occupantZones[1].occupantType, OccupantType::FRONT_PASSENGER);
+        EXPECT_EQ(occupantZones[1].seat, 4);
+    }
+}
+
+}  // namespace ivn
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index ec0d310..0a1f904 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -113,6 +113,7 @@
         {"WHEEL_FRONT_LEFT", WHEEL_FRONT_LEFT},
         {"CHARGE_PORT_FRONT_LEFT", CHARGE_PORT_FRONT_LEFT},
         {"CHARGE_PORT_REAR_LEFT", CHARGE_PORT_REAR_LEFT},
+        {"FAN_DIRECTION_UNKNOWN", toInt(VehicleHvacFanDirection::UNKNOWN)},
         {"FAN_DIRECTION_FLOOR", FAN_DIRECTION_FLOOR},
         {"FAN_DIRECTION_FACE", FAN_DIRECTION_FACE},
         {"FAN_DIRECTION_DEFROST", FAN_DIRECTION_DEFROST},
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 84edeed..5503de2 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -2164,6 +2164,7 @@
             "property": "VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE",
             "defaultValue": {
                 "int32Values": [
+                    "Constants::FAN_DIRECTION_UNKNOWN",
                     "Constants::FAN_DIRECTION_FACE",
                     "Constants::FAN_DIRECTION_FLOOR",
                     "Constants::FAN_DIRECTION_FACE_FLOOR",
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
index d4e4b34..940f2ad 100644
--- a/bluetooth/aidl/default/BluetoothHci.cpp
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -176,7 +176,10 @@
   mFdWatcher.WatchFdForNonBlockingReads(mFd,
                                         [this](int) { mH4->OnDataReady(); });
 
-  send(PacketType::COMMAND, reset);
+  ndk::ScopedAStatus result = send(PacketType::COMMAND, reset);
+  if (!result.isOk()) {
+    ALOGE("Error sending reset command");
+  }
   auto status = resetFuture.wait_for(std::chrono::seconds(1));
   mFdWatcher.StopWatchingFileDescriptors();
   if (status == std::future_status::ready) {
@@ -303,30 +306,35 @@
 
 ndk::ScopedAStatus BluetoothHci::sendHciCommand(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::COMMAND, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::COMMAND, packet);
 }
 
 ndk::ScopedAStatus BluetoothHci::sendAclData(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::ACL_DATA, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::ACL_DATA, packet);
 }
 
 ndk::ScopedAStatus BluetoothHci::sendScoData(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::SCO_DATA, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::SCO_DATA, packet);
 }
 
 ndk::ScopedAStatus BluetoothHci::sendIsoData(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::ISO_DATA, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::ISO_DATA, packet);
 }
 
-void BluetoothHci::send(PacketType type, const std::vector<uint8_t>& v) {
+ndk::ScopedAStatus BluetoothHci::send(PacketType type,
+    const std::vector<uint8_t>& v) {
+  if (mH4 == nullptr) {
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+  }
+  if (v.empty()) {
+    ALOGE("Packet is empty, no data was found to be sent");
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
   mH4->Send(type, v);
+  return ndk::ScopedAStatus::ok();
 }
 
 }  // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/BluetoothHci.h b/bluetooth/aidl/default/BluetoothHci.h
index 85aafc8..477cc5c 100644
--- a/bluetooth/aidl/default/BluetoothHci.h
+++ b/bluetooth/aidl/default/BluetoothHci.h
@@ -66,8 +66,9 @@
   ::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
 
   int getFdFromDevPath();
-  void send(::android::hardware::bluetooth::hci::PacketType type,
-            const std::vector<uint8_t>& packet);
+  [[nodiscard]] ndk::ScopedAStatus send(
+      ::android::hardware::bluetooth::hci::PacketType type,
+      const std::vector<uint8_t>& packet);
   std::unique_ptr<NetBluetoothMgmt> management_{};
 
   // Send a reset command and discard all packets until a reset is received.
diff --git a/bluetooth/hci/h4_protocol.cc b/bluetooth/hci/h4_protocol.cc
index 51a624f..5f6d86e 100644
--- a/bluetooth/hci/h4_protocol.cc
+++ b/bluetooth/hci/h4_protocol.cc
@@ -105,15 +105,12 @@
       buffer_offset += 1;
     } else {
       bool packet_ready = hci_packetizer_.OnDataReady(
-          hci_packet_type_, input_buffer, buffer_offset);
+          hci_packet_type_, input_buffer, &buffer_offset);
       if (packet_ready) {
-        // Call packet callback and move offset.
-        buffer_offset += OnPacketReady(hci_packetizer_.GetPacket());
+        // Call packet callback.
+        OnPacketReady(hci_packetizer_.GetPacket());
         // Get ready for the next type byte.
         hci_packet_type_ = PacketType::UNKNOWN;
-      } else {
-        // The data was consumed, but there wasn't a packet.
-        buffer_offset = input_buffer.size();
       }
     }
   }
diff --git a/bluetooth/hci/hci_packetizer.cc b/bluetooth/hci/hci_packetizer.cc
index 5b6c443..4135920 100644
--- a/bluetooth/hci/hci_packetizer.cc
+++ b/bluetooth/hci/hci_packetizer.cc
@@ -51,9 +51,10 @@
 
 bool HciPacketizer::OnDataReady(PacketType packet_type,
                                 const std::vector<uint8_t>& buffer,
-                                size_t offset) {
+                                size_t* offset) {
   bool packet_completed = false;
-  size_t bytes_available = buffer.size() - offset;
+  size_t bytes_available = buffer.size() - *offset;
+
   switch (state_) {
     case HCI_HEADER: {
       size_t header_size =
@@ -62,18 +63,20 @@
         bytes_remaining_ = header_size;
         packet_.clear();
       }
+
       size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
-      packet_.insert(packet_.end(), buffer.begin() + offset,
-                     buffer.begin() + offset + bytes_to_copy);
+      packet_.insert(packet_.end(), buffer.begin() + *offset,
+                     buffer.begin() + *offset + bytes_to_copy);
       bytes_remaining_ -= bytes_to_copy;
       bytes_available -= bytes_to_copy;
+      *offset += bytes_to_copy;
+
       if (bytes_remaining_ == 0) {
         bytes_remaining_ = HciGetPacketLengthForType(packet_type, packet_);
         if (bytes_remaining_ > 0) {
           state_ = HCI_PAYLOAD;
           if (bytes_available > 0) {
-            packet_completed =
-                OnDataReady(packet_type, buffer, offset + bytes_to_copy);
+            packet_completed = OnDataReady(packet_type, buffer, offset);
           }
         } else {
           packet_completed = true;
@@ -84,9 +87,10 @@
 
     case HCI_PAYLOAD: {
       size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
-      packet_.insert(packet_.end(), buffer.begin() + offset,
-                     buffer.begin() + offset + bytes_to_copy);
+      packet_.insert(packet_.end(), buffer.begin() + *offset,
+                     buffer.begin() + *offset + bytes_to_copy);
       bytes_remaining_ -= bytes_to_copy;
+      *offset += bytes_to_copy;
       if (bytes_remaining_ == 0) {
         state_ = HCI_HEADER;
         packet_completed = true;
@@ -94,6 +98,7 @@
       break;
     }
   }
+
   return packet_completed;
 }
 
diff --git a/bluetooth/hci/hci_packetizer.h b/bluetooth/hci/hci_packetizer.h
index ba3e841..0d9319f 100644
--- a/bluetooth/hci/hci_packetizer.h
+++ b/bluetooth/hci/hci_packetizer.h
@@ -28,7 +28,7 @@
  public:
   HciPacketizer() = default;
   bool OnDataReady(PacketType packet_type, const std::vector<uint8_t>& data,
-                   size_t offset);
+                   size_t* offset);
   const std::vector<uint8_t>& GetPacket() const;
 
  protected:
diff --git a/bluetooth/hci/test/h4_protocol_unittest.cc b/bluetooth/hci/test/h4_protocol_unittest.cc
index d3fab61..f0c49b5 100644
--- a/bluetooth/hci/test/h4_protocol_unittest.cc
+++ b/bluetooth/hci/test/h4_protocol_unittest.cc
@@ -31,7 +31,6 @@
 #include <vector>
 
 #include "async_fd_watcher.h"
-#include "log/log.h"
 
 using android::hardware::bluetooth::async::AsyncFdWatcher;
 using namespace android::hardware::bluetooth::hci;
@@ -49,6 +48,7 @@
 static char event_data[100] = "The edges of a surface are lines.";
 static char iso_data[100] =
     "A plane angle is the inclination to one another of two lines in a ...";
+static char short_payload[10] = "12345";
 
 // 5 seconds.  Just don't hang.
 static constexpr size_t kTimeoutMs = 5000;
@@ -225,6 +225,49 @@
     CallDataReady();
   }
 
+  void WriteAndExpectManyAclDataPacketsDifferentOffsetsShort() {
+    std::promise<void> last_packet_promise;
+    size_t kNumPackets = 30;
+    // h4 type[1] + handle[2] + size[2]
+    char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
+                        0};
+    int length = strlen(short_payload);
+    preamble[3] = length & 0xFF;
+    preamble[4] = 0;
+
+    EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, kAclHeaderSize,
+                                            short_payload)))
+        .Times(kNumPackets);
+    ExpectInboundEvent(event_data, &last_packet_promise);
+
+    char all_packets[kNumPackets * 10];
+    size_t total_bytes = 0;
+
+    for (size_t packet = 0; packet < kNumPackets; packet++) {
+      for (size_t i = 0; i < sizeof(preamble); i++) {
+        all_packets[total_bytes++] = preamble[i];
+      }
+      for (size_t i = 0; i < length; i++) {
+        all_packets[total_bytes++] = short_payload[i];
+      }
+    }
+
+    size_t written_bytes = 0;
+    size_t partial_size = 1;
+    while (written_bytes < total_bytes) {
+      size_t to_write = std::min(partial_size, total_bytes - written_bytes);
+      TEMP_FAILURE_RETRY(
+          write(chip_uart_fd_, all_packets + written_bytes, to_write));
+      written_bytes += to_write;
+      CallDataReady();
+      partial_size++;
+      partial_size = partial_size % 5 + 1;
+    }
+    WriteInboundEvent(event_data);
+    CallDataReady();
+    WaitForTimeout(&last_packet_promise);
+  }
+
   testing::MockFunction<void(const std::vector<uint8_t>&)> cmd_cb_;
   testing::MockFunction<void(const std::vector<uint8_t>&)> event_cb_;
   testing::MockFunction<void(const std::vector<uint8_t>&)> acl_cb_;
@@ -276,6 +319,10 @@
   WriteAndExpectManyInboundAclDataPackets(sco_data);
 }
 
+TEST_F(H4ProtocolTest, TestMultipleWritesPacketsShortWrites) {
+  WriteAndExpectManyAclDataPacketsDifferentOffsetsShort();
+}
+
 TEST_F(H4ProtocolTest, TestDisconnect) {
   EXPECT_CALL(disconnect_cb_, Call());
   close(chip_uart_fd_);
@@ -332,10 +379,8 @@
 
   void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
 
-  void CallDataReady() override {
-    // The Async test can't call data ready.
-    FAIL();
-  }
+  // Calling CallDataReady() has no effect in the AsyncTest
+  void CallDataReady() override {}
 
   void SendAndReadUartOutbound(PacketType type, char* data) {
     ALOGD("%s sending", __func__);
@@ -434,6 +479,10 @@
   WriteAndExpectManyInboundAclDataPackets(sco_data);
 }
 
+TEST_F(H4ProtocolAsyncTest, TestMultipleWritesPacketsShortWrites) {
+  WriteAndExpectManyAclDataPacketsDifferentOffsetsShort();
+}
+
 TEST_F(H4ProtocolAsyncTest, TestDisconnect) {
   std::promise<void> promise;
   EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 93b5380..b3ca293 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -82,3 +82,15 @@
         "kernel_config_u_6.1",
     ],
 }
+
+vintf_compatibility_matrix {
+    name: "framework_compatibility_matrix.9.xml",
+    stem: "compatibility_matrix.9.xml",
+    srcs: [
+        "compatibility_matrix.9.xml",
+    ],
+    kernel_configs: [
+        "kernel_config_v_5.15",
+        "kernel_config_v_6.1",
+    ],
+}
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 6e4c419..a82a421 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -103,6 +103,7 @@
     framework_compatibility_matrix.6.xml \
     framework_compatibility_matrix.7.xml \
     framework_compatibility_matrix.8.xml \
+    framework_compatibility_matrix.9.xml \
     framework_compatibility_matrix.device.xml \
 
 my_framework_matrix_deps += \
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 188746d..f9b795e 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -1,4 +1,3 @@
-<!-- WARNING: This file is unused in the Android 14 branch. -->
 <compatibility-matrix version="1.0" type="framework" level="9">
     <hal format="hidl" optional="true">
         <name>android.hardware.audio</name>
@@ -493,16 +492,6 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
-        <name>android.hardware.radio.satellite</name>
-        <version>1</version>
-        <interface>
-            <name>IRadioSatellite</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
         <name>android.hardware.radio.ims.media</name>
         <version>1</version>
         <interface>
@@ -510,14 +499,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.renderscript</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.rebootescrow</name>
         <version>1</version>
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index f544d83..89a9e23 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -133,10 +133,6 @@
     ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
 }
 
-TEST_P(ContextHubAidl, TestRegisterNullCallback) {
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), nullptr).isOk());
-}
-
 // Helper callback that puts the async appInfo callback data into a promise
 class QueryAppsCallback : public android::hardware::contexthub::BnContextHubCallback {
   public:
@@ -195,7 +191,6 @@
         GTEST_SKIP() << "Not supported -> old API; or not implemented";
     } else {
         ASSERT_TRUE(status.isOk());
-        ASSERT_FALSE(preloadedNanoappIds.empty());
     }
 }
 
@@ -323,8 +318,6 @@
 
     ASSERT_TRUE(contextHub->onSettingChanged(setting, true /* enabled */).isOk());
     ASSERT_TRUE(contextHub->onSettingChanged(setting, false /* enabled */).isOk());
-
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), nullptr).isOk());
 }
 
 TEST_P(ContextHubAidl, TestOnLocationSettingChanged) {
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index 624d003..ee8b4dc 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
@@ -654,6 +654,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error,
                                      {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
     }
+    // wait until modem reset finishes
+    sleep(10);
     LOG(DEBUG) << "nvResetConfig finished";
 }
 
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index 6ed8e7d..f18da55 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -85,7 +85,7 @@
     // Do not use checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "")
     // until b/148904287 is fixed. We need exact matching instead of partial matching. (i.e.
     // by definition the empty string "" is a substring of any string).
-    return !isDsDsEnabled() && !isTsTsEnabled();
+    return !isDsDsEnabled() && !isTsTsEnabled() && !isDsDaEnabled();
 }
 
 bool isDsDsEnabled() {
@@ -125,8 +125,8 @@
             ALOGI("%s instance is not valid for SSSS device.", serviceName.c_str());
             return false;
         }
-    } else if (isDsDsEnabled()) {
-        // Device is configured as DSDS.
+    } else if (isDsDsEnabled() || isDsDaEnabled()) {
+        // Device is configured as DSDS or DSDA.
         if (!stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME) &&
             !stringEndsWith(serviceName, RADIO_SERVICE_SLOT2_NAME)) {
             ALOGI("%s instance is not valid for DSDS device.", serviceName.c_str());
diff --git a/radio/aidl/vts/radio_data_test.cpp b/radio/aidl/vts/radio_data_test.cpp
index aa6ac88..3eedc14 100644
--- a/radio/aidl/vts/radio_data_test.cpp
+++ b/radio/aidl/vts/radio_data_test.cpp
@@ -531,8 +531,7 @@
 
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_data->rspInfo.error,
-                {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS,
-                 RadioError::REQUEST_NOT_SUPPORTED}));
+                {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -549,8 +548,7 @@
 
     ASSERT_TRUE(
             CheckAnyOfErrors(radioRsp_data->rspInfo.error,
-                             {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                              RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+                             {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
 }
 
 /*
diff --git a/radio/aidl/vts/radio_modem_test.cpp b/radio/aidl/vts/radio_modem_test.cpp
index 3454f33..67747a8 100644
--- a/radio/aidl/vts/radio_modem_test.cpp
+++ b/radio/aidl/vts/radio_modem_test.cpp
@@ -290,6 +290,8 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_modem->rspInfo.error,
                                      {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
     }
+    // wait until modem reset finishes
+    sleep(10);
     LOG(DEBUG) << "nvResetConfig finished";
 }
 
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 57bd4fb..0b7c16e 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -66,12 +66,20 @@
 }
 
 /*
- * Test IRadioNetwork.setAllowedNetworkTypesBitmap for the response returned.
+ * Test IRadioNetwork.setAllowedNetworkTypesBitmap and IRadioNetwork.getAllowedNetworkTypesBitmap
+ * for the response returned.
  */
-TEST_P(RadioNetworkTest, setAllowedNetworkTypesBitmap) {
+TEST_P(RadioNetworkTest, setGetAllowedNetworkTypesBitmap) {
     serial = GetRandomSerialNumber();
-    int32_t allowedNetworkTypesBitmap = static_cast<int32_t>(RadioAccessFamily::LTE);
 
+    // save current value
+    radio_network->getAllowedNetworkTypesBitmap(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    int32_t currentAllowedNetworkTypesBitmap = radioRsp_network->networkTypeBitmapResponse;
+
+    // set new value
+    int32_t allowedNetworkTypesBitmap = static_cast<int32_t>(RadioAccessFamily::LTE);
+    serial = GetRandomSerialNumber();
     radio_network->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap);
 
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -83,20 +91,6 @@
              RadioError::MODE_NOT_SUPPORTED, RadioError::INTERNAL_ERR, RadioError::MODEM_ERR,
              RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED,
              RadioError::NO_RESOURCES}));
-}
-
-/*
- * Test IRadioNetwork.getAllowedNetworkTypesBitmap for the response returned.
- */
-TEST_P(RadioNetworkTest, getAllowedNetworkTypesBitmap) {
-    serial = GetRandomSerialNumber();
-    int32_t allowedNetworkTypesBitmap = static_cast<int32_t>(RadioAccessFamily::LTE);
-
-    radio_network->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap);
-
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
     if (radioRsp_network->rspInfo.error == RadioError::NONE) {
         sleep(3);  // wait for modem
@@ -112,7 +106,16 @@
                  RadioError::OPERATION_NOT_ALLOWED, RadioError::MODE_NOT_SUPPORTED,
                  RadioError::INVALID_ARGUMENTS, RadioError::MODEM_ERR,
                  RadioError::REQUEST_NOT_SUPPORTED, RadioError::NO_RESOURCES}));
+        if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+            // verify we get the value we set
+            ASSERT_EQ(radioRsp_network->networkTypeBitmapResponse, allowedNetworkTypesBitmap);
+        }
     }
+
+    // reset value to previous
+    serial = GetRandomSerialNumber();
+    radio_network->setAllowedNetworkTypesBitmap(serial, currentAllowedNetworkTypesBitmap);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
 }
 
 /*
@@ -947,7 +950,7 @@
     RadioAccessSpecifier specifier850 = {
             .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
 
-    NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
+    NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
                                   .interval = 4,
                                   .specifiers = {specifierP900, specifier850},
                                   .maxSearchTime = 60,
@@ -988,7 +991,7 @@
     RadioAccessSpecifier specifier850 = {
             .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
 
-    NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
+    NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
                                   .interval = 301,
                                   .specifiers = {specifierP900, specifier850},
                                   .maxSearchTime = 60,
@@ -1521,7 +1524,7 @@
     }
 
     // 32 bit system might return invalid mcc and mnc string "\xff\xff..."
-    if (checkMccMnc && mcc.size() < 4 && mnc.size() < 4) {
+    if (checkMccMnc && mcc.size() == 3 && (mnc.size() == 2 || mnc.size() == 3)) {
         int mcc_int = stoi(mcc);
         int mnc_int = stoi(mnc);
         EXPECT_TRUE(mcc_int >= 0 && mcc_int <= 999);
diff --git a/tetheroffload/aidl/Android.bp b/tetheroffload/aidl/Android.bp
index b3b6ebf..6de27c3 100644
--- a/tetheroffload/aidl/Android.bp
+++ b/tetheroffload/aidl/Android.bp
@@ -4,7 +4,6 @@
 
 aidl_interface {
     name: "android.hardware.tetheroffload",
-    owner: "google",
     vendor_available: true,
     srcs: ["android/hardware/tetheroffload/*.aidl"],
     stability: "vintf",
@@ -24,4 +23,12 @@
             apps_enabled: false,
         },
     },
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+    ],
+    frozen: true,
+
 }
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/.hash b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/.hash
new file mode 100644
index 0000000..e7b452e
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/.hash
@@ -0,0 +1 @@
+ba3f0342e13af942628a6c00e920d55ce8ad1ea3
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/ForwardedStats.aidl b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/ForwardedStats.aidl
new file mode 100644
index 0000000..493a698
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/ForwardedStats.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tetheroffload;
+@VintfStability
+parcelable ForwardedStats {
+  long rxBytes;
+  long txBytes;
+}
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/IOffload.aidl b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/IOffload.aidl
new file mode 100644
index 0000000..9a58b1f
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/IOffload.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tetheroffload;
+@VintfStability
+interface IOffload {
+  void initOffload(in ParcelFileDescriptor fd1, in ParcelFileDescriptor fd2, in android.hardware.tetheroffload.ITetheringOffloadCallback cb);
+  void stopOffload();
+  void setLocalPrefixes(in String[] prefixes);
+  android.hardware.tetheroffload.ForwardedStats getForwardedStats(in String upstream);
+  void setDataWarningAndLimit(in String upstream, in long warningBytes, in long limitBytes);
+  void setUpstreamParameters(in String iface, in String v4Addr, in String v4Gw, in String[] v6Gws);
+  void addDownstream(in String iface, in String prefix);
+  void removeDownstream(in String iface, in String prefix);
+  const int ERROR_CODE_UNUSED = 0;
+}
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/IPv4AddrPortPair.aidl b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/IPv4AddrPortPair.aidl
new file mode 100644
index 0000000..2b42f0c
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/IPv4AddrPortPair.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tetheroffload;
+@VintfStability
+parcelable IPv4AddrPortPair {
+  String addr;
+  int port;
+}
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/ITetheringOffloadCallback.aidl b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/ITetheringOffloadCallback.aidl
new file mode 100644
index 0000000..4eb7d04
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/ITetheringOffloadCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tetheroffload;
+@VintfStability
+interface ITetheringOffloadCallback {
+  oneway void onEvent(in android.hardware.tetheroffload.OffloadCallbackEvent event);
+  oneway void updateTimeout(in android.hardware.tetheroffload.NatTimeoutUpdate params);
+}
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/NatTimeoutUpdate.aidl b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/NatTimeoutUpdate.aidl
new file mode 100644
index 0000000..9eddaa2
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/NatTimeoutUpdate.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tetheroffload;
+@VintfStability
+parcelable NatTimeoutUpdate {
+  android.hardware.tetheroffload.IPv4AddrPortPair src;
+  android.hardware.tetheroffload.IPv4AddrPortPair dst;
+  android.hardware.tetheroffload.NetworkProtocol proto;
+}
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/NetworkProtocol.aidl b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/NetworkProtocol.aidl
new file mode 100644
index 0000000..52bd2a6
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/NetworkProtocol.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tetheroffload;
+@Backing(type="int") @VintfStability
+enum NetworkProtocol {
+  TCP = 6,
+  UDP = 17,
+}
diff --git a/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/OffloadCallbackEvent.aidl b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/OffloadCallbackEvent.aidl
new file mode 100644
index 0000000..026e18e
--- /dev/null
+++ b/tetheroffload/aidl/aidl_api/android.hardware.tetheroffload/1/android/hardware/tetheroffload/OffloadCallbackEvent.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tetheroffload;
+@Backing(type="int") @VintfStability
+enum OffloadCallbackEvent {
+  OFFLOAD_STARTED = 1,
+  OFFLOAD_STOPPED_ERROR = 2,
+  OFFLOAD_STOPPED_UNSUPPORTED = 3,
+  OFFLOAD_SUPPORT_AVAILABLE = 4,
+  OFFLOAD_STOPPED_LIMIT_REACHED = 5,
+  OFFLOAD_WARNING_REACHED = 6,
+}