Merge changes from topic "resetUsbPort"

* changes:
  Implement VTS for resetUsbPort and notifyResetUsbPort
  Add resetUsbPort in USB HAL interface
diff --git a/atrace/1.0/default/android.hardware.atrace@1.0-service.rc b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
index 7110b45..31459b4 100644
--- a/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
+++ b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
@@ -14,4 +14,4 @@
     interface android.hardware.atrace@1.0::IAtraceDevice default
     class early_hal
     user system
-    group system
+    group system readtracefs
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 2759801..222fad7 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -53,9 +53,9 @@
 
 TEST_P(AudioHidlDeviceTest, SetConnectedStateInvalidDeviceAddress) {
     doc::test("Check that invalid device address is rejected by IDevice::setConnectedState");
-    EXPECT_RESULT(Result::INVALID_ARGUMENTS,
+    EXPECT_RESULT(invalidArgsOrNotSupported,
                   getDevice()->setConnectedState(getInvalidDeviceAddress(), true));
-    EXPECT_RESULT(Result::INVALID_ARGUMENTS,
+    EXPECT_RESULT(invalidArgsOrNotSupported,
                   getDevice()->setConnectedState(getInvalidDeviceAddress(), false));
 }
 
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
index f035baf..ae57125 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
@@ -34,5 +34,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalAudioV6_0TargetTest" />
+        <option name="native-test-timeout" value="5m" />
     </test>
 </configuration>
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
index 6635f31..55dbaf1 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
@@ -34,5 +34,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalAudioV7_0TargetTest" />
+        <option name="native-test-timeout" value="5m" />
     </test>
 </configuration>
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 29a9cd4..1478381 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -232,8 +232,10 @@
 
   public class ValueType {
     ctor public ValueType();
+    method public int getAndroid_type();
     method public String getLiteral();
     method public int getNumerical();
+    method public void setAndroid_type(int);
     method public void setLiteral(String);
     method public void setNumerical(int);
   }
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 842e724..852ea77 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -190,6 +190,7 @@
     <xs:complexType name="valueType">
         <xs:attribute name="literal" type="xs:string" use="required"/>
         <xs:attribute name="numerical" type="xs:int" use="required"/>
+        <xs:attribute name="android_type" type="xs:int" use="optional"/>
     </xs:complexType>
 
     <xs:complexType name="attributesRefType">
diff --git a/authsecret/aidl/default/service.cpp b/authsecret/aidl/default/service.cpp
index efecf10..a7d8678 100644
--- a/authsecret/aidl/default/service.cpp
+++ b/authsecret/aidl/default/service.cpp
@@ -28,7 +28,7 @@
 
     const std::string instance = std::string() + AuthSecret::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(authsecret->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return -1; // Should never be reached
diff --git a/automotive/audiocontrol/aidl/default/main.cpp b/automotive/audiocontrol/aidl/default/main.cpp
index 9b259fc..cc15ccb 100644
--- a/automotive/audiocontrol/aidl/default/main.cpp
+++ b/automotive/audiocontrol/aidl/default/main.cpp
@@ -31,7 +31,7 @@
     const std::string instance = std::string() + AudioControl::descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(audioControl->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     std::shared_ptr<PowerPolicyClient> powerPolicyClient =
             ::ndk::SharedRefBase::make<PowerPolicyClient>(audioControl);
diff --git a/automotive/can/1.0/tools/libprotocan/Android.bp b/automotive/can/1.0/tools/libprotocan/Android.bp
new file mode 100644
index 0000000..4c23fad
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "libprotocan",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor: true,
+    srcs: [
+        "Checksum.cpp",
+        "MessageCounter.cpp",
+        "MessageDef.cpp",
+        "MessageInjector.cpp",
+        "Signal.cpp",
+    ],
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+    ],
+}
diff --git a/automotive/can/1.0/tools/libprotocan/Checksum.cpp b/automotive/can/1.0/tools/libprotocan/Checksum.cpp
new file mode 100644
index 0000000..72fb0af
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/Checksum.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libprotocan/Checksum.h>
+
+namespace android::hardware::automotive::protocan {
+
+Checksum::Checksum(Signal signal, formula f) : mSignal(signal), mFormula(f) {}
+
+void Checksum::update(can::V1_0::CanMessage& msg) const {
+  mSignal.set(msg, 0);
+  mSignal.set(msg, mFormula(msg) % (mSignal.maxValue + 1));
+}
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/MessageCounter.cpp b/automotive/can/1.0/tools/libprotocan/MessageCounter.cpp
new file mode 100644
index 0000000..ef9882f
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/MessageCounter.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libprotocan/MessageCounter.h>
+
+#include <android-base/logging.h>
+
+namespace android::hardware::automotive::protocan {
+
+/** Whether to log counter state messages. */
+static constexpr bool kSuperVerbose = false;
+
+MessageCounter::MessageCounter(Signal signal) : upperBound(signal.maxValue + 1), mSignal(signal) {}
+
+Signal::value MessageCounter::next() const {
+  CHECK(mCurrent.has_value()) << "Counter not initialized. Did you call isReady?";
+  return (*mCurrent + 1) % upperBound;
+}
+
+void MessageCounter::read(const can::V1_0::CanMessage& msg) {
+    auto val = mSignal.get(msg);
+
+    if (!mCurrent.has_value()) {
+        LOG(VERBOSE) << "Got first counter val of " << val;
+        mCurrent = val;
+        return;
+    }
+
+    auto nextVal = next();
+    if (nextVal == val) {
+        if constexpr (kSuperVerbose) {
+            LOG(VERBOSE) << "Got next counter val of " << nextVal;
+        }
+        mCurrent = nextVal;
+    } else {
+        LOG(DEBUG) << "Ignoring next counter val of " << val << ", waiting for " << nextVal;
+    }
+}
+
+bool MessageCounter::isReady() const { return mCurrent.has_value(); }
+
+void MessageCounter::increment(can::V1_0::CanMessage& msg) {
+  auto newVal = next();
+  mCurrent = newVal;
+  mSignal.set(msg, newVal);
+}
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/MessageDef.cpp b/automotive/can/1.0/tools/libprotocan/MessageDef.cpp
new file mode 100644
index 0000000..23ce1df
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/MessageDef.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libprotocan/MessageDef.h>
+
+#include <android-base/logging.h>
+
+namespace android::hardware::automotive::protocan {
+
+using can::V1_0::CanMessage;
+using can::V1_0::CanMessageId;
+
+MessageDef::MessageDef(CanMessageId id, uint16_t len, std::map<std::string, Signal> signals,
+                       std::optional<Signal> counter, std::optional<Checksum> checksum)
+    : id(id), kLen(len), kSignals(std::move(signals)), kCounter(counter), kChecksum(checksum) {}
+
+const Signal& MessageDef::operator[](const std::string& signalName) const {
+  auto it = kSignals.find(signalName);
+  CHECK(it != kSignals.end()) << "Signal " << signalName << " doesn't exist";
+  return it->second;
+}
+
+CanMessage MessageDef::makeDefault() const {
+  CanMessage msg = {};
+  msg.id = id;
+  msg.payload.resize(kLen);
+
+  for (auto const& [name, signal] : kSignals) {
+    signal.setDefault(msg);
+  }
+
+  return msg;
+}
+
+MessageCounter MessageDef::makeCounter() const {
+  CHECK(kCounter.has_value()) << "Can't build a counter for message without such signal";
+  return MessageCounter(*kCounter);
+}
+
+void MessageDef::updateChecksum(can::V1_0::CanMessage& msg) const {
+  if (!kChecksum.has_value()) return;
+  kChecksum->update(msg);
+}
+
+bool MessageDef::validate(const can::V1_0::CanMessage& msg) const {
+    return msg.payload.size() >= kLen;
+}
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/MessageInjector.cpp b/automotive/can/1.0/tools/libprotocan/MessageInjector.cpp
new file mode 100644
index 0000000..7c45eaa
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/MessageInjector.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libprotocan/MessageInjector.h>
+
+#include <android-base/logging.h>
+
+#include <thread>
+
+namespace android::hardware::automotive::protocan {
+
+/** Whether to log injected messages. */
+static constexpr bool kSuperVerbose = true;
+
+using namespace std::literals::chrono_literals;
+
+using can::V1_0::CanMessage;
+using can::V1_0::CanMessageId;
+using can::V1_0::ICanBus;
+using can::V1_0::Result;
+
+MessageInjector::MessageInjector(MessageDef msgDef,
+                                 std::optional<std::chrono::milliseconds> interMessageDelay)
+    : kMsgDef(std::move(msgDef)),
+      kInterMessageDelay(interMessageDelay),
+      mCounter(msgDef.makeCounter()) {}
+
+void MessageInjector::inject(const CanMessage& msg) { inject({msg}); }
+
+void MessageInjector::inject(const std::initializer_list<can::V1_0::CanMessage> msgs) {
+  std::lock_guard<std::mutex> lock(mMessagesGuard);
+  for (const auto& msg : msgs) {
+    if constexpr (kSuperVerbose) {
+      LOG(VERBOSE) << "Message scheduled for injection: " << toString(msg);
+    }
+
+    mMessages.push(msg);
+  }
+}
+
+void MessageInjector::processQueueLocked(can::V1_0::ICanBus& bus) {
+  if (mMessages.empty() || !mCounter.isReady()) return;
+
+  auto paddingMessagesCount = mCounter.upperBound - (mMessages.size() % mCounter.upperBound);
+  auto padMessage = kMsgDef.makeDefault();
+  for (unsigned i = 0; i < paddingMessagesCount; i++) {
+    mMessages.push(padMessage);
+  }
+
+  while (!mMessages.empty()) {
+    auto&& outMsg = mMessages.front();
+
+    mCounter.increment(outMsg);
+    kMsgDef.updateChecksum(outMsg);
+
+    if constexpr (kSuperVerbose) {
+      LOG(VERBOSE) << "Injecting message: " << toString(outMsg);
+    }
+    auto result = bus.send(outMsg);
+    if (result != Result::OK) {
+      LOG(ERROR) << "Message injection failed: " << toString(result);
+    }
+
+    mMessages.pop();
+
+    // This would block onReceive, but the class is not supposed to be used in production anyway
+    // (see MessageInjector docstring).
+    if (kInterMessageDelay.has_value()) {
+      std::this_thread::sleep_for(*kInterMessageDelay);
+    }
+  }
+}
+
+void MessageInjector::onReceive(ICanBus& bus, const CanMessage& msg) {
+    if (!kMsgDef.validate(msg)) return;
+
+    std::lock_guard<std::mutex> lock(mMessagesGuard);
+
+    mCounter.read(msg);
+    processQueueLocked(bus);
+}
+
+MessageInjectorManager::MessageInjectorManager(
+    std::initializer_list<std::shared_ptr<MessageInjector>> injectors) {
+  std::transform(injectors.begin(), injectors.end(), std::inserter(mInjectors, mInjectors.end()),
+                 [](const std::shared_ptr<MessageInjector>& injector) {
+                   return std::make_pair(injector->kMsgDef.id, std::move(injector));
+                 });
+}
+
+void MessageInjectorManager::onReceive(sp<ICanBus> bus, const CanMessage& msg) {
+  auto it = mInjectors.find(msg.id);
+  if (it == mInjectors.end()) return;
+  it->second->onReceive(*bus, msg);
+}
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/Signal.cpp b/automotive/can/1.0/tools/libprotocan/Signal.cpp
new file mode 100644
index 0000000..bc3e070
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/Signal.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libprotocan/Signal.h>
+
+#include <android-base/logging.h>
+
+namespace android::hardware::automotive::protocan {
+
+static uint8_t calculateLastByteMask(uint16_t start, uint8_t length) {
+  unsigned lastByteBits = (start + length) % 8;
+  unsigned lastBytePadding = (8 - lastByteBits) % 8;
+  return 0xFF >> lastBytePadding;
+}
+
+static uint8_t calculateFirstByteMask(uint16_t firstByte, uint8_t firstBit, uint16_t lastByte,
+                                      uint8_t lastMask) {
+  uint8_t firstMask = 0xFF << firstBit;
+  if (firstByte == lastByte) firstMask &= lastMask;
+  return firstMask;
+}
+
+Signal::Signal(uint16_t start, uint8_t length, value defVal)
+    : maxValue((1u << length) - 1),
+      kFirstByte(start / 8),
+      kFirstBit(start % 8),
+      kFirstByteBits(8 - kFirstBit),
+      kLastByte((start + length - 1) / 8),
+      kLastMask(calculateLastByteMask(start, length)),
+      kFirstMask(calculateFirstByteMask(kFirstByte, kFirstBit, kLastByte, kLastMask)),
+      kDefVal(defVal) {
+  CHECK(length > 0) << "Signal length must not be zero";
+}
+
+Signal::value Signal::get(const can::V1_0::CanMessage& msg) const {
+    CHECK(msg.payload.size() > kLastByte)
+            << "Message is too short. Did you call MessageDef::validate?";
+
+    Signal::value v = 0;
+    if (kLastByte != kFirstByte) v = kLastMask & msg.payload[kLastByte];
+
+    for (int i = kLastByte - 1; i > kFirstByte; i--) {
+        v = (v << 8) | msg.payload[i];
+    }
+
+    return (v << kFirstByteBits) | ((msg.payload[kFirstByte] & kFirstMask) >> kFirstBit);
+}
+
+void Signal::set(can::V1_0::CanMessage& msg, Signal::value val) const {
+  CHECK(msg.payload.size() > kLastByte)
+      << "Signal requires message of length " << (kLastByte + 1)
+      << " which is beyond message length of " << msg.payload.size();
+
+  uint8_t firstByte = val << kFirstBit;
+  val >>= kFirstByteBits;
+
+  msg.payload[kFirstByte] = (msg.payload[kFirstByte] & ~kFirstMask) | (firstByte & kFirstMask);
+
+  for (int i = kFirstByte + 1; i < kLastByte; i++) {
+    msg.payload[i] = val & 0xFF;
+    val >>= 8;
+  }
+
+  if (kLastByte != kFirstByte) {
+    msg.payload[kLastByte] = (msg.payload[kLastByte] & ~kLastMask) | (val & kLastMask);
+  }
+}
+
+void Signal::setDefault(can::V1_0::CanMessage& msg) const { set(msg, kDefVal); }
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/include/libprotocan/Checksum.h b/automotive/can/1.0/tools/libprotocan/include/libprotocan/Checksum.h
new file mode 100644
index 0000000..ff1dc91
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/include/libprotocan/Checksum.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <libprotocan/Signal.h>
+
+namespace android::hardware::automotive::protocan {
+
+class Checksum {
+ public:
+  using formula = std::function<Signal::value(const can::V1_0::CanMessage&)>;
+
+  Checksum(Signal signal, formula f);
+
+  void update(can::V1_0::CanMessage& msg) const;
+
+ private:
+  const Signal mSignal;
+  const formula mFormula;
+};
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageCounter.h b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageCounter.h
new file mode 100644
index 0000000..56113be
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageCounter.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <libprotocan/Signal.h>
+
+namespace android::hardware::automotive::protocan {
+
+class MessageCounter {
+ public:
+  const Signal::value upperBound;
+
+  MessageCounter(Signal signal);
+
+  /**
+   * Parse CAN message sent by external ECU to determine current counter value.
+   */
+  void read(const can::V1_0::CanMessage& msg);
+
+  /**
+   * States whether current counter value is determined.
+   */
+  bool isReady() const;
+
+  /**
+   * Increment current counter value and set it in a new message.
+   *
+   * Caller must check isReady() at least once before calling this method.
+   */
+  void increment(can::V1_0::CanMessage& msg);
+
+ private:
+  const Signal mSignal;
+
+  std::optional<Signal::value> mCurrent = std::nullopt;
+
+  Signal::value next() const;
+};
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageDef.h b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageDef.h
new file mode 100644
index 0000000..79b21e1
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageDef.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <libprotocan/Checksum.h>
+#include <libprotocan/MessageCounter.h>
+#include <libprotocan/Signal.h>
+
+namespace android::hardware::automotive::protocan {
+
+/**
+ * CAN message definition (not the actual message data).
+ *
+ * Describes static message properties (message ID, signals etc).
+ */
+class MessageDef {
+ public:
+  const can::V1_0::CanMessageId id;
+
+  /**
+   * Create message definition.
+   *
+   * Currently only constant length messages are supported.
+   *
+   * \param id CAN message ID
+   * \param len CAN message length
+   * \param signals CAN signal definitions
+   * \param counter Designated CAN signal definition for message counter, if the message has one
+   * \param checksum Designated CAN signal definition for payload checksum, if the message has one
+   */
+  MessageDef(can::V1_0::CanMessageId id, uint16_t len, std::map<std::string, Signal> signals,
+             std::optional<Signal> counter = std::nullopt,
+             std::optional<Checksum> checksum = std::nullopt);
+
+  const Signal& operator[](const std::string& signalName) const;
+
+  can::V1_0::CanMessage makeDefault() const;
+  MessageCounter makeCounter() const;
+
+  void updateChecksum(can::V1_0::CanMessage& msg) const;
+
+  /**
+   * Validate the message payload is large enough to hold all the signals.
+   */
+  bool validate(const can::V1_0::CanMessage& msg) const;
+
+private:
+  const uint16_t kLen;
+  const std::map<std::string, Signal> kSignals;
+  const std::optional<Signal> kCounter;
+  const std::optional<Checksum> kChecksum;
+};
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageInjector.h b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageInjector.h
new file mode 100644
index 0000000..b0ea260
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageInjector.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <libprotocan/MessageCounter.h>
+#include <libprotocan/MessageDef.h>
+#include <utils/Mutex.h>
+
+#include <queue>
+
+namespace android::hardware::automotive::protocan {
+
+class MessageInjectorManager;
+
+/**
+ * Injects CAN messages with a counter to an existing system.
+ *
+ * This class is NOT meant to use in production - there should be no need to inject counted CAN
+ * messages where the other sender is also broadcasting them. If this is the case, it may be a sign
+ * your CAN network needs a redesign. This tool is intended for use for testing and demo purposes.
+ */
+class MessageInjector {
+ public:
+  MessageInjector(MessageDef msgDef, std::optional<std::chrono::milliseconds> interMessageDelay);
+
+  void inject(const can::V1_0::CanMessage& msg);
+  void inject(const std::initializer_list<can::V1_0::CanMessage> msgs);
+
+ private:
+  const MessageDef kMsgDef;
+  const std::optional<std::chrono::milliseconds> kInterMessageDelay;
+  MessageCounter mCounter;
+
+  mutable std::mutex mMessagesGuard;
+  std::queue<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+
+  void onReceive(can::V1_0::ICanBus& bus, const can::V1_0::CanMessage& msg);
+  void processQueueLocked(can::V1_0::ICanBus& bus);
+
+  friend class MessageInjectorManager;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageInjector);
+};
+
+/**
+ * Routes intercepted messages to MessageInjector instances configured to handle specific CAN
+ * message (CAN message ID). Intercepted messages from other nodes in CAN network are used to read
+ * current counter value in order to spoof the next packet.
+ */
+class MessageInjectorManager {
+ public:
+  MessageInjectorManager(std::initializer_list<std::shared_ptr<MessageInjector>> injectors);
+
+  void onReceive(sp<can::V1_0::ICanBus> bus, const can::V1_0::CanMessage& msg);
+
+ private:
+  std::map<can::V1_0::CanMessageId, std::shared_ptr<MessageInjector>> mInjectors;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageInjectorManager);
+};
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/include/libprotocan/Signal.h b/automotive/can/1.0/tools/libprotocan/include/libprotocan/Signal.h
new file mode 100644
index 0000000..7c0f119
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/include/libprotocan/Signal.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+
+namespace android::hardware::automotive::protocan {
+
+/**
+ * TODO(twasilczyk): right now, only Little Endian signals are supported.
+ */
+class Signal {
+ public:
+  using value = uint64_t;
+
+  const value maxValue;
+
+  Signal(uint16_t start, uint8_t length, value defVal = 0);
+
+  value get(const can::V1_0::CanMessage& msg) const;
+  void set(can::V1_0::CanMessage& msg, value val) const;
+  void setDefault(can::V1_0::CanMessage& msg) const;
+
+ private:
+  const uint16_t kFirstByte;     ///< Index of first byte that holds the signal
+  const uint8_t kFirstBit;       ///< Index of first bit within first byte
+  const uint8_t kFirstByteBits;  ///< How many bits of the first byte belong to the signal
+  const uint16_t kLastByte;      ///< Index of last byte that holds the signal
+  const uint8_t kLastMask;       ///< Bits of the last byte that belong to the signal
+  const uint8_t kFirstMask;      ///< Bits of the first byte that belong to the signal
+
+  const value kDefVal;
+};
+
+}  // namespace android::hardware::automotive::protocan
diff --git a/automotive/can/1.0/tools/libprotocan/tests/Android.bp b/automotive/can/1.0/tools/libprotocan/tests/Android.bp
new file mode 100644
index 0000000..251cc06
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/tests/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "libprotocan_signal_test",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor: true,
+    gtest: true,
+    srcs: ["libprotocan_signal_test.cpp"],
+    static_libs: [
+        "libprotocan",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+}
diff --git a/automotive/can/1.0/tools/libprotocan/tests/libprotocan_signal_test.cpp b/automotive/can/1.0/tools/libprotocan/tests/libprotocan_signal_test.cpp
new file mode 100644
index 0000000..19c1209
--- /dev/null
+++ b/automotive/can/1.0/tools/libprotocan/tests/libprotocan_signal_test.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libprotocan/Signal.h>
+
+#include <gtest/gtest.h>
+
+namespace android::hardware::automotive::protocan::unittest {
+
+TEST(SignalTest, TestGetSingleBytes) {
+  can::V1_0::CanMessage msg = {};
+  msg.payload = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  for (unsigned i = 0; i < msg.payload.size(); i++) {
+    Signal signal(8 * i, 8);
+    ASSERT_EQ(i, signal.get(msg));
+  }
+}
+
+TEST(SignalTest, TestSetSingleBytes) {
+  std::vector<can::V1_0::CanMessage> msgs = {{}, {}, {}};
+  msgs[0].payload = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+  msgs[1].payload = {0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB};
+  msgs[2].payload = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  for (unsigned i = 0; i < msgs[0].payload.size(); i++) {
+    Signal signal(8 * i, 8);
+
+    for (auto&& msgOriginal : msgs) {
+      auto msgModified = msgOriginal;
+      signal.set(msgModified, 0xBA);
+
+      auto msgExpected = msgOriginal;
+      msgExpected.payload[i] = 0xBA;
+
+      ASSERT_EQ(msgExpected, msgModified) << "i=" << i;
+    }
+  }
+}
+
+TEST(SignalTest, TestGetStart4) {
+  /* Data generated with Python3:
+   *
+   * from cantools.database.can import *
+   * hex(Message(1, 'm', 4, [Signal('s', 4, 16, byte_order='little_endian')]).
+   *     decode(b'\xde\xad\xbe\xef')['s'])
+   */
+
+  can::V1_0::CanMessage msg = {};
+  msg.payload = {0xDE, 0xAD, 0xBE, 0xEF};
+  can::V1_0::CanMessage msg2 = {};
+  msg2.payload = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD};
+
+  Signal s0_4(0, 4);
+  Signal s4_4(4, 4);
+  Signal s4_8(4, 8);
+  Signal s4_16(4, 16);
+  Signal s4_28(4, 28);
+  Signal s12_8(12, 8);
+  Signal s12_12(12, 12);
+  Signal s12_16(12, 16);
+  Signal s12_20(12, 20);
+  Signal s12_32(12, 32);
+
+  ASSERT_EQ(0xEu, s0_4.get(msg));
+  ASSERT_EQ(0xDu, s4_4.get(msg));
+  ASSERT_EQ(0xDDu, s4_8.get(msg));
+  ASSERT_EQ(0xEADDu, s4_16.get(msg));
+  ASSERT_EQ(0xEFBEADDu, s4_28.get(msg));
+  ASSERT_EQ(0xEAu, s12_8.get(msg));
+  ASSERT_EQ(0xBEAu, s12_12.get(msg));
+  ASSERT_EQ(0xFBEAu, s12_16.get(msg));
+  ASSERT_EQ(0xEFBEAu, s12_20.get(msg));
+  ASSERT_EQ(0xDDEEFBEAu, s12_32.get(msg2));
+}
+
+TEST(SignalTest, TestGet64) {
+  /* Data generated with Python3:
+   *
+   * from cantools.database.can import *
+   * hex(Message(1, 'm', 9, [Signal('s', 4, 64, byte_order='little_endian')]).
+   *     decode(b'\xde\xad\xbe\xef\xab\xbc\xcd\xde\xef')['s'])
+   */
+
+  can::V1_0::CanMessage msg = {};
+  msg.payload = {0xDE, 0xAD, 0xBE, 0xEF, 0xAB, 0xBC, 0xCD, 0xDE, 0xEF};
+
+  Signal s0_64(0, 64);
+  Signal s8_64(8, 64);
+  Signal s4_64(4, 64);
+  Signal s1_64(1, 64);
+
+  ASSERT_EQ(0xDECDBCABEFBEADDEu, s0_64.get(msg));
+  ASSERT_EQ(0xEFDECDBCABEFBEADu, s8_64.get(msg));
+  ASSERT_EQ(0xFDECDBCABEFBEADDu, s4_64.get(msg));
+  ASSERT_EQ(0xEF66DE55F7DF56EFu, s1_64.get(msg));
+}
+
+TEST(SignalTest, TestGetAllStarts) {
+  /* Data generated with Python3:
+   *
+   * from cantools.database.can import *
+   * hex(Message(1, 'm', 6, [Signal('s', 0, 20, byte_order='little_endian')]).
+   *     decode(b'\xde\xad\xbe\xef\xde\xad')['s'])
+   */
+
+  std::map<int, Signal::value> shifts = {
+      {0, 0xEADDEu}, {1, 0xF56EFu}, {2, 0xFAB77u}, {3, 0x7D5BBu}, {4, 0xBEADDu},  {5, 0xDF56Eu},
+      {6, 0xEFAB7u}, {7, 0xF7D5Bu}, {8, 0xFBEADu}, {9, 0x7DF56u}, {10, 0xBEFABu}, {11, 0xDF7D5u},
+  };
+
+  can::V1_0::CanMessage msg = {};
+  msg.payload = {0xDE, 0xAD, 0xBE, 0xEF, 0xCC, 0xCC};
+
+  for (auto const& [start, expected] : shifts) {
+    Signal s(start, 20);
+    ASSERT_EQ(expected, s.get(msg)) << "shift of " << start << " failed";
+  }
+}
+
+TEST(SignalTest, TestSetStart4) {
+  /* Data generated with Python3:
+   *
+   * from cantools.database.can import *
+   * so=4 ; sl=8
+   * md = Message(1, 'm', 4, [Signal('a1', 0, so), Signal('a2', so+sl, 32-so-sl),
+   *     Signal('s', so, sl, byte_order='little_endian')])
+   * m = md.decode(b'\xcc\xcc\xcc\xcc')
+   * m['s'] = 0xDE
+   * binascii.hexlify(md.encode(m)).upper()
+   */
+  typedef struct {
+    int start;
+    int length;
+    Signal::value setValue;
+    hidl_vec<uint8_t> payload;
+  } case_t;
+
+  std::vector<case_t> cases = {
+      {0, 4, 0xDu, {0xCD, 0xCC, 0xCC, 0xCC}},       {4, 4, 0xDu, {0xDC, 0xCC, 0xCC, 0xCC}},
+      {4, 8, 0xDEu, {0xEC, 0xCD, 0xCC, 0xCC}},      {4, 16, 0xDEADu, {0xDC, 0xEA, 0xCD, 0xCC}},
+      {4, 24, 0xDEADBEu, {0xEC, 0xDB, 0xEA, 0xCD}}, {4, 28, 0xDEADBEEu, {0xEC, 0xBE, 0xAD, 0xDE}},
+      {12, 8, 0xDEu, {0xCC, 0xEC, 0xCD, 0xCC}},     {12, 12, 0xDEAu, {0xCC, 0xAC, 0xDE, 0xCC}},
+      {12, 16, 0xDEADu, {0xCC, 0xDC, 0xEA, 0xCD}},  {12, 20, 0xDEADBu, {0xCC, 0xBC, 0xAD, 0xDE}},
+  };
+
+  can::V1_0::CanMessage msg = {};
+  msg.payload = {0xCC, 0xCC, 0xCC, 0xCC};
+
+  for (auto const& tcase : cases) {
+    Signal s(tcase.start, tcase.length);
+
+    can::V1_0::CanMessage expectedMsg = {};
+    expectedMsg.payload = tcase.payload;
+
+    can::V1_0::CanMessage editedMsg = msg;
+    s.set(editedMsg, tcase.setValue);
+
+    ASSERT_EQ(expectedMsg, editedMsg) << " set(" << tcase.start << ", " << tcase.length << ")";
+  }
+}
+
+TEST(SignalTest, TestSetAllStarts) {
+  /* Data generated with Python3:
+   * from cantools.database.can import *
+   * import binascii
+   * import textwrap
+   *
+   * length = 20
+   * for start in range(0, 32 - length):
+   *     signals = [Signal('s', start, length, byte_order='little_endian')]
+   *     if start > 0: signals.append(Signal('a', 0, start, byte_order='little_endian'))
+   *     signals.append(Signal('b', start + length, 32 - start - length,
+   *         byte_order='little_endian'))
+   *
+   *     md = Message(1, 'm', 4, signals)
+   *     m = md.decode(b'\xcc\xcc\xcc\xcc')
+   *     m['s'] = 0xDEADB
+   *     out = binascii.hexlify(md.encode(m)).decode('ascii').upper()
+   *     out = ', '.join(['0x{}'.format(v) for v in textwrap.wrap(out, 2)])
+   *     print('{{ {:d}, {{ {:s} }}}},'.format(start, out))
+   */
+
+  std::map<int, hidl_vec<uint8_t>> shifts = {
+      {0, {0xDB, 0xEA, 0xCD, 0xCC}}, {1, {0xB6, 0xD5, 0xDB, 0xCC}},  {2, {0x6C, 0xAB, 0xF7, 0xCC}},
+      {3, {0xDC, 0x56, 0xEF, 0xCC}}, {4, {0xBC, 0xAD, 0xDE, 0xCC}},  {5, {0x6C, 0x5B, 0xBD, 0xCD}},
+      {6, {0xCC, 0xB6, 0x7A, 0xCF}}, {7, {0xCC, 0x6D, 0xF5, 0xCE}},  {8, {0xCC, 0xDB, 0xEA, 0xCD}},
+      {9, {0xCC, 0xB6, 0xD5, 0xDB}}, {10, {0xCC, 0x6C, 0xAB, 0xF7}}, {11, {0xCC, 0xDC, 0x56, 0xEF}},
+  };
+
+  can::V1_0::CanMessage msg = {};
+  msg.payload = {0xCC, 0xCC, 0xCC, 0xCC};
+
+  for (auto const& [start, expectedPayload] : shifts) {
+    Signal s(start, 20);
+
+    can::V1_0::CanMessage expectedMsg = {};
+    expectedMsg.payload = expectedPayload;
+
+    can::V1_0::CanMessage editedMsg = msg;
+    s.set(editedMsg, 0xDEADB);
+
+    ASSERT_EQ(expectedMsg, editedMsg) << "shift of " << start << " failed";
+  }
+}
+
+}  // namespace android::hardware::automotive::protocan::unittest
diff --git a/automotive/evs/OWNERS b/automotive/evs/OWNERS
index 6fc5024..b973e91 100644
--- a/automotive/evs/OWNERS
+++ b/automotive/evs/OWNERS
@@ -1,3 +1,3 @@
+ankitarora@google.com
 changyeon@google.com
-garysungang@google.com
-haoxiangl@google.com
+jwhpryor@google.com
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
new file mode 100644
index 0000000..3c0aa13
--- /dev/null
+++ b/automotive/evs/aidl/Android.bp
@@ -0,0 +1,51 @@
+// 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.automotive.evs",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/automotive/evs/*.aidl"
+    ],
+    stability: "vintf",
+    imports: [
+        "android.hardware.common-V2",
+        "android.hardware.graphics.common-V3",
+    ],
+    backend: {
+        java: {
+            // android.hardware.graphics.common package is not enabled
+            // for Java backend.
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            vndk: {
+                enabled: false,
+            },
+            min_sdk_version: "29"
+        },
+    },
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/BufferDesc.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/BufferDesc.aidl
new file mode 100644
index 0000000..31acdb8
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/BufferDesc.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.automotive.evs;
+@VintfStability
+parcelable BufferDesc {
+  android.hardware.graphics.common.HardwareBuffer buffer;
+  int pixelSizeBytes;
+  int bufferId;
+  @utf8InCpp String deviceId;
+  long timestamp;
+  byte[] metadata;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraDesc.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraDesc.aidl
new file mode 100644
index 0000000..4dadeb8
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraDesc.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.automotive.evs;
+@VintfStability
+parcelable CameraDesc {
+  @utf8InCpp String id;
+  int vendorFlags;
+  byte[] metadata;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraParam.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraParam.aidl
new file mode 100644
index 0000000..ae4ce77
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraParam.aidl
@@ -0,0 +1,49 @@
+/*
+ * 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.automotive.evs;
+@Backing(type="int") @VintfStability
+enum CameraParam {
+  BRIGHTNESS = 0,
+  CONTRAST = 1,
+  AUTOGAIN = 2,
+  GAIN = 3,
+  AUTO_WHITE_BALANCE = 4,
+  WHITE_BALANCE_TEMPERATURE = 5,
+  SHARPNESS = 6,
+  AUTO_EXPOSURE = 7,
+  ABSOLUTE_EXPOSURE = 8,
+  ABSOLUTE_FOCUS = 9,
+  AUTO_FOCUS = 10,
+  ABSOLUTE_ZOOM = 11,
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatus.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatus.aidl
new file mode 100644
index 0000000..cc066ac
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatus.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.automotive.evs;
+@VintfStability
+parcelable DeviceStatus {
+  @utf8InCpp String id;
+  android.hardware.automotive.evs.DeviceStatusType status;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatusType.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatusType.aidl
new file mode 100644
index 0000000..d0f1d8e
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatusType.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.evs;
+@Backing(type="int") @VintfStability
+enum DeviceStatusType {
+  CAMERA_AVAILABLE = 0,
+  CAMERA_NOT_AVAILABLE = 1,
+  DISPLAY_AVAILABLE = 2,
+  DISPLAY_NOT_AVAILABLE = 3,
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayDesc.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayDesc.aidl
new file mode 100644
index 0000000..4ac029e
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayDesc.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+parcelable DisplayDesc {
+  @utf8InCpp String id;
+  int width;
+  int height;
+  android.hardware.automotive.evs.Rotation orientation;
+  int vendorFlags;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayState.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayState.aidl
new file mode 100644
index 0000000..a5f4309
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayState.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.automotive.evs;
+@Backing(type="int") @VintfStability
+enum DisplayState {
+  NOT_OPEN = 0,
+  NOT_VISIBLE = 1,
+  VISIBLE_ON_NEXT_FRAME = 2,
+  VISIBLE = 3,
+  DEAD = 4,
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventDesc.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventDesc.aidl
new file mode 100644
index 0000000..09b2b9d
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventDesc.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.automotive.evs;
+@VintfStability
+parcelable EvsEventDesc {
+  android.hardware.automotive.evs.EvsEventType aType;
+  @utf8InCpp String deviceId;
+  int[] payload;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventType.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventType.aidl
new file mode 100644
index 0000000..052a6b3
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventType.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.automotive.evs;
+@Backing(type="int") @VintfStability
+enum EvsEventType {
+  STREAM_STARTED = 0,
+  STREAM_STOPPED = 1,
+  FRAME_DROPPED = 2,
+  TIMEOUT = 3,
+  PARAMETER_CHANGED = 4,
+  MASTER_RELEASED = 5,
+  STREAM_ERROR = 6,
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsResult.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsResult.aidl
new file mode 100644
index 0000000..a0418a9
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsResult.aidl
@@ -0,0 +1,48 @@
+/*
+ * 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.automotive.evs;
+@Backing(type="int") @VintfStability
+enum EvsResult {
+  OK = 0,
+  INVALID_ARG = 1,
+  STREAM_ALREADY_RUNNING = 2,
+  BUFFER_NOT_AVAILABLE = 3,
+  OWNERSHIP_LOST = 4,
+  UNDERLYING_SERVICE_ERROR = 5,
+  PERMISSION_DENIED = 6,
+  RESOURCE_NOT_AVAILABLE = 7,
+  RESOURCE_BUSY = 8,
+  NOT_IMPLEMENTED = 9,
+  NOT_SUPPORTED = 10,
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCamera.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCamera.aidl
new file mode 100644
index 0000000..ce1b97d
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCamera.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+interface IEvsCamera {
+  void doneWithFrame(in android.hardware.automotive.evs.BufferDesc[] buffer);
+  void forcePrimaryClient(in android.hardware.automotive.evs.IEvsDisplay display);
+  android.hardware.automotive.evs.CameraDesc getCameraInfo();
+  byte[] getExtendedInfo(in int opaqueIdentifier);
+  int[] getIntParameter(in android.hardware.automotive.evs.CameraParam id);
+  android.hardware.automotive.evs.ParameterRange getIntParameterRange(in android.hardware.automotive.evs.CameraParam id);
+  android.hardware.automotive.evs.CameraParam[] getParameterList();
+  android.hardware.automotive.evs.CameraDesc getPhysicalCameraInfo(in String deviceId);
+  int importExternalBuffers(in android.hardware.automotive.evs.BufferDesc[] buffers);
+  void pauseVideoStream();
+  void resumeVideoStream();
+  void setExtendedInfo(in int opaqueIdentifier, in byte[] opaqueValue);
+  int[] setIntParameter(in android.hardware.automotive.evs.CameraParam id, in int value);
+  void setPrimaryClient();
+  void setMaxFramesInFlight(in int bufferCount);
+  void startVideoStream(in android.hardware.automotive.evs.IEvsCameraStream receiver);
+  void stopVideoStream();
+  void unsetPrimaryClient();
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCameraStream.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCameraStream.aidl
new file mode 100644
index 0000000..6e2e64a
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCameraStream.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.automotive.evs;
+@VintfStability
+interface IEvsCameraStream {
+  oneway void deliverFrame(in android.hardware.automotive.evs.BufferDesc[] buffer);
+  oneway void notify(in android.hardware.automotive.evs.EvsEventDesc event);
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsDisplay.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsDisplay.aidl
new file mode 100644
index 0000000..9b538d4
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsDisplay.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+interface IEvsDisplay {
+  android.hardware.automotive.evs.DisplayDesc getDisplayInfo();
+  android.hardware.automotive.evs.DisplayState getDisplayState();
+  android.hardware.automotive.evs.BufferDesc getTargetBuffer();
+  void returnTargetBufferForDisplay(in android.hardware.automotive.evs.BufferDesc buffer);
+  void setDisplayState(in android.hardware.automotive.evs.DisplayState state);
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumerator.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumerator.aidl
new file mode 100644
index 0000000..a79c68d
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumerator.aidl
@@ -0,0 +1,50 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+interface IEvsEnumerator {
+  void closeCamera(in android.hardware.automotive.evs.IEvsCamera carCamera);
+  void closeDisplay(in android.hardware.automotive.evs.IEvsDisplay display);
+  void closeUltrasonicsArray(in android.hardware.automotive.evs.IEvsUltrasonicsArray evsUltrasonicsArray);
+  android.hardware.automotive.evs.CameraDesc[] getCameraList();
+  byte[] getDisplayIdList();
+  android.hardware.automotive.evs.DisplayState getDisplayState();
+  android.hardware.automotive.evs.Stream[] getStreamList(in android.hardware.automotive.evs.CameraDesc description);
+  android.hardware.automotive.evs.UltrasonicsArrayDesc[] getUltrasonicsArrayList();
+  boolean isHardware();
+  android.hardware.automotive.evs.IEvsCamera openCamera(in String cameraId, in android.hardware.automotive.evs.Stream streamCfg);
+  android.hardware.automotive.evs.IEvsDisplay openDisplay(in byte id);
+  android.hardware.automotive.evs.IEvsUltrasonicsArray openUltrasonicsArray(in String ultrasonicsArrayId);
+  void registerStatusCallback(in android.hardware.automotive.evs.IEvsEnumeratorStatusCallback callback);
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
new file mode 100644
index 0000000..c39a4e8
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+interface IEvsEnumeratorStatusCallback {
+  oneway void deviceStatusChanged(in android.hardware.automotive.evs.DeviceStatus[] status);
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
new file mode 100644
index 0000000..1183ab3
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+interface IEvsUltrasonicsArray {
+  void doneWithDataFrame(in android.hardware.automotive.evs.UltrasonicsDataFrameDesc dataFrameDesc);
+  android.hardware.automotive.evs.UltrasonicsArrayDesc getUltrasonicArrayInfo();
+  void setMaxFramesInFlight(in int bufferCount);
+  void startStream(in android.hardware.automotive.evs.IEvsUltrasonicsArrayStream stream);
+  void stopStream();
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
new file mode 100644
index 0000000..510b0a4
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.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.automotive.evs;
+@VintfStability
+interface IEvsUltrasonicsArrayStream {
+  oneway void deliverDataFrame(in android.hardware.automotive.evs.UltrasonicsDataFrameDesc dataFrameDesc);
+  oneway void notify(in android.hardware.automotive.evs.EvsEventDesc event);
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/ParameterRange.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/ParameterRange.aidl
new file mode 100644
index 0000000..44e9b59
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/ParameterRange.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.automotive.evs;
+@VintfStability
+parcelable ParameterRange {
+  int min;
+  int max;
+  int step;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Rotation.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Rotation.aidl
new file mode 100644
index 0000000..91971fc
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Rotation.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.evs;
+@Backing(type="int") @VintfStability
+enum Rotation {
+  ROTATION_0 = 0,
+  ROTATION_90 = 1,
+  ROTATION_180 = 2,
+  ROTATION_270 = 3,
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/RotationQuaternion.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/RotationQuaternion.aidl
new file mode 100644
index 0000000..d9c8b6e
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/RotationQuaternion.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+parcelable RotationQuaternion {
+  float x;
+  float y;
+  float z;
+  float w;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/SensorPose.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/SensorPose.aidl
new file mode 100644
index 0000000..4ead9ea
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/SensorPose.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.automotive.evs;
+@VintfStability
+parcelable SensorPose {
+  android.hardware.automotive.evs.RotationQuaternion rotation;
+  android.hardware.automotive.evs.Translation translation;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
new file mode 100644
index 0000000..a780412
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+parcelable Stream {
+  int id;
+  android.hardware.automotive.evs.StreamType streamType;
+  int width;
+  int height;
+  android.hardware.graphics.common.PixelFormat format;
+  android.hardware.graphics.common.BufferUsage usage;
+  android.hardware.automotive.evs.Rotation rotation;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/StreamType.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/StreamType.aidl
new file mode 100644
index 0000000..9819c89
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/StreamType.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.automotive.evs;
+@Backing(type="int") @VintfStability
+enum StreamType {
+  OUTPUT = 0,
+  INPUT = 1,
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Translation.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Translation.aidl
new file mode 100644
index 0000000..488d80f
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Translation.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.automotive.evs;
+@VintfStability
+parcelable Translation {
+  float x;
+  float y;
+  float z;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicSensor.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicSensor.aidl
new file mode 100644
index 0000000..23f81f8
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicSensor.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.automotive.evs;
+@VintfStability
+parcelable UltrasonicSensor {
+  android.hardware.automotive.evs.SensorPose pose;
+  float maxRangeMm;
+  float angleOfMeasurement;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
new file mode 100644
index 0000000..4a98875
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.evs;
+@VintfStability
+parcelable UltrasonicsArrayDesc {
+  @utf8InCpp String ultrasonicsArrayId;
+  int maxReadingsPerSensorCount;
+  int maxReceiversCount;
+  android.hardware.automotive.evs.UltrasonicSensor[] sensors;
+}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
new file mode 100644
index 0000000..35ec84b
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.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.automotive.evs;
+@VintfStability
+parcelable UltrasonicsDataFrameDesc {
+  long timestampNs;
+  int id;
+  byte[] transmittersIdList;
+  byte[] receiversIdList;
+  int[] receiversReadingsCountList;
+  android.hardware.common.Ashmem waveformsData;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/BufferDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/BufferDesc.aidl
new file mode 100644
index 0000000..0604abe
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/BufferDesc.aidl
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.graphics.common.HardwareBuffer;
+
+/**
+ * Structure representing an image buffer through our APIs
+ *
+ * In addition to the handle to the graphics memory, we need to retain
+ * the properties of the buffer for easy reference and reconstruction of
+ * an ANativeWindowBuffer object on the remote side of API calls.
+ * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a
+ * texture via eglCreateImageKHR()).
+ */
+@VintfStability
+parcelable BufferDesc {
+    /**
+     * Stable AIDL counter part of AHardwareBuffer.  Please see
+     * hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
+     * for more details.
+     */
+    HardwareBuffer buffer;
+    /**
+     * The size of a pixel in the units of bytes.
+     */
+    int pixelSizeBytes;
+    /**
+     * Opaque value from driver
+     */
+    int bufferId;
+    /**
+     * Unique identifier of the physical camera device that produces this buffer.
+     */
+    @utf8InCpp
+    String deviceId;
+    /**
+     * Time that this buffer is being filled in the units of microseconds and must be
+     * obtained from android::elapsedRealtimeNanos() or its equivalents.
+     */
+    long timestamp;
+    /**
+     * Frame metadata.  This is opaque to EvsManager.
+     */
+    byte[] metadata;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/CameraDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/CameraDesc.aidl
new file mode 100644
index 0000000..2f500a7
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/CameraDesc.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * Structure describing the basic properties of an EVS camera.
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system.
+ */
+@VintfStability
+parcelable CameraDesc {
+    /**
+     * Unique identifier for camera devices.  This may be a path to detected
+     * camera device; for example, "/dev/video0".
+     */
+    @utf8InCpp
+    String id;
+    /**
+     * Opaque value from driver.  Vendor may use this field to store additional
+     * information; for example, sensor and bridge chip id.
+     */
+    int vendorFlags;
+    /**
+     * Store camera metadata such as lens characteristics.
+     */
+    byte[] metadata;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/CameraParam.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/CameraParam.aidl
new file mode 100644
index 0000000..15500b2
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/CameraParam.aidl
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * EVS camera parameter
+ */
+@VintfStability
+@Backing(type="int")
+enum CameraParam {
+    /**
+     * The brightness of image frames
+     */
+    BRIGHTNESS,
+    /**
+     * The contrast of image frames
+     */
+    CONTRAST,
+    /**
+     * Automatic gain/exposure control
+     */
+    AUTOGAIN,
+    /**
+     * Gain control
+     */
+    GAIN,
+    /**
+     * Automatic Whitebalance
+     */
+    AUTO_WHITE_BALANCE,
+    /**
+     * Manual white balance setting as a color temperature in Kelvin.
+     */
+    WHITE_BALANCE_TEMPERATURE,
+    /**
+     * Image sharpness adjustment
+     */
+    SHARPNESS,
+    /**
+     * Auto Exposure Control modes; auto, manual, shutter priority, or
+     * aperture priority.
+     */
+    AUTO_EXPOSURE,
+    /**
+     * Manual exposure time of the camera
+     */
+    ABSOLUTE_EXPOSURE,
+    /**
+     * Sets the focal point of the camera to the specified position.  This
+     * parameter may not be effective when auto focus is enabled.
+     */
+    ABSOLUTE_FOCUS,
+    /**
+     * Enables continuous automatic focus adjustments.
+     */
+    AUTO_FOCUS,
+    /**
+     * Specifies the objective lens focal length as an absolute value.
+     */
+    ABSOLUTE_ZOOM,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatus.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatus.aidl
new file mode 100644
index 0000000..535ace3
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatus.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.DeviceStatusType;
+
+/**
+ * The status of the devices, as sent by EVS HAL through the
+ * IEvsEnumeratorCallback::deviceStatusChanged() call.
+ */
+@VintfStability
+parcelable DeviceStatus {
+    /**
+     * The identifier of a device that has transitioned to a new status.
+     */
+    @utf8InCpp
+    String id;
+    /**
+     * A new status of this device
+     */
+    DeviceStatusType status;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatusType.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatusType.aidl
new file mode 100644
index 0000000..902b31b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatusType.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * The status of the devices available through the EVS
+ */
+@VintfStability
+@Backing(type="int")
+enum DeviceStatusType {
+    /**
+     * A camera device is available and ready to be used.
+     */
+    CAMERA_AVAILABLE,
+    /**
+     * A camera device is not available; e.g. disconnected from the system.
+     */
+    CAMERA_NOT_AVAILABLE,
+    /**
+     * A display device is available and ready to be used.
+     */
+    DISPLAY_AVAILABLE,
+    /**
+     * A display device is not available; e.g. disconnected from the
+     * system.
+     */
+    DISPLAY_NOT_AVAILABLE,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DisplayDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayDesc.aidl
new file mode 100644
index 0000000..0b4243b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayDesc.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.Rotation;
+
+/**
+ * Structure describing the basic properties of an EVS display
+ *
+ * The HAL is responsible for filling out this structure to describe
+ * the EVS display. As an implementation detail, this may be a physical
+ * display or a virtual display that is overlaid or mixed with another
+ * presentation device.
+ */
+@VintfStability
+parcelable DisplayDesc {
+    /**
+     * Unique identifier for the display
+     */
+    @utf8InCpp
+    String id;
+    /**
+     * The width of the display
+     */
+    int width;
+    /**
+     * The height of the display
+     */
+    int height;
+    /**
+     * Counterclock-wise orientation of the display
+     */
+    Rotation orientation;
+    /**
+     * Opaque value from driver.  Vendor may use this field to store additional
+     * information; for example, sensor and bridge chip id.
+     */
+    int vendorFlags;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DisplayState.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayState.aidl
new file mode 100644
index 0000000..c242d2f
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayState.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * States for control of the EVS display
+ *
+ * The DisplayInfo structure describes the basic properties of an EVS display. Any EVS
+ * implementation is required to have one. The HAL is responsible for filling out this
+ * structure to describe the EVS display. As an implementation detail, this may be a
+ * physical display or a virtual display that is overlaid or mixed with another
+ * presentation device.
+ */
+@VintfStability
+@Backing(type="int")
+enum DisplayState {
+    /*
+     * Display has not been requested by any application yet
+     */
+    NOT_OPEN = 0,
+    /*
+     * Display is inhibited
+     */
+    NOT_VISIBLE,
+    /*
+     * Will become visible with next frame
+     */
+    VISIBLE_ON_NEXT_FRAME,
+    /*
+     * Display is currently active
+     */
+    VISIBLE,
+    /*
+     * Driver is in an undefined state.  Interface should be closed.
+     */
+    DEAD,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
new file mode 100644
index 0000000..ebff98f
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.EvsEventType;
+
+/**
+ * Structure that describes informative events occurred during EVS is streaming
+ */
+@VintfStability
+parcelable EvsEventDesc {
+    /**
+     * Type of an informative event
+     */
+    EvsEventType aType;
+    /**
+     * Device identifier
+     */
+    @utf8InCpp
+    String deviceId;
+    /**
+     * Possible additional vendor information that is opaque to the EvsManager
+     */
+    int[] payload;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventType.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventType.aidl
new file mode 100644
index 0000000..3a493af
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventType.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * Types of informative streaming events
+ */
+@VintfStability
+@Backing(type="int")
+enum EvsEventType {
+    /**
+     * Video stream is started
+     */
+    STREAM_STARTED = 0,
+    /**
+     * Video stream is stopped
+     */
+    STREAM_STOPPED,
+    /**
+     * Video frame is dropped
+     */
+    FRAME_DROPPED,
+    /**
+     * Timeout happens
+     */
+    TIMEOUT,
+    /**
+     * Camera parameter is changed; payload contains a changed parameter ID and
+     * its value
+     */
+    PARAMETER_CHANGED,
+    /**
+     * Master role has become available
+     */
+    MASTER_RELEASED,
+    /**
+     * Any other erroneous streaming events
+     */
+    STREAM_ERROR,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/EvsResult.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsResult.aidl
new file mode 100644
index 0000000..c355be3
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsResult.aidl
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * Error codes used in EVS HAL interface.
+ */
+@VintfStability
+@Backing(type="int")
+enum EvsResult {
+    OK = 0,
+    /**
+     * Given arguments are invalid
+     */
+    INVALID_ARG,
+    /**
+     * Requested stream is already running
+     */
+    STREAM_ALREADY_RUNNING,
+    /**
+     * Buffer is not available; e.g. failed to allocate
+     */
+    BUFFER_NOT_AVAILABLE,
+    /**
+     * Ownership has been expired or stolen by other clients
+     */
+    OWNERSHIP_LOST,
+    /**
+     * A dependent service fails to handle a request
+     */
+    UNDERLYING_SERVICE_ERROR,
+    /**
+     * Permission denied
+     */
+    PERMISSION_DENIED,
+    /**
+     * Either the camera or the display is not available
+     */
+    RESOURCE_NOT_AVAILABLE,
+    /**
+     * Device or resource busy
+     */
+    RESOURCE_BUSY,
+    /**
+     * A method is not implemented yet
+     */
+    NOT_IMPLEMENTED,
+    /**
+     * Requested functionality is not supported
+     */
+    NOT_SUPPORTED,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCamera.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCamera.aidl
new file mode 100644
index 0000000..080dd75
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCamera.aidl
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.BufferDesc;
+import android.hardware.automotive.evs.CameraDesc;
+import android.hardware.automotive.evs.CameraParam;
+import android.hardware.automotive.evs.IEvsCameraStream;
+import android.hardware.automotive.evs.IEvsDisplay;
+import android.hardware.automotive.evs.ParameterRange;
+
+/**
+ * Represents a single camera and is the primary interface for capturing images.
+ */
+@VintfStability
+interface IEvsCamera {
+    /**
+     * Returns frames that were delivered to the IEvsCameraStream.
+     *
+     * When done consuming a frame delivered to the IEvsCameraStream
+     * interface, it must be returned to the IEvsCamera for reuse.
+     * A small, finite number of buffers are available (possibly as small
+     * as one), and if the supply is exhausted, no further frames may be
+     * delivered until a buffer is returned.
+     *
+     * @param in buffer Buffers to be returned.
+     */
+    void doneWithFrame(in BufferDesc[] buffer);
+
+    /**
+     * Sets to be the primary client forcibly.
+     *
+     * The client, which owns the display, has a high priority and can take over
+     * a primary client role from other clients without the display.
+     *
+     * @param in display IEvsDisplay handle.  If a given display is in either
+     *                   NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the
+     *                   calling client is considered as the high priority client
+     *                   and therefore allowed to take over a primary client role from
+     *                   existing primary client.
+     * @throws EvsResult::INVALID_ARG if a given display handle is null or invalid states.
+     */
+    void forcePrimaryClient(in IEvsDisplay display);
+
+    /**
+     * Returns the description of this camera.
+     *
+     * @return The description of this camera.  This must be the same value as
+     *         reported by IEvsEnumerator::getCameraList().
+     */
+    CameraDesc getCameraInfo();
+
+    /**
+     * Request driver specific information from the HAL implementation.
+     *
+     * The values allowed for opaqueIdentifier are driver specific,
+     * but no value passed in may crash the driver.
+     *
+     * @param in opaqueIdentifier An unique identifier of the information to
+     *                            request.
+     * @return Requested information.  Zero-size vector is returned if the driver does
+     *         not recognize a given identifier.
+     * @throws EvsResult::INVALID_ARG for any unrecognized opaqueIdentifier.
+     */
+    byte[] getExtendedInfo(in int opaqueIdentifier);
+
+    /**
+     * Retrieves values of given camera parameter.  The driver must report
+     * EvsResult::INVALID_ARG if a request parameter is not supported.
+     *
+     * @param in id The identifier of camera parameter, CameraParam enum.
+     * @return Values of requested camera parameter, the same number of values as
+     *         backing camera devices.
+     * @throws EvsResult::INVALID_ARG for any unrecognized parameter.
+     *        EvsResult::UNDERLYING_SERVICE_ERROR for any other failures.
+     */
+    int[] getIntParameter(in CameraParam id);
+
+    /**
+     * Requests a valid value range of a camera parameter
+     *
+     * @param in id The identifier of camera parameter, CameraParam enum.
+     * @return ParameterRange of a requested CameraParam
+     */
+    ParameterRange getIntParameterRange(in CameraParam id);
+
+    /**
+     * Retrieves a list of parameters this camera supports.
+     *
+     * @return A list of CameraParam that this camera supports.
+     */
+    CameraParam[] getParameterList();
+
+    /**
+     * Returns the description of the physical camera device that backs this
+     * logical camera.
+     *
+     * If a requested device does not either exist or back this logical device,
+     * this method returns a null camera descriptor.  And, if this is called on
+     * a physical camera device, this method is the same as getCameraInfo()
+     * method if a given device ID is matched.  Otherwise, this will return a
+     * null camera descriptor.
+     *
+     * @param in deviceId Physical camera device identifier string.
+     * @return The description of a member physical camera device.
+     *         This must be the same value as reported by IEvsEnumerator::getCameraList().
+     */
+    CameraDesc getPhysicalCameraInfo(in String deviceId);
+
+    /**
+     * Import external buffers to capture frames
+     *
+     * This API must be called with a physical camera device identifier.
+     *
+     * @param in buffers A list of buffers allocated by the caller.  EvsCamera
+     *                   will use these buffers to capture frames, in addition to
+     *                   other buffers already in its buffer pool.
+     * @return The amount of buffer pool size changes after importing given buffers.
+     */
+    int importExternalBuffers(in BufferDesc[] buffers);
+
+    /**
+     * Requests to pause EVS camera stream events.
+     *
+     * Like stopVideoStream(), events may continue to arrive for some time
+     * after this call returns. Delivered frame buffers must be returned.
+     */
+    void pauseVideoStream();
+
+    /**
+     * Requests to resume EVS camera stream.
+     */
+    void resumeVideoStream();
+
+    /**
+     * Send a driver specific value to the HAL implementation.
+     *
+     * This extension is provided to facilitate car specific
+     * extensions, but no HAL implementation may require this call
+     * in order to function in a default state.
+     * INVALID_ARG is returned if the opaqueValue is not meaningful to
+     * the driver implementation.
+     *
+     * @param in opaqueIdentifier An unique identifier of the information to
+     *                            program.
+     *        in opaqueValue A value to program.
+     * @throws EvsResult::INVALID_ARG if this call fails to set a parameter.
+     */
+    void setExtendedInfo(in int opaqueIdentifier, in byte[] opaqueValue);
+
+    /**
+     * Requests to set a camera parameter.
+     *
+     * Only a request from the primary client will be processed successfully.
+     * When this method is called on a logical camera device, it will be forwarded
+     * to each physical device and, if it fails to program any physical device,
+     * it will return an error code with the same number of effective values as
+     * the number of backing camera devices.
+     *
+     * @param in id The identifier of camera parameter, CameraParam enum.
+     * @param in value A desired parameter value.
+     * @return Programmed parameter values.  This may differ from what the client
+     *         gives if, for example, the driver does not support a target parameter.
+     * @throws EvsResult::INVALID_ARG if either the request is not made by the primary
+     *        client, or a requested parameter is not supported.
+     *        EvsResult::UNDERLYING_SERVICE_ERROR if it fails to program a value by any
+     *        other reason.
+     */
+    int[] setIntParameter(in CameraParam id, in int value);
+
+    /**
+     * Requests to be the primary client.
+     *
+     * When multiple clients subscribe to a single camera hardware and one of
+     * them adjusts a camera parameter such as the contrast, it may disturb
+     * other clients' operations.  Therefore, the client must call this method
+     * to be a primary client.  Once it becomes a primary client, it will be able to
+     * change camera parameters until either it dies or explicitly gives up the
+     * role.
+     *
+     * @throws EvsResult::OWNERSHIP_LOST if there is already the primary client.
+     */
+    void setPrimaryClient();
+
+    /**
+     * Specifies the depth of the buffer chain the camera is asked to support.
+     *
+     * Up to this many frames may be held concurrently by the client of IEvsCamera.
+     * If this many frames have been delivered to the receiver without being returned
+     * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse.
+     * It is legal for this call to come at any time, even while streams are already running,
+     * in which case buffers should be added or removed from the chain as appropriate.
+     * If no call is made to this entry point, the IEvsCamera must support at least one
+     * frame by default. More is acceptable.
+     *
+     * @param in bufferCount Number of buffers the client of IEvsCamera may hold concurrently.
+     * @throws EvsResult::BUFFER_NOT_AVAILABLE if the client cannot increase the max frames.
+     *        EvsResult::INVALID_ARG if the client cannot decrease the max frames.
+     *        EvsResult::OWNERSHIP_LOST if we lost an ownership of a target camera.
+     */
+    void setMaxFramesInFlight(in int bufferCount);
+
+    /**
+     * Request to start EVS camera stream from this camera.
+     *
+     * The IEvsCameraStream must begin receiving calls with various events
+     * including new image frame ready until stopVideoStream() is called.
+     *
+     * @param in receiver IEvsCameraStream implementation.
+     * @throws EvsResult::OWNERSHIP_LOST if we lost an ownership of a target camera.
+     *        EvsResult::STREAM_ALREADY_RUNNING if a video stream has been started already.
+     *        EvsResult::BUFFER_NOT_AVAILABLE if it fails to secure a minimum number of
+     *        buffers to run a video stream.
+     *        EvsResult::UNDERLYING_SERVICE_ERROR for all other failures.
+     */
+    void startVideoStream(in IEvsCameraStream receiver);
+
+    /**
+     * Stop the delivery of EVS camera frames.
+     *
+     * Because delivery is asynchronous, frames may continue to arrive for
+     * some time after this call returns. Each must be returned until the
+     * closure of the stream is signaled to the IEvsCameraStream.
+     * This function cannot fail and is simply ignored if the stream isn't running.
+     */
+    void stopVideoStream();
+
+    /**
+     * Retires from the primary client role.
+     *
+     * @throws EvsResult::INVALID_ARG if the caller client is not a primary client.
+     */
+    void unsetPrimaryClient();
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
new file mode 100644
index 0000000..2c2b44c
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.BufferDesc;
+import android.hardware.automotive.evs.EvsEventDesc;
+import android.hardware.graphics.common.HardwareBuffer;
+
+/**
+ * Implemented on client side to receive asynchronous streaming event deliveries.
+ */
+@VintfStability
+oneway interface IEvsCameraStream {
+    /**
+     * Receives calls from the HAL each time video frames is ready for inspection.
+     * Buffer handles received by this method must be returned via calls to
+     * IEvsCamera::doneWithFrame(). When the video stream is stopped via a call
+     * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
+     * some time as the pipeline drains. Each frame must still be returned.
+     * When the last frame in the stream has been delivered, STREAM_STOPPED
+     * event must be delivered.  No further frame deliveries may happen
+     * thereafter.
+     *
+     * A camera device will deliver the same number of frames as number of
+     * backing physical camera devices; it means, a physical camera device
+     * sends always a single frame and a logical camera device sends multiple
+     * frames as many as number of backing physical camera devices.
+     *
+     * @param in buffer Buffer descriptors of delivered image frames.
+     */
+    void deliverFrame(in BufferDesc[] buffer);
+
+    /**
+     * Receives calls from the HAL each time an event happens.
+     *
+     * @param in event EVS event with possible event information.
+     */
+    void notify(in EvsEventDesc event);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsDisplay.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsDisplay.aidl
new file mode 100644
index 0000000..8d57014
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsDisplay.aidl
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.BufferDesc;
+import android.hardware.automotive.evs.DisplayDesc;
+import android.hardware.automotive.evs.DisplayState;
+
+/**
+ * Represents a single display.
+ */
+@VintfStability
+interface IEvsDisplay {
+    /**
+     * Returns the description of this display.
+     *
+     * @return The information of this display including id, current mode, current state,
+     *         and additional vendor-specific information.
+     * @throws EvsResult::UNDERLYING_SERVICE_ERROR if it fails to read a display information.
+     */
+    DisplayDesc getDisplayInfo();
+
+    /**
+     * This call requests the current state of the display
+     *
+     * The HAL implementation should report the actual current state, which might
+     * transiently differ from the most recently requested state. Note, however, that
+     * the logic responsible for changing display states should generally live above
+     * the device layer, making it undesirable for the HAL implementation to spontaneously
+     * change display states.
+     *
+     * @return Current DisplayState of this Display.
+     */
+    DisplayState getDisplayState();
+
+    /**
+     * This call returns a handle to a frame buffer associated with the display.
+     *
+     * @return A handle to a frame buffer.  The returned buffer may be locked and
+     *         written to by software and/or GL.  This buffer must be returned via
+     *         a call to returnTargetBufferForDisplay() even if the display is no
+     *         longer visible.
+     * @throws EvsResult::OWNERSHIP_LOST if a display is in DisplayState::DEAD.
+     *        EvsResult::BUFFER_NOT_AVAILABLE if no buffer is available.
+     *        EvsResult::UNDERLYING_SERVICE_ERROR for any other failures.
+     */
+    BufferDesc getTargetBuffer();
+
+    /**
+     * This call tells the display that the buffer is ready for display.
+     *
+     * The buffer is no longer valid for use by the client after this call.
+     * There is no maximum time the caller may hold onto the buffer before making this
+     * call. The buffer may be returned at any time and in any DisplayState, but all
+     * buffers are expected to be returned before the IEvsDisplay interface is destroyed.
+     *
+     * @param in buffer A buffer handle to the frame that is ready for display.
+     * @throws EvsResult::INVALID_ARG if a given buffer is unknown or invalid.
+     *        EvsResult::OWNERSHIP_LOST if a display is in DisplayState::DEAD.
+     *        EvsResult::UNDERLYING_SERVICE_ERROR for any other failures.
+     */
+    void returnTargetBufferForDisplay(in BufferDesc buffer);
+
+    /**
+     * Clients may set the display state to express their desired state.
+     *
+     * The HAL implementation must gracefully accept a request for any state while in
+     * any other state, although the response may be to defer or ignore the request. The display
+     * is defined to start in the NOT_VISIBLE state upon initialization. The client is
+     * then expected to request the VISIBLE_ON_NEXT_FRAME state, and then begin providing
+     * video. When the display is no longer required, the client is expected to request
+     * the NOT_VISIBLE state after passing the last video frame.
+     * Returns INVALID_ARG if the requested state is not a recognized value.
+     *
+     * @param in state Desired new DisplayState.
+     * @throws EvsResult::INVALID_ARG if a given state is invalid.
+     *        EvsResult::OWNERSHIP_LOST if a display is in DisplayState::DEAD.
+     */
+    void setDisplayState(in DisplayState state);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumerator.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumerator.aidl
new file mode 100644
index 0000000..8e380e0
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumerator.aidl
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.CameraDesc;
+import android.hardware.automotive.evs.DisplayState;
+import android.hardware.automotive.evs.IEvsCamera;
+import android.hardware.automotive.evs.IEvsDisplay;
+import android.hardware.automotive.evs.IEvsEnumeratorStatusCallback;
+import android.hardware.automotive.evs.IEvsUltrasonicsArray;
+import android.hardware.automotive.evs.Stream;
+import android.hardware.automotive.evs.UltrasonicsArrayDesc;
+
+/**
+ * Provides the mechanism for EVS camera and ultrasonics array discovery
+ */
+@VintfStability
+interface IEvsEnumerator {
+    /**
+     * Return the specified IEvsCamera interface as no longer in use
+     *
+     * When the IEvsCamera object is no longer required, it must be released.
+     * NOTE: Video streaming must be cleanly stopped before making this call.
+     *
+     * @param in carCamera EvsCamera object to be closed.
+     * @throws EvsResult::INVALID_ARG if a given camera object is invalid.
+     */
+    void closeCamera(in IEvsCamera carCamera);
+
+    /**
+     * Return the specified IEvsDisplay interface as no longer in use
+     *
+     * When the IEvsDisplay object is no longer required, it must be released.
+     * NOTE: All buffers must have been returned to the display before making this call.
+     *
+     * @param in display EvsDisplay object to be closed.
+     */
+    void closeDisplay(in IEvsDisplay display);
+
+    /**
+     * Return the specified IEvsUltrasonicsArray interface as no longer in use
+     *
+     * When the IEvsUltrasonicsArray object is no longer required, it must be released.
+     * NOTE: Data streaming must be cleanly stopped before making this call.
+     *
+     * @param in evsUltrasonicsArray EvsUltrasonics array object to be closed.
+     */
+    void closeUltrasonicsArray(in IEvsUltrasonicsArray evsUltrasonicsArray);
+
+    /**
+     * Returns a list of all EVS cameras available to the system
+     *
+     * @return A list of cameras availale for EVS service.
+     * @throws EvsResult::PERMISSION_DENIED if the process is not permitted to enumerate
+     *        camera devices.
+     */
+    CameraDesc[] getCameraList();
+
+    /**
+     * Returns a list of all EVS displays available to the system
+     *
+     * @return Identifiers of available displays.
+     */
+    byte[] getDisplayIdList();
+
+    /**
+     * This call requests the current state of the display
+     *
+     * If there is no open display, this returns DisplayState::NOT_OPEN. otherwise, it returns
+     * the actual state of the active display.  This call is replicated on the IEvsEnumerator
+     * interface in order to allow secondary clients to monitor the state of the EVS display
+     * without acquiring exclusive ownership of the display.
+     *
+     * @return Current DisplayState of this Display.
+     * @throws EvsResult::OWNERSHIP_LOST if current display is inactive
+     *        EvsResult::PERMISSION_DENIED if the process is not permitted to do this operation.
+     */
+    DisplayState getDisplayState();
+
+    /**
+     * Return a list of the stream configurations a target camera device supports
+     *
+     * @param in description A target camera descriptor
+     * @return A list of stream configurations supported by a given camera device
+     */
+    Stream[] getStreamList(in CameraDesc description);
+
+    /**
+     * Returns a list of all ultrasonics array available to the system.
+     * Will return an empty vector if ultrasonics is not supported.
+     *
+     * @return A list of ultrasonics available for EVS service.
+     */
+    UltrasonicsArrayDesc[] getUltrasonicsArrayList();
+
+    /**
+     * Tells whether this is EvsManager or HAL implementation.
+     *
+     * @return False for EvsManager implementations and true for all others.
+     */
+    boolean isHardware();
+
+    /**
+     * Gets the IEvsCamera associated with a cameraId from a CameraDesc
+     *
+     * Given a camera's unique cameraId from CameraDesc, returns the
+     * IEvsCamera interface associated with the specified camera. When
+     * done using the camera, the caller may release it by calling closeCamera().
+     *
+     * @param in cameraId  A unique identifier of the camera.
+     * @param in streamCfg A stream configuration the client wants to use.
+     * @return EvsCamera object associated with a given cameraId.
+     *         Returned object would be null if a camera device does not support a
+     *         given stream configuration or is already configured differently by
+     *         another client.
+     * @throws EvsResult::PERMISSION_DENIED if the process is not permitted to use camera
+     *        devices.
+     *        EveResult::INVALID_ARG if it fails to open a camera with a given id.
+     */
+    IEvsCamera openCamera(in String cameraId, in Stream streamCfg);
+
+    /**
+     * Get exclusive access to IEvsDisplay for the system
+     *
+     * There can be more than one EVS display objects for the system and this function
+     * requests access to the display identified by a given ID. If the target EVS display
+     * is not available or is already in use the old instance shall be closed and give
+     * the new caller exclusive access.
+     * When done using the display, the caller may release it by calling closeDisplay().
+     *
+     * @param in id Target display identifier.
+     * @return EvsDisplay object to be used.
+     * @throws EvsResult::INVALID_ARG if no display with a given id exists
+     */
+    IEvsDisplay openDisplay(in byte id);
+
+    /**
+     * Gets the IEvsUltrasonicsArray associated with a ultrasonicsArrayId from a
+     * UltrasonicsDataDesc
+     *
+     * @param in ultrasonicsArrayId A unique identifier of the ultrasonic array.
+     * @return IEvsUltrasonicsArray object associated with a given ultrasonicsArrayId.
+     */
+    IEvsUltrasonicsArray openUltrasonicsArray(in String ultrasonicsArrayId);
+
+    /**
+     * Registers a callback to listen to devices' status changes
+     *
+     * @param in callback IEvsEnumeratorStatusCallback implementation
+     */
+    void registerStatusCallback(in IEvsEnumeratorStatusCallback callback);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
new file mode 100644
index 0000000..26ccf72
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.DeviceStatus;
+
+/**
+ * Implemented on client side to receive asynchronous notifications from
+ * IEvsEnumreator.
+ */
+@VintfStability
+oneway interface IEvsEnumeratorStatusCallback {
+    /**
+     * Receives calls from the HAL each time a status of camera devices is
+     * changed.
+     *
+     * @param in status A list of newly updated device status
+     */
+    void deviceStatusChanged(in DeviceStatus[] status);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
new file mode 100644
index 0000000..40de313
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.IEvsUltrasonicsArrayStream;
+import android.hardware.automotive.evs.UltrasonicsArrayDesc;
+import android.hardware.automotive.evs.UltrasonicsDataFrameDesc;
+
+/**
+ * HAL interface for ultrasonics sensor array.
+ */
+@VintfStability
+interface IEvsUltrasonicsArray {
+    /**
+     * Notifies the UltrasonicsDataDesc is consumed that was received from
+     * IEvsUltrasonicsArrayStream
+     *
+     * @param in dataFrameDesc Ultrasonics data descriptor
+     */
+    void doneWithDataFrame(in UltrasonicsDataFrameDesc dataFrameDesc);
+
+    /**
+     * Returns the ultrasonic sensor array information
+     *
+     * @throws The description of this ultrasonic array. This must be the same
+     *        value as reported by IEvsEnumerator::getUltrasonicsArrayList().
+     */
+    UltrasonicsArrayDesc getUltrasonicArrayInfo();
+
+    /**
+     * Specifies the depth of the buffer chain the ultrasonic sensors is
+     * asked to support
+     *
+     * Up to this many data frames may be held concurrently by the client of IEvsUltrasonicsArray.
+     * If this many frames have been delivered to the receiver without being returned
+     * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse.
+     * It is legal for this call to come at any time, even while streams are already running,
+     * in which case buffers should be added or removed from the chain as appropriate.
+     * If no call is made to this entry point, the IEvsUltrasonicsArray must support at least one
+     * data frame by default. More is acceptable.
+     *
+     * @param in bufferCount Number of buffers the client of IEvsUltrasonicsArray may hold
+     *           concurrently.
+     * @throws EvsResult::INVALID_ARG on invalid bufferCount.
+     */
+    void setMaxFramesInFlight(in int bufferCount);
+
+    /**
+     * Requests to start the stream
+     *
+     * @param in stream Implementation of IEvsUltrasonicsArrayStream.
+     * @throws EvsResult::STREAM_ALREADY_RUNNING if stream is already running
+     */
+    void startStream(in IEvsUltrasonicsArrayStream stream);
+
+    /**
+     * Requests to stop the delivery of the ultrasonic array data frames
+     *
+     * Because delivery is asynchronous, frames may continue to arrive for
+     * some time after this call returns. Each must be returned until the
+     * closure of the stream is signaled to the IEvsCameraStream.
+     * This function cannot fail and is ignored if the stream isn't running.
+     */
+    void stopStream();
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
new file mode 100644
index 0000000..bc31a6b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.EvsEventDesc;
+import android.hardware.automotive.evs.UltrasonicsDataFrameDesc;
+
+/**
+ * Implemented on client side to receive asynchronous ultrasonic data
+ * deliveries.
+ */
+@VintfStability
+interface IEvsUltrasonicsArrayStream {
+    /**
+     * Receives calls from the HAL each time a data frame is ready
+     *
+     * @param in dataFrameDesc Ultrasonic array data frame descriptor
+     */
+    oneway void deliverDataFrame(in UltrasonicsDataFrameDesc dataFrameDesc);
+
+    /**
+     * Receives calls from the HAL each time an event happens
+     *
+     * @param in event Event EVS event with possible event information
+     */
+    oneway void notify(in EvsEventDesc event);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/ParameterRange.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/ParameterRange.aidl
new file mode 100644
index 0000000..b08fcbd
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/ParameterRange.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * Represent a valid range of CameraParam
+ */
+@VintfStability
+parcelable ParameterRange {
+    /**
+     * Lower bound of a valid value range
+     */
+    int min;
+    /**
+     * Upper bound of a valid value range
+     */
+    int max;
+    /**
+     * A value of unit increment
+     */
+    int step;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/Rotation.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/Rotation.aidl
new file mode 100644
index 0000000..dede39e
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/Rotation.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * Rotation:
+ *
+ * The required counterclockwise rotation of EVS camera stream and display.
+ */
+@VintfStability
+@Backing(type="int")
+enum Rotation {
+    /** No rotation */
+    ROTATION_0 = 0,
+    /** Rotate by 90 degree counterclockwise */
+    ROTATION_90 = 1,
+    /** Rotate by 180 degree counterclockwise */
+    ROTATION_180 = 2,
+    /** Rotate by 270 degree counterclockwise */
+    ROTATION_270 = 3
+
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/RotationQuaternion.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/RotationQuaternion.aidl
new file mode 100644
index 0000000..b80343b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/RotationQuaternion.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * Structure for rotation expressed as quaternions.
+ * Convention used: Unit quaternion with hamilton convention.
+ */
+@VintfStability
+parcelable RotationQuaternion {
+    float x;
+    float y;
+    float z;
+    float w;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/SensorPose.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/SensorPose.aidl
new file mode 100644
index 0000000..26c3339
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/SensorPose.aidl
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.RotationQuaternion;
+import android.hardware.automotive.evs.Translation;
+
+/**
+ * Provides the orientation and location of a car sensor relative to the android automotive
+ * coordinate system:
+ * https://source.android.com/devices/sensors/sensor-types#auto_axes
+ * The sensor pose defines the transformation to be applied to the android automotive axes to
+ * obtain the sensor local axes.
+ * The pose consists of rotation, (specified as a quaternions) and translation
+ * (vector with x, y, z).
+ * This rotation and translation applied to the sensor data in the sensor's local coordinate
+ * system transform the data to the automotive coordinate system.
+ * i.e.  loc =  ( Rot * Psensor ) + Trans
+ * Here loc is a point in automotive coordinate system and Psensor is a point in the sensor's
+ * coordinate system.
+ * Example:
+ * For a sensor on the front bumper and on the left corner of the car with its X axis pointing to
+ * the front, the sensor is located at (-2, 4, 0) meters w.r.t android automotive axes and the
+ * sensor local axes has a rotation of 90 degrees counter-clockwise w.r.t android automotive axes
+ * when viewing the car from top on the +Z axis side:
+ *
+ *      ↑X sensor
+ *    Y←∘______
+ *      |      |  front
+ *      | car  |
+ *      |  ↑Y  |
+ *      |  ∘→X |  rear
+ *      |______|
+ *
+ * For this example the rotation and translation will be:
+ * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion.
+ * Translation = (-2, 4, 0) in meters = (-2000, 4000, 0) in milli-meters.
+ * Note: Every sensor type must specify its own pose.
+ */
+@VintfStability
+parcelable SensorPose {
+    /**
+     * Rotation part of the sensor pose, expressed as a unit quaternion.
+     */
+    RotationQuaternion rotation;
+    /**
+     * Translation part of the sensor pose, in (x, y, z) format with milli-meter units.
+     */
+    Translation translation;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl
new file mode 100644
index 0000000..ae5c7f0
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.Rotation;
+import android.hardware.automotive.evs.StreamType;
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+/**
+ * Stream:
+ *
+ * Structure that describes a EVS Camera stream
+ */
+@VintfStability
+parcelable Stream {
+    /**
+     * Stream ID - a non-negative integer identifier for a stream.
+     *
+     * The identical stream ID must reference the same stream, with the same
+     * width/height/format, across consecutive calls to configureStreams.
+     *
+     * If previously-used stream ID is not used in a new call to
+     * configureStreams, then that stream is no longer active. Such a stream ID
+     * may be reused in a future configureStreams with a new
+     * width/height/format.
+     *
+     */
+    int id;
+    /**
+     * The type of the stream (input vs output, etc).
+     */
+    StreamType streamType;
+    /**
+     * The width in pixels of the buffers in this stream.
+     */
+    int width;
+    /**
+     * The height in pixels of the buffers in this stream.
+     */
+    int height;
+    /**
+     * The frame rate of this stream in frames-per-second
+     /
+    int framerate;
+    /**
+     * The pixel format form the buffers in this stream.
+     */
+    PixelFormat format;
+    /**
+     * The gralloc usage flags for this stream, as needed by the consumer of
+     * the stream.
+     */
+    BufferUsage usage;
+    /**
+     * The required output rotation of the stream.
+     *
+     * This must be inspected by HAL along with stream with and height.
+     */
+    Rotation rotation;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/StreamType.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/StreamType.aidl
new file mode 100644
index 0000000..c028a5c
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/StreamType.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * StreamType:
+ *
+ * The type of the camera stream, which defines whether the EVS client device is
+ * the producer or the consumer for that stream, and how the buffers of the
+ * stream relate to the other streams.
+ */
+@VintfStability
+@Backing(type="int")
+enum StreamType {
+    /**
+     * This stream is an output stream; the EVS HAL device must fill buffers
+     * from this stream with newly captured or reprocessed image data.
+     */
+    OUTPUT = 0,
+
+    /**
+     * This stream is an input stream; the EVS HAL device must read buffers
+     * from this stream and send them through the camera processing pipeline,
+     * as if the buffer was a newly captured image from the imager.
+     */
+    INPUT = 1
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/Translation.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/Translation.aidl
new file mode 100644
index 0000000..14b14db
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/Translation.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+/**
+ * Structure for translation with x, y and z units.
+ */
+@VintfStability
+parcelable Translation {
+    float x;
+    float y;
+    float z;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicSensor.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicSensor.aidl
new file mode 100644
index 0000000..712411b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicSensor.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.SensorPose;
+
+/**
+ * Structure that contains all information of an ultrasonic sensor.
+ */
+@VintfStability
+parcelable UltrasonicSensor {
+    /**
+     * Pose provides the orientation and location of the ultrasonic sensor within the car.
+     * The +Y axis points along the center of the beam spread the X axis to the right and the Z
+     * axis in the up direction.
+     */
+    SensorPose pose;
+    /**
+     * Maximum range of the sensor in milli-metres.
+     */
+    float maxRangeMm;
+    /**
+     * Half-angle of the angle of measurement of the sensor, relative to the
+     * sensor’s x axis, in radians.
+     */
+    float angleOfMeasurement;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
new file mode 100644
index 0000000..d4f0663
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.automotive.evs.UltrasonicSensor;
+
+/**
+ * Structure identifies and describes an ultrasonics array in the car.
+ *
+ * A ultrasonics array represents a group of ultrasonic sensors within the
+ * car. These may be sensors that are physically connected to the same hardware
+ * control unit or represent a logical group of sensors like front and back.
+ * The HAL is responsible for filling out this structure for each Ultrasonics
+ * Array.
+ */
+@VintfStability
+parcelable UltrasonicsArrayDesc {
+    /**
+     * Unique identifier for the ultrasonic array. This may be a path or name of the
+     * physical control device or a string identifying a logical group of sensors forming an array
+     * such as "front_array" and "back_array".
+     */
+    @utf8InCpp
+    String ultrasonicsArrayId;
+    /**
+     * Maximum number of readings (points on waveform) provided per sensor in
+     * each data frame. Used by client to pre-allocate required memory buffer for
+     * incoming data.
+     */
+    int maxReadingsPerSensorCount;
+    /**
+     * Maximum number of receiver sensors in a data frame. Must be between 1
+     * and sensorCount. Used by client to pre-allocate required memory buffer for
+     * incoming data.
+     */
+    int maxReceiversCount;
+    /**
+     * The order of sensors specified must be in clockwise order around the car, starting
+     * from front left-most sensor.
+     */
+    UltrasonicSensor[] sensors;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
new file mode 100644
index 0000000..e546db9
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.evs;
+
+import android.hardware.common.Ashmem;
+
+/**
+ * Structure that describes the data frame received from an ultrasonics array.
+ *
+ * Each data frame returned consists of received waveform signals from a subset
+ * of sensors in an array as indicated by the receiversIdList. The signal is
+ * transmitted at a particular time instant indicated by timestampNs from a
+ * subset of sensors in the array as provided in the transmittersIdList.
+ */
+@VintfStability
+parcelable UltrasonicsDataFrameDesc {
+    /**
+     * Timestamp of the start of the transmit signal for this data frame.
+     * Timestamp unit is nanoseconds and is obtained from android::elapsedRealtimeNanos().
+     * timeOfFlight readings are future-deltas to this timestamp.
+     */
+    long timestampNs;
+    /**
+     * Identifier of data frame. Used by implementation for managing multiple frames in flight.
+     */
+    int id;
+    /**
+     * List of indexes of sensors in range [0, sensorCount - 1] that
+     * transmitted the signal for this data frame.
+     */
+    byte[] transmittersIdList;
+    /**
+     * List of indexes of sensors in range [0, sensorCount - 1] that received
+     * the signal. The order of ids must match the order of the waveforms in the
+     * waveformsData.
+     * Size of list is upper bound by maxReceiversCount.
+     */
+    byte[] receiversIdList;
+    /**
+     * List of the number of readings corresponding to each ultrasonics sensor in
+     * the receiversIdList. Order of the readings count must match the order in
+     * receiversIdList.
+     * Size of list is upper bound by maxReadingsPerSensorCount.
+     */
+    int[] receiversReadingsCountList;
+    /**
+     * Shared memory object containing the waveforms data. Contains one waveform
+     * for each sensor specified in receiversIdList, in order.
+     * Each waveform is represented by a number of readings, which are sample
+     * points on the waveform. The number of readings for each waveform is as
+     * specified in the receiversReadingsCountList.
+     * Each reading is a pair of time Of flight and resonance.
+     * Time of flight (float): Time between transmit and receive signal in nanoseconds.
+     * Resonance (float): Resonance at time on waveform in range [0.0, 1.0].
+     *
+     * The structure of shared memory (example with 2 waveforms, each with 2 readings):
+     *
+     * Byte: |   0    |  1-4  |  5-8  | 9-12  | 13-16 ||   17   |  18-21 | 22-25  | 26-29 | 30-33 |
+     * Data: | RecId1 | TOF1  | RES1  | TOF2  | RES2  || RecId2 |  TOF1  |  RES1  | TOF2  | RES2  |
+     *       |              Waveform1                 ||             Waveform2                    |
+     * Here:
+     * RecId : Receiver's Id. Order matches the receiversIdList, type uint8_t
+     * TOF : Time of flight, type float (4 bytes)
+     * RES : Resonance, type float (4 bytes)
+     * Note: All readings and waveforms are contigious with no padding.
+     */
+    Ashmem waveformsData;
+}
diff --git a/automotive/evs/aidl/impl/Android.bp b/automotive/evs/aidl/impl/Android.bp
new file mode 100644
index 0000000..7eb0116
--- /dev/null
+++ b/automotive/evs/aidl/impl/Android.bp
@@ -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.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+    name: "EvsHalDefaults",
+    static_libs: [
+        "android.hardware.automotive.evs-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.graphics.common-V3-ndk",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+    ],
+}
diff --git a/automotive/evs/aidl/impl/default/Android.bp b/automotive/evs/aidl/impl/default/Android.bp
new file mode 100644
index 0000000..dbe0314
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/Android.bp
@@ -0,0 +1,36 @@
+// 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.automotive.evs-aidl-default-service",
+    defaults: ["EvsHalDefaults"],
+    local_include_dirs: ["include"],
+    vintf_fragments: ["evs-default-service.xml"],
+    init_rc: ["evs-default-service.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: ["src/*.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+}
diff --git a/automotive/evs/aidl/impl/default/evs-default-service.rc b/automotive/evs/aidl/impl/default/evs-default-service.rc
new file mode 100644
index 0000000..ea8e689
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/evs-default-service.rc
@@ -0,0 +1,5 @@
+service vendor.evs-hal-default /vendor/bin/hw/android.hardware.automotive.evs-aidl-default-service
+    class early_hal
+    user automotive_evs
+    group automotive_evs
+    disabled
diff --git a/automotive/evs/aidl/impl/default/evs-default-service.xml b/automotive/evs/aidl/impl/default/evs-default-service.xml
new file mode 100644
index 0000000..96ff9f6
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/evs-default-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.automotive.evs</name>
+        <transport>hwbinder</transport>
+        <version>1</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>hw/0</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/evs/aidl/impl/default/include/DefaultEvsEnumerator.h b/automotive/evs/aidl/impl/default/include/DefaultEvsEnumerator.h
new file mode 100644
index 0000000..8bcd867
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/DefaultEvsEnumerator.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_automotive_evs_aidl_impl_evshal_include_DefaultEvsHal_H_
+#define android_hardware_automotive_evs_aidl_impl_evshal_include_DefaultEvsHal_H_
+
+#include <aidl/android/hardware/automotive/evs/BnEvsEnumerator.h>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class DefaultEvsEnumerator final
+    : public ::aidl::android::hardware::automotive::evs::BnEvsEnumerator {
+    ::ndk::ScopedAStatus isHardware(bool* flag) override;
+    ::ndk::ScopedAStatus openCamera(
+            const std::string& cameraId,
+            const ::aidl::android::hardware::automotive::evs::Stream& streamConfig,
+            std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera>* obj) override;
+    ::ndk::ScopedAStatus closeCamera(
+            const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera>& obj)
+            override;
+    ::ndk::ScopedAStatus getCameraList(
+            std::vector<::aidl::android::hardware::automotive::evs::CameraDesc>* list) override;
+    ::ndk::ScopedAStatus getStreamList(
+            const ::aidl::android::hardware::automotive::evs::CameraDesc& desc,
+            std::vector<::aidl::android::hardware::automotive::evs::Stream>* _aidl_return) override;
+    ::ndk::ScopedAStatus openDisplay(
+            int8_t displayId,
+            std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>* obj) override;
+    ::ndk::ScopedAStatus closeDisplay(
+            const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>& obj)
+            override;
+    ::ndk::ScopedAStatus getDisplayIdList(std::vector<uint8_t>* list) override;
+    ::ndk::ScopedAStatus getDisplayState(
+            ::aidl::android::hardware::automotive::evs::DisplayState* state) override;
+    ::ndk::ScopedAStatus registerStatusCallback(
+            const std::shared_ptr<
+                    ::aidl::android::hardware::automotive::evs::IEvsEnumeratorStatusCallback>&
+                    callback) override;
+    ::ndk::ScopedAStatus openUltrasonicsArray(
+            const std::string& id,
+            std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>* obj)
+            override;
+    ::ndk::ScopedAStatus closeUltrasonicsArray(
+            const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>&
+                    arr) override;
+    ::ndk::ScopedAStatus getUltrasonicsArrayList(
+            std::vector<::aidl::android::hardware::automotive::evs::UltrasonicsArrayDesc>* list)
+            override;
+};
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
+
+#endif  // android_hardware_automotive_evs_aidl_impl_evshal_include_DefaultEvsHal_H_
diff --git a/automotive/evs/aidl/impl/default/src/DefaultEvsEnumerator.cpp b/automotive/evs/aidl/impl/default/src/DefaultEvsEnumerator.cpp
new file mode 100644
index 0000000..2ff6d59
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/DefaultEvsEnumerator.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+// TODO(b/203661081): Remove below lines to disable compiler warnings.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+
+#define LOG_TAG "DefaultEvsEnumerator"
+
+#include <DefaultEvsEnumerator.h>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+using ::ndk::ScopedAStatus;
+
+ScopedAStatus DefaultEvsEnumerator::isHardware(bool* flag) {
+    // This returns true always.
+    *flag = true;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::openCamera(const std::string& cameraId,
+                                               const Stream& streamConfig,
+                                               std::shared_ptr<IEvsCamera>* obj) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::closeCamera(const std::shared_ptr<IEvsCamera>& obj) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getCameraList(std::vector<CameraDesc>* list) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getStreamList(const CameraDesc& desc,
+                                                  std::vector<Stream>* _aidl_return) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::openDisplay(int8_t displayId,
+                                                std::shared_ptr<IEvsDisplay>* obj) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::closeDisplay(const std::shared_ptr<IEvsDisplay>& state) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getDisplayIdList(std::vector<uint8_t>* list) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getDisplayState(DisplayState* state) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::registerStatusCallback(
+        const std::shared_ptr<IEvsEnumeratorStatusCallback>& callback) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::openUltrasonicsArray(
+        const std::string& id, std::shared_ptr<IEvsUltrasonicsArray>* obj) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::closeUltrasonicsArray(
+        const std::shared_ptr<IEvsUltrasonicsArray>& obj) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getUltrasonicsArrayList(
+        std::vector<UltrasonicsArrayDesc>* list) {
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
+
+#pragma clang diagnostic pop
diff --git a/automotive/evs/aidl/impl/default/src/service.cpp b/automotive/evs/aidl/impl/default/src/service.cpp
new file mode 100644
index 0000000..0a0913f
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/service.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "EvsService"
+
+#include <DefaultEvsEnumerator.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+using ::aidl::android::hardware::automotive::evs::implementation::DefaultEvsEnumerator;
+
+int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
+    std::shared_ptr<DefaultEvsEnumerator> vhal = ndk::SharedRefBase::make<DefaultEvsEnumerator>();
+
+    ALOGI("Registering as service...");
+    binder_exception_t err =
+            AServiceManager_addService(vhal->asBinder().get(), "android.hardware.automotive.evs");
+    if (err != EX_NONE) {
+        ALOGE("failed to register android.hardware.automotive.evs service, exception: %d", err);
+        return 1;
+    }
+
+    if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+        ALOGE("%s", "failed to set thread pool max thread count");
+        return 1;
+    }
+    ABinderProcess_startThreadPool();
+
+    ALOGI("Evs Service Ready");
+
+    ABinderProcess_joinThreadPool();
+
+    ALOGI("Evs Service Exiting");
+
+    return 0;
+}
diff --git a/automotive/evs/aidl/vts/Android.bp b/automotive/evs/aidl/vts/Android.bp
new file mode 100644
index 0000000..980c6d5
--- /dev/null
+++ b/automotive/evs/aidl/vts/Android.bp
@@ -0,0 +1,53 @@
+//
+// 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.
+//
+
+package{
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses : ["hardware_interfaces_license"],
+}
+
+cc_test {
+name:
+    "VtsHalEvsTargetTest",
+    srcs: [
+        "*.cpp",
+    ],
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcamera_metadata",
+        "libui",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@common-default-lib",
+        "android.hardware.automotive.evs-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.graphics.common-V3-ndk",
+        "libaidlcommonsupport",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/automotive/evs/aidl/vts/FrameHandler.cpp b/automotive/evs/aidl/vts/FrameHandler.cpp
new file mode 100644
index 0000000..bab832b
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandler.cpp
@@ -0,0 +1,358 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+
+#include "FrameHandler.h"
+#include "FormatConvert.h"
+
+#include <aidl/android/hardware/graphics/common/HardwareBufferDescription.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+
+using ::aidl::android::hardware::automotive::evs::BufferDesc;
+using ::aidl::android::hardware::automotive::evs::CameraDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::IEvsCamera;
+using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
+using ::aidl::android::hardware::graphics::common::HardwareBufferDescription;
+using ::ndk::ScopedAStatus;
+using std::chrono_literals::operator""s;
+
+FrameHandler::FrameHandler(const std::shared_ptr<IEvsCamera>& pCamera, const CameraDesc& cameraInfo,
+                           const std::shared_ptr<IEvsDisplay>& pDisplay, BufferControlFlag mode)
+    : mCamera(pCamera), mCameraInfo(cameraInfo), mDisplay(pDisplay), mReturnMode(mode) {
+    // Nothing but member initialization here.
+}
+
+void FrameHandler::shutdown() {
+    // Make sure we're not still streaming
+    blockingStopStream();
+
+    // At this point, the receiver thread is no longer running, so we can safely drop
+    // our remote object references so they can be freed
+    mCamera = nullptr;
+    mDisplay = nullptr;
+}
+
+bool FrameHandler::startStream() {
+    // Tell the camera to start streaming
+    auto status = mCamera->startVideoStream(ref<FrameHandler>());
+    if (!status.isOk()) {
+        return false;
+    }
+
+    // Mark ourselves as running
+    mLock.lock();
+    mRunning = true;
+    mLock.unlock();
+
+    return true;
+}
+
+void FrameHandler::asyncStopStream() {
+    // Tell the camera to stop streaming.
+    // This will result in a null frame being delivered when the stream actually stops.
+    mCamera->stopVideoStream();
+}
+
+void FrameHandler::blockingStopStream() {
+    // Tell the stream to stop
+    asyncStopStream();
+
+    // Wait until the stream has actually stopped
+    std::unique_lock<std::mutex> lock(mEventLock);
+    if (mRunning) {
+        mEventSignal.wait(lock, [this]() { return !mRunning; });
+    }
+}
+
+bool FrameHandler::returnHeldBuffer() {
+    std::lock_guard<std::mutex> lock(mLock);
+
+    // Return the oldest buffer we're holding
+    if (mHeldBuffers.empty()) {
+        // No buffers are currently held
+        return false;
+    }
+
+    std::vector<BufferDesc> buffers = std::move(mHeldBuffers.front());
+    mHeldBuffers.pop();
+    mCamera->doneWithFrame(buffers);
+
+    return true;
+}
+
+bool FrameHandler::isRunning() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return mRunning;
+}
+
+void FrameHandler::waitForFrameCount(unsigned frameCount) {
+    // Wait until we've seen at least the requested number of frames (could be more)
+    std::unique_lock<std::mutex> lock(mLock);
+    mFrameSignal.wait(lock, [this, frameCount]() { return mFramesReceived >= frameCount; });
+}
+
+void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
+    std::lock_guard<std::mutex> lock(mLock);
+
+    if (received) {
+        *received = mFramesReceived;
+    }
+    if (displayed) {
+        *displayed = mFramesDisplayed;
+    }
+}
+
+ScopedAStatus FrameHandler::deliverFrame(const std::vector<BufferDesc>& buffers) {
+    mLock.lock();
+    // For VTS tests, FrameHandler uses a single frame among delivered frames.
+    auto bufferIdx = mFramesDisplayed % buffers.size();
+    auto& buffer = buffers[bufferIdx];
+    mLock.unlock();
+
+    // Store a dimension of a received frame.
+    mFrameWidth = buffer.buffer.description.width;
+    mFrameHeight = buffer.buffer.description.height;
+
+    // If we were given an opened display at construction time, then send the received
+    // image back down the camera.
+    bool displayed = false;
+    if (mDisplay) {
+        // Get the output buffer we'll use to display the imagery
+        BufferDesc tgtBuffer;
+        auto status = mDisplay->getTargetBuffer(&tgtBuffer);
+        if (!status.isOk()) {
+            printf("Didn't get target buffer - frame lost\n");
+            LOG(ERROR) << "Didn't get requested output buffer -- skipping this frame.";
+        } else {
+            // Copy the contents of the of buffer.memHandle into tgtBuffer
+            copyBufferContents(tgtBuffer, buffer);
+
+            // Send the target buffer back for display
+            auto status = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+            if (!status.isOk()) {
+                printf("AIDL error on display buffer (%d)- frame lost\n",
+                       status.getServiceSpecificError());
+                LOG(ERROR) << "Error making the remote function call.  AIDL said "
+                           << status.getServiceSpecificError();
+            } else {
+                // Everything looks good!
+                // Keep track so tests or watch dogs can monitor progress
+                displayed = true;
+            }
+        }
+    }
+
+    mLock.lock();
+    // increases counters
+    ++mFramesReceived;
+    mFramesDisplayed += (int)displayed;
+    mLock.unlock();
+    mFrameSignal.notify_all();
+
+    switch (mReturnMode) {
+        case eAutoReturn:
+            // Send the camera buffer back now that the client has seen it
+            LOG(DEBUG) << "Calling doneWithFrame";
+            mCamera->doneWithFrame(buffers);
+            break;
+        case eNoAutoReturn:
+            // Hang onto the buffer handles for now -- the client will return it explicitly later
+            // mHeldBuffers.push(buffers);
+            break;
+    }
+
+    LOG(DEBUG) << "Frame handling complete";
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus FrameHandler::notify(const EvsEventDesc& event) {
+    // Local flag we use to keep track of when the stream is stopping
+    std::unique_lock<std::mutex> lock(mEventLock);
+    mLatestEventDesc.aType = event.aType;
+    mLatestEventDesc.payload[0] = event.payload[0];
+    mLatestEventDesc.payload[1] = event.payload[1];
+    if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
+        // Signal that the last frame has been received and the stream is stopped
+        mRunning = false;
+    } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) {
+        LOG(DEBUG) << "Camera parameter " << mLatestEventDesc.payload[0] << " is changed to "
+                   << mLatestEventDesc.payload[1];
+    } else {
+        LOG(DEBUG) << "Received an event " << eventToString(mLatestEventDesc.aType);
+    }
+    lock.unlock();
+    mEventSignal.notify_one();
+
+    return ScopedAStatus::ok();
+}
+
+bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, const BufferDesc& srcBuffer) {
+    bool success = true;
+    const HardwareBufferDescription* pSrcDesc =
+            reinterpret_cast<const HardwareBufferDescription*>(&srcBuffer.buffer.description);
+    const HardwareBufferDescription* pTgtDesc =
+            reinterpret_cast<const HardwareBufferDescription*>(&tgtBuffer.buffer.description);
+
+    // Make sure we don't run off the end of either buffer
+    const unsigned width = std::min(pTgtDesc->width, pSrcDesc->width);
+    const unsigned height = std::min(pTgtDesc->height, pSrcDesc->height);
+
+    // FIXME: We duplicate file descriptors twice below; consider using TAKE_HANDLE
+    // instead of CLONE_HANDLE.
+    buffer_handle_t target = ::android::dupFromAidl(tgtBuffer.buffer.handle);
+    ::android::sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(
+            target, android::GraphicBuffer::CLONE_HANDLE, pTgtDesc->width, pTgtDesc->height,
+            static_cast<android::PixelFormat>(pTgtDesc->format), pTgtDesc->layers,
+            static_cast<uint64_t>(pTgtDesc->usage), pTgtDesc->stride);
+
+    buffer_handle_t source = ::android::dupFromAidl(srcBuffer.buffer.handle);
+    ::android::sp<android::GraphicBuffer> src = new android::GraphicBuffer(
+            source, android::GraphicBuffer::CLONE_HANDLE, pSrcDesc->width, pSrcDesc->height,
+            static_cast<android::PixelFormat>(pSrcDesc->format), pSrcDesc->layers,
+            static_cast<uint64_t>(pSrcDesc->usage), pSrcDesc->stride);
+
+    // Lock our source buffer for reading (current expectation are for this to be NV21 format)
+    uint8_t* srcPixels = nullptr;
+    src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
+
+    // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format)
+    uint32_t* tgtPixels = nullptr;
+    tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
+
+    if (srcPixels && tgtPixels) {
+        using namespace ::android::hardware::automotive::evs::common;
+        if (static_cast<android_pixel_format_t>(pTgtDesc->format) == HAL_PIXEL_FORMAT_RGBA_8888) {
+            if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+                HAL_PIXEL_FORMAT_YCRCB_420_SP) {  // 420SP == NV21
+                Utils::copyNV21toRGB32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+            } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+                       HAL_PIXEL_FORMAT_YV12) {  // YUV_420P == YV12
+                Utils::copyYV12toRGB32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+            } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+                       HAL_PIXEL_FORMAT_YCBCR_422_I) {  // YUYV
+                Utils::copyYUYVtoRGB32(width, height, srcPixels, pSrcDesc->stride, tgtPixels,
+                                       pTgtDesc->stride);
+            } else if (pSrcDesc->format == pTgtDesc->format) {  // 32bit RGBA
+                Utils::copyMatchedInterleavedFormats(width, height, srcPixels, pSrcDesc->stride,
+                                                     tgtPixels, pTgtDesc->stride,
+                                                     tgtBuffer.pixelSizeBytes);
+            } else {
+                LOG(ERROR) << "Camera buffer format is not supported";
+                success = false;
+            }
+        } else if (static_cast<android_pixel_format_t>(pTgtDesc->format) ==
+                   HAL_PIXEL_FORMAT_BGRA_8888) {
+            if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+                HAL_PIXEL_FORMAT_YCRCB_420_SP) {  // 420SP == NV21
+                Utils::copyNV21toBGR32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+            } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+                       HAL_PIXEL_FORMAT_YV12) {  // YUV_420P == YV12
+                Utils::copyYV12toBGR32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+            } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+                       HAL_PIXEL_FORMAT_YCBCR_422_I) {  // YUYV
+                Utils::copyYUYVtoBGR32(width, height, srcPixels, pSrcDesc->stride, tgtPixels,
+                                       pTgtDesc->stride);
+            } else if (pSrcDesc->format == pTgtDesc->format) {  // 32bit RGBA
+                Utils::copyMatchedInterleavedFormats(width, height, srcPixels, pSrcDesc->stride,
+                                                     tgtPixels, pTgtDesc->stride,
+                                                     tgtBuffer.pixelSizeBytes);
+            } else {
+                LOG(ERROR) << "Camera buffer format is not supported";
+                success = false;
+            }
+        } else {
+            // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
+            LOG(ERROR) << "Diplay buffer is always expected to be 32bit RGBA";
+            success = false;
+        }
+    } else {
+        LOG(ERROR) << "Failed to lock buffer contents for contents transfer";
+        success = false;
+    }
+
+    if (srcPixels) {
+        src->unlock();
+    }
+    if (tgtPixels) {
+        tgt->unlock();
+    }
+
+    return success;
+}
+
+void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) {
+    if (width) {
+        *width = mFrameWidth;
+    }
+
+    if (height) {
+        *height = mFrameHeight;
+    }
+}
+
+bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent, EvsEventDesc& aReceivedEvent,
+                                bool ignorePayload) {
+    // Wait until we get an expected parameter change event.
+    std::unique_lock<std::mutex> lock(mEventLock);
+    auto now = std::chrono::system_clock::now();
+    bool found = false;
+    while (!found) {
+        bool result = mEventSignal.wait_until(
+                lock, now + 5s, [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found]() {
+                    found = (mLatestEventDesc.aType == aTargetEvent.aType) &&
+                            (ignorePayload ||
+                             (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] &&
+                              mLatestEventDesc.payload[1] == aTargetEvent.payload[1]));
+
+                    aReceivedEvent.aType = mLatestEventDesc.aType;
+                    aReceivedEvent.payload[0] = mLatestEventDesc.payload[0];
+                    aReceivedEvent.payload[1] = mLatestEventDesc.payload[1];
+                    return found;
+                });
+
+        if (!result) {
+            LOG(WARNING) << "A timer is expired before a target event has happened.";
+            break;
+        }
+    }
+
+    return found;
+}
+
+const char* FrameHandler::eventToString(const EvsEventType aType) {
+    switch (aType) {
+        case EvsEventType::STREAM_STARTED:
+            return "STREAM_STARTED";
+        case EvsEventType::STREAM_STOPPED:
+            return "STREAM_STOPPED";
+        case EvsEventType::FRAME_DROPPED:
+            return "FRAME_DROPPED";
+        case EvsEventType::TIMEOUT:
+            return "TIMEOUT";
+        case EvsEventType::PARAMETER_CHANGED:
+            return "PARAMETER_CHANGED";
+        case EvsEventType::MASTER_RELEASED:
+            return "MASTER_RELEASED";
+        default:
+            return "Unknown";
+    }
+}
diff --git a/automotive/evs/aidl/vts/FrameHandler.h b/automotive/evs/aidl/vts/FrameHandler.h
new file mode 100644
index 0000000..0b959ab
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandler.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef AUTOMOTIVE_EVS_VTS_FRAMEHANDLER_H
+#define AUTOMOTIVE_EVS_VTS_FRAMEHANDLER_H
+
+#include <aidl/android/hardware/automotive/evs/BnEvsCameraStream.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+
+#include <mutex>
+#include <queue>
+
+/*
+ * FrameHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation.  Given an
+ * IEvsDisplay instance at startup, it will forward the received imagery to the display,
+ * providing a trivial implementation of a rear vew camera type application.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class FrameHandler : public ::aidl::android::hardware::automotive::evs::BnEvsCameraStream {
+  public:
+    enum BufferControlFlag {
+        eAutoReturn,
+        eNoAutoReturn,
+    };
+
+    FrameHandler(
+            const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera>& pCamera,
+            const ::aidl::android::hardware::automotive::evs::CameraDesc& cameraInfo,
+            const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
+                    pDisplay,
+            BufferControlFlag mode = eAutoReturn);
+    virtual ~FrameHandler() {
+        if (mCamera != nullptr) {
+            /* shutdown a camera explicitly */
+            shutdown();
+        }
+    }
+
+    void shutdown();
+    bool startStream();
+    void asyncStopStream();
+    void blockingStopStream();
+    bool returnHeldBuffer();
+    bool isRunning();
+    void waitForFrameCount(unsigned frameCount);
+    bool waitForEvent(const ::aidl::android::hardware::automotive::evs::EvsEventDesc& aTargetEvent,
+                      ::aidl::android::hardware::automotive::evs::EvsEventDesc& aReceivedEvent,
+                      bool ignorePayload = false);
+    void getFramesCounters(unsigned* received, unsigned* displayed);
+    void getFrameDimension(unsigned* width, unsigned* height);
+
+  private:
+    // Methods from ::aidl::android::hardware::automotive::evs::IEvsCameraStream follow.
+    ::ndk::ScopedAStatus deliverFrame(
+            const std::vector<::aidl::android::hardware::automotive::evs::BufferDesc>& buffer)
+            override;
+    ::ndk::ScopedAStatus notify(
+            const ::aidl::android::hardware::automotive::evs::EvsEventDesc& event) override;
+
+    // Local implementation details
+    bool copyBufferContents(
+            const ::aidl::android::hardware::automotive::evs::BufferDesc& tgtBuffer,
+            const ::aidl::android::hardware::automotive::evs::BufferDesc& srcBuffer);
+    const char* eventToString(const ::aidl::android::hardware::automotive::evs::EvsEventType aType);
+
+    std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera> mCamera;
+    ::aidl::android::hardware::automotive::evs::CameraDesc mCameraInfo;
+    std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay> mDisplay;
+    BufferControlFlag mReturnMode;
+
+    // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface,
+    // we need to protect all member variables that may be modified while we're streaming
+    // (ie: those below)
+    std::mutex mLock;
+    std::mutex mEventLock;
+    std::condition_variable mEventSignal;
+    std::condition_variable mFrameSignal;
+    std::queue<std::vector<::aidl::android::hardware::automotive::evs::BufferDesc>> mHeldBuffers;
+
+    bool mRunning = false;
+    unsigned mFramesReceived = 0;   // Simple counter -- rolls over eventually!
+    unsigned mFramesDisplayed = 0;  // Simple counter -- rolls over eventually!
+    unsigned mFrameWidth = 0;
+    unsigned mFrameHeight = 0;
+    ::aidl::android::hardware::automotive::evs::EvsEventDesc mLatestEventDesc;
+};
+
+#endif  // AUTOMOTIVE_EVS_VTS_FRAMEHANDLER_H
diff --git a/automotive/evs/aidl/vts/FrameHandlerUltrasonics.cpp b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.cpp
new file mode 100644
index 0000000..650f0ed
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 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.
+ */
+
+#include "FrameHandlerUltrasonics.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventType.h>
+#include <aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.h>
+#include <aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.h>
+#include <android-base/logging.h>
+
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray;
+using ::aidl::android::hardware::automotive::evs::UltrasonicsDataFrameDesc;
+using ::ndk::ScopedAStatus;
+
+namespace {
+
+// Struct used by SerializeWaveformData().
+struct WaveformData {
+    uint8_t receiverId;
+    std::vector<std::pair<float, float>> readings;
+};
+
+}  // namespace
+
+FrameHandlerUltrasonics::FrameHandlerUltrasonics(
+        const std::shared_ptr<IEvsUltrasonicsArray>& pArray)
+    : mEvsUltrasonicsArray(pArray), mReceiveFramesCount(0) {
+    // Nothing but member initialization
+}
+
+ScopedAStatus FrameHandlerUltrasonics::notify(const EvsEventDesc& evsEvent) {
+    switch (evsEvent.aType) {
+        case EvsEventType::STREAM_STARTED:
+        case EvsEventType::STREAM_STOPPED:
+        case EvsEventType::FRAME_DROPPED:
+        case EvsEventType::TIMEOUT:
+            mReceivedEvents.emplace_back(evsEvent);
+            break;
+        default:
+            LOG(ERROR) << "Received unexpected event";
+    }
+
+    return ScopedAStatus::ok();
+}
+
+// De-serializes shared memory to vector of WaveformData.
+// TODO(b/149950362): Add a common library for serializing and deserializing waveform data.
+std::vector<WaveformData> DeSerializeWaveformData(std::vector<uint32_t> recvReadingsCountList,
+                                                  uint8_t* pData) {
+    std::vector<WaveformData> waveformDataList(recvReadingsCountList.size());
+
+    for (int i = 0; i < waveformDataList.size(); i++) {
+        // Set Id
+        memcpy(&waveformDataList[i].receiverId, pData, sizeof(uint8_t));
+        pData += sizeof(uint8_t);
+
+        waveformDataList[i].readings.resize(recvReadingsCountList[i]);
+
+        for (auto& reading : waveformDataList[i].readings) {
+            // Set the time of flight.
+            memcpy(&reading.first, pData, sizeof(float));
+            pData += sizeof(float);
+
+            // Set the resonance.
+            memcpy(&reading.second, pData, sizeof(float));
+            pData += sizeof(float);
+        }
+    }
+    return waveformDataList;
+}
+
+bool DataFrameValidator(const UltrasonicsDataFrameDesc& /*dataFrameDesc*/) {
+    // TODO(b/214026378): implement a method to validate an ultrasonics data frame
+    (void)DeSerializeWaveformData;
+    return true;
+}
+
+ScopedAStatus FrameHandlerUltrasonics::deliverDataFrame(
+        const UltrasonicsDataFrameDesc& dataFrameDesc) {
+    LOG(DEBUG) << "FrameHandlerUltrasonics::receiveFrames";
+
+    mReceiveFramesCount++;
+
+    if (!DataFrameValidator(dataFrameDesc)) {
+        mAllFramesValid = false;
+    }
+
+    // Send done with data frame.
+    mEvsUltrasonicsArray->doneWithDataFrame(dataFrameDesc);
+    return ScopedAStatus::ok();
+}
+
+bool FrameHandlerUltrasonics::checkEventReceived(const EvsEventDesc& evsEvent) {
+    LOG(DEBUG) << "FrameHandlerUltrasonics::checkEventReceived";
+    int size = mReceivedEvents.size();  // work around
+    LOG(DEBUG) << "Received event number: " << size;
+    auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), evsEvent);
+    return iter != mReceivedEvents.end();
+}
+
+int FrameHandlerUltrasonics::getReceiveFramesCount() {
+    return mReceiveFramesCount;
+}
+
+bool FrameHandlerUltrasonics::areAllFramesValid() {
+    return mAllFramesValid;
+}
diff --git a/automotive/evs/aidl/vts/FrameHandlerUltrasonics.h b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.h
new file mode 100644
index 0000000..f853a00
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef AUTOMOTIVE_EVS_VTS_FRAMEHANDLERULTRASONICS_H
+#define AUTOMOTIVE_EVS_VTS_FRAMEHANDLERULTRASONICS_H
+
+#include <aidl/android/hardware/automotive/evs/BnEvsUltrasonicsArrayStream.h>
+#include <aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.h>
+
+#include <vector>
+
+class FrameHandlerUltrasonics
+    : public ::aidl::android::hardware::automotive::evs::BnEvsUltrasonicsArrayStream {
+  public:
+    FrameHandlerUltrasonics(
+            const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>&
+                    pArray);
+
+    // Implementation for ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArrayStream
+    ::ndk::ScopedAStatus notify(
+            const ::aidl::android::hardware::automotive::evs::EvsEventDesc& event) override;
+    ::ndk::ScopedAStatus deliverDataFrame(
+            const ::aidl::android::hardware::automotive::evs::UltrasonicsDataFrameDesc& desc)
+            override;
+
+    bool checkEventReceived(
+            const ::aidl::android::hardware::automotive::evs::EvsEventDesc& evsEvent);
+    int getReceiveFramesCount();
+    bool areAllFramesValid();
+
+  private:
+    std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>
+            mEvsUltrasonicsArray;
+    std::vector<::aidl::android::hardware::automotive::evs::EvsEventDesc> mReceivedEvents;
+    int mReceiveFramesCount;
+    bool mAllFramesValid = true;
+};
+
+#endif  // AUTOMOTIVE_EVS_VTS_FRAMEHANDLERULTRASONICS_H
diff --git a/automotive/evs/aidl/vts/OWNERS b/automotive/evs/aidl/vts/OWNERS
new file mode 100644
index 0000000..a104f50
--- /dev/null
+++ b/automotive/evs/aidl/vts/OWNERS
@@ -0,0 +1,3 @@
+#Bug component : 853002
+ankitarora@google.com
+changyeon@google.com
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
new file mode 100644
index 0000000..c709d40
--- /dev/null
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -0,0 +1,2170 @@
+/*
+ * 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.
+ */
+
+#include "FrameHandler.h"
+#include "FrameHandlerUltrasonics.h"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraParam.h>
+#include <aidl/android/hardware/automotive/evs/DisplayDesc.h>
+#include <aidl/android/hardware/automotive/evs/DisplayState.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventType.h>
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.h>
+#include <aidl/android/hardware/automotive/evs/ParameterRange.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.h>
+#include <aidl/android/hardware/common/NativeHandle.h>
+#include <aidl/android/hardware/graphics/common/HardwareBufferDescription.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+#include <system/camera_metadata.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <utils/Timers.h>
+
+#include <deque>
+#include <thread>
+#include <unordered_set>
+
+namespace {
+
+// These values are called out in the EVS design doc (as of Mar 8, 2017)
+constexpr int kMaxStreamStartMilliseconds = 500;
+constexpr int kMinimumFramesPerSecond = 10;
+constexpr int kSecondsToMilliseconds = 1000;
+constexpr int kMillisecondsToMicroseconds = 1000;
+constexpr float kNanoToMilliseconds = 0.000001f;
+constexpr float kNanoToSeconds = 0.000000001f;
+
+/*
+ * Please note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+typedef struct {
+    int32_t id;
+    int32_t width;
+    int32_t height;
+    int32_t format;
+    int32_t direction;
+    int32_t framerate;
+} RawStreamConfig;
+constexpr size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
+
+}  // namespace
+
+using ::aidl::android::hardware::automotive::evs::BufferDesc;
+using ::aidl::android::hardware::automotive::evs::CameraDesc;
+using ::aidl::android::hardware::automotive::evs::CameraParam;
+using ::aidl::android::hardware::automotive::evs::DisplayDesc;
+using ::aidl::android::hardware::automotive::evs::DisplayState;
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::EvsResult;
+using ::aidl::android::hardware::automotive::evs::IEvsCamera;
+using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray;
+using ::aidl::android::hardware::automotive::evs::ParameterRange;
+using ::aidl::android::hardware::automotive::evs::Stream;
+using ::aidl::android::hardware::automotive::evs::UltrasonicsArrayDesc;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::HardwareBufferDescription;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using std::chrono_literals::operator""s;
+
+// The main test class for EVS
+class EvsAidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        // Make sure we can connect to the enumerator
+        std::string service_name = GetParam();
+        AIBinder* binder = AServiceManager_waitForService(service_name.data());
+        ASSERT_NE(binder, nullptr);
+        mEnumerator = IEvsEnumerator::fromBinder(::ndk::SpAIBinder(binder));
+        LOG(INFO) << "Test target service: " << service_name;
+
+        ASSERT_TRUE(mEnumerator->isHardware(&mIsHwModule).isOk());
+    }
+
+    virtual void TearDown() override {
+        // Attempt to close any active camera
+        for (auto&& cam : mActiveCameras) {
+            if (cam != nullptr) {
+                mEnumerator->closeCamera(cam);
+            }
+        }
+        mActiveCameras.clear();
+    }
+
+  protected:
+    void loadCameraList() {
+        // SetUp() must run first!
+        ASSERT_NE(mEnumerator, nullptr);
+
+        // Get the camera list
+        ASSERT_TRUE(mEnumerator->getCameraList(&mCameraInfo).isOk())
+                << "Failed to get a list of available cameras";
+        LOG(INFO) << "We have " << mCameraInfo.size() << " cameras.";
+    }
+
+    void loadUltrasonicsArrayList() {
+        // SetUp() must run first!
+        ASSERT_NE(mEnumerator, nullptr);
+
+        // Get the ultrasonics array list
+        ASSERT_TRUE(mEnumerator->getUltrasonicsArrayList(&mUltrasonicsArraysInfo).isOk())
+                << "Failed to get a list of available ultrasonics arrays";
+        LOG(INFO) << "We have " << mCameraInfo.size() << " ultrasonics arrays.";
+    }
+
+    bool isLogicalCamera(const camera_metadata_t* metadata) {
+        if (metadata == nullptr) {
+            // A logical camera device must have a valid camera metadata.
+            return false;
+        }
+
+        // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
+        camera_metadata_ro_entry_t entry;
+        int rc = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                               &entry);
+        if (rc != 0) {
+            // No capabilities are found.
+            return false;
+        }
+
+        for (size_t i = 0; i < entry.count; ++i) {
+            uint8_t cap = entry.data.u8[i];
+            if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    std::unordered_set<std::string> getPhysicalCameraIds(const std::string& id, bool& flag) {
+        std::unordered_set<std::string> physicalCameras;
+        const auto it = std::find_if(mCameraInfo.begin(), mCameraInfo.end(),
+                                     [&id](const CameraDesc& desc) { return id == desc.id; });
+        if (it == mCameraInfo.end()) {
+            // Unknown camera is requested.  Return an empty list.
+            return physicalCameras;
+        }
+
+        const camera_metadata_t* metadata = reinterpret_cast<camera_metadata_t*>(&it->metadata[0]);
+        flag = isLogicalCamera(metadata);
+        if (!flag) {
+            // EVS assumes that the device w/o a valid metadata is a physical
+            // device.
+            LOG(INFO) << id << " is not a logical camera device.";
+            physicalCameras.insert(id);
+            return physicalCameras;
+        }
+
+        // Look for physical camera identifiers
+        camera_metadata_ro_entry entry;
+        int rc = find_camera_metadata_ro_entry(metadata, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+                                               &entry);
+        if (rc != 0) {
+            LOG(ERROR) << "No physical camera ID is found for a logical camera device";
+        }
+
+        const uint8_t* ids = entry.data.u8;
+        size_t start = 0;
+        for (size_t i = 0; i < entry.count; ++i) {
+            if (ids[i] == '\0') {
+                if (start != i) {
+                    std::string id(reinterpret_cast<const char*>(ids + start));
+                    physicalCameras.insert(id);
+                }
+                start = i + 1;
+            }
+        }
+
+        LOG(INFO) << id << " consists of " << physicalCameras.size() << " physical camera devices";
+        return physicalCameras;
+    }
+
+    Stream getFirstStreamConfiguration(camera_metadata_t* metadata) {
+        Stream targetCfg = {};
+        camera_metadata_entry_t streamCfgs;
+        if (!find_camera_metadata_entry(metadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                        &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
+            for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+                    targetCfg.width = ptr->width;
+                    targetCfg.height = ptr->height;
+                    targetCfg.format = static_cast<PixelFormat>(ptr->format);
+                    break;
+                }
+                ++ptr;
+            }
+        }
+
+        return targetCfg;
+    }
+
+    // Every test needs access to the service
+    std::shared_ptr<IEvsEnumerator> mEnumerator;
+    // Empty unless/util loadCameraList() is called
+    std::vector<CameraDesc> mCameraInfo;
+    // boolean to tell current module under testing is HW module implementation
+    // or not
+    bool mIsHwModule;
+    // A list of active camera handles that are need to be cleaned up
+    std::deque<std::shared_ptr<IEvsCamera>> mActiveCameras;
+    // Empty unless/util loadUltrasonicsArrayList() is called
+    std::vector<UltrasonicsArrayDesc> mUltrasonicsArraysInfo;
+    // A list of active ultrasonics array handles that are to be cleaned up
+    std::deque<std::weak_ptr<IEvsUltrasonicsArray>> mActiveUltrasonicsArrays;
+};
+
+// Test cases, their implementations, and corresponding requirements are
+// documented at go/aae-evs-public-api-test.
+
+/*
+ * CameraOpenClean:
+ * Opens each camera reported by the enumerator and then explicitly closes it via a
+ * call to closeCamera.  Then repeats the test to ensure all cameras can be reopened.
+ */
+TEST_P(EvsAidlTest, CameraOpenClean) {
+    LOG(INFO) << "Starting CameraOpenClean test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Open and close each camera twice
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device, " << cam.id << " for HW target.";
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        for (int pass = 0; pass < 2; pass++) {
+            std::shared_ptr<IEvsCamera> pCam;
+            ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+            ASSERT_NE(pCam, nullptr);
+
+            CameraDesc cameraInfo;
+            for (auto&& devName : devices) {
+                ASSERT_TRUE(pCam->getPhysicalCameraInfo(devName, &cameraInfo).isOk());
+                EXPECT_EQ(devName, cameraInfo.id);
+            }
+
+            // Store a camera handle for a clean-up
+            mActiveCameras.push_back(pCam);
+
+            // Verify that this camera self-identifies correctly
+            ASSERT_TRUE(pCam->getCameraInfo(&cameraInfo).isOk());
+            EXPECT_EQ(cam.id, cameraInfo.id);
+
+            // Verify methods for extended info
+            const auto id = 0xFFFFFFFF;  // meaningless id
+            std::vector<uint8_t> values;
+            auto status = pCam->setExtendedInfo(id, values);
+            if (isLogicalCam) {
+                EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+                                                      static_cast<int>(EvsResult::NOT_SUPPORTED));
+            } else {
+                EXPECT_TRUE(status.isOk());
+            }
+
+            status = pCam->getExtendedInfo(id, &values);
+            if (isLogicalCam) {
+                EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+                                                      static_cast<int>(EvsResult::NOT_SUPPORTED));
+            } else {
+                EXPECT_TRUE(status.isOk());
+            }
+
+            // Explicitly close the camera so resources are released right away
+            ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+            mActiveCameras.clear();
+        }
+    }
+}
+
+/*
+ * CameraOpenAggressive:
+ * Opens each camera reported by the enumerator twice in a row without an intervening closeCamera
+ * call.  This ensures that the intended "aggressive open" behavior works.  This is necessary for
+ * the system to be tolerant of shutdown/restart race conditions.
+ */
+TEST_P(EvsAidlTest, CameraOpenAggressive) {
+    LOG(INFO) << "Starting CameraOpenAggressive test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Open and close each camera twice
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device, " << cam.id << " for HW target.";
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        mActiveCameras.clear();
+        std::shared_ptr<IEvsCamera> pCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+        EXPECT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam);
+
+        // Verify that this camera self-identifies correctly
+        CameraDesc cameraInfo;
+        ASSERT_TRUE(pCam->getCameraInfo(&cameraInfo).isOk());
+        EXPECT_EQ(cam.id, cameraInfo.id);
+
+        std::shared_ptr<IEvsCamera> pCam2;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam2).isOk());
+        EXPECT_NE(pCam2, nullptr);
+        EXPECT_NE(pCam, pCam2);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam2);
+
+        auto status = pCam->setMaxFramesInFlight(2);
+        if (mIsHwModule) {
+            // Verify that the old camera rejects calls via HW module.
+            EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+                                                  static_cast<int>(EvsResult::OWNERSHIP_LOST));
+        } else {
+            // default implementation supports multiple clients.
+            EXPECT_TRUE(status.isOk());
+        }
+
+        // Close the superseded camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+        mActiveCameras.pop_front();
+
+        // Verify that the second camera instance self-identifies correctly
+        ASSERT_TRUE(pCam2->getCameraInfo(&cameraInfo).isOk());
+        EXPECT_EQ(cam.id, cameraInfo.id);
+
+        // Close the second camera instance
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam2).isOk());
+        mActiveCameras.pop_front();
+    }
+
+    // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests
+    sleep(1);  // I hate that this is an arbitrary time to wait.  :(  b/36122635
+}
+
+/*
+ * CameraStreamPerformance:
+ * Measure and qualify the stream start up time and streaming frame rate of each reported camera
+ */
+TEST_P(EvsAidlTest, CameraStreamPerformance) {
+    LOG(INFO) << "Starting CameraStreamPerformance test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device " << cam.id;
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        std::shared_ptr<IEvsCamera> pCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+        EXPECT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam);
+
+        // Set up a frame receiver object which will fire up its own thread
+        std::shared_ptr<FrameHandler> frameHandler =
+                std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Start the camera's video stream
+        nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+        ASSERT_TRUE(frameHandler->startStream());
+
+        // Ensure the first frame arrived within the expected time
+        frameHandler->waitForFrameCount(1);
+        nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+        nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start;
+
+        // Extra delays are expected when we attempt to start a video stream on
+        // the logical camera device.  The amount of delay is expected the
+        // number of physical camera devices multiplied by
+        // kMaxStreamStartMilliseconds at most.
+        EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame),
+                  kMaxStreamStartMilliseconds * devices.size());
+        printf("%s: Measured time to first frame %0.2f ms\n", cam.id.data(),
+               timeToFirstFrame * kNanoToMilliseconds);
+        LOG(INFO) << cam.id << ": Measured time to first frame " << std::scientific
+                  << timeToFirstFrame * kNanoToMilliseconds << " ms.";
+
+        // Check aspect ratio
+        unsigned width = 0, height = 0;
+        frameHandler->getFrameDimension(&width, &height);
+        EXPECT_GE(width, height);
+
+        // Wait a bit, then ensure we get at least the required minimum number of frames
+        sleep(5);
+        nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Even when the camera pointer goes out of scope, the FrameHandler object will
+        // keep the stream alive unless we tell it to shutdown.
+        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+        // we have to break that cycle in order for either of them to get cleaned up.
+        frameHandler->shutdown();
+
+        unsigned framesReceived = 0;
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        framesReceived = framesReceived - 1;  // Back out the first frame we already waited for
+        nsecs_t runTime = end - firstFrame;
+        float framesPerSecond = framesReceived / (runTime * kNanoToSeconds);
+        printf("Measured camera rate %3.2f fps\n", framesPerSecond);
+        LOG(INFO) << "Measured camera rate " << std::scientific << framesPerSecond << " fps.";
+        EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+        mActiveCameras.clear();
+    }
+}
+
+/*
+ * CameraStreamBuffering:
+ * Ensure the camera implementation behaves properly when the client holds onto buffers for more
+ * than one frame time.  The camera must cleanly skip frames until the client is ready again.
+ */
+TEST_P(EvsAidlTest, CameraStreamBuffering) {
+    LOG(INFO) << "Starting CameraStreamBuffering test";
+
+    // Arbitrary constant (should be > 1 and not too big)
+    static const unsigned int kBuffersToHold = 6;
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device " << cam.id << " for HW target.";
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        std::shared_ptr<IEvsCamera> pCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+        EXPECT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam);
+
+        // Ask for a very large number of buffers in flight to ensure it errors correctly
+        auto badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
+        EXPECT_TRUE(!badResult.isOk() && badResult.getServiceSpecificError() ==
+                                                 static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
+
+        // Now ask for exactly two buffers in flight as we'll test behavior in that case
+        ASSERT_TRUE(pCam->setMaxFramesInFlight(kBuffersToHold).isOk());
+
+        // Set up a frame receiver object which will fire up its own thread.
+        std::shared_ptr<FrameHandler> frameHandler =
+                std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eNoAutoReturn);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler->startStream());
+
+        // Check that the video stream stalls once we've gotten exactly the number of buffers
+        // we requested since we told the frameHandler not to return them.
+        sleep(1);  // 1 second should be enough for at least 5 frames to be delivered worst case
+        unsigned framesReceived = 0;
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+
+        // Give back one buffer
+        ASSERT_TRUE(frameHandler->returnHeldBuffer());
+
+        // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+        // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+        usleep(110 * kMillisecondsToMicroseconds);
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        EXPECT_EQ(kBuffersToHold + 1, framesReceived) << "Stream should've resumed";
+
+        // Even when the camera pointer goes out of scope, the FrameHandler object will
+        // keep the stream alive unless we tell it to shutdown.
+        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+        // we have to break that cycle in order for either of them to get cleaned up.
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+        mActiveCameras.clear();
+    }
+}
+
+/*
+ * CameraToDisplayRoundTrip:
+ * End to end test of data flowing from the camera to the display.  Each delivered frame of camera
+ * imagery is simply copied to the display buffer and presented on screen.  This is the one test
+ * which a human could observe to see the operation of the system on the physical display.
+ */
+TEST_P(EvsAidlTest, CameraToDisplayRoundTrip) {
+    LOG(INFO) << "Starting CameraToDisplayRoundTrip test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Request available display IDs
+    uint8_t targetDisplayId = 0;
+    std::vector<uint8_t> displayIds;
+    ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+    EXPECT_GT(displayIds.size(), 0);
+    targetDisplayId = displayIds[0];
+
+    // Request exclusive access to the first EVS display
+    std::shared_ptr<IEvsDisplay> pDisplay;
+    ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+    EXPECT_NE(pDisplay, nullptr);
+    LOG(INFO) << "Display " << targetDisplayId << " is in use.";
+
+    // Get the display descriptor
+    DisplayDesc displayDesc;
+    ASSERT_TRUE(pDisplay->getDisplayInfo(&displayDesc).isOk());
+    LOG(INFO) << "    Resolution: " << displayDesc.width << "x" << displayDesc.height;
+    ASSERT_GT(displayDesc.width, 0);
+    ASSERT_GT(displayDesc.height, 0);
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device " << cam.id << " for HW target.";
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        std::shared_ptr<IEvsCamera> pCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+        EXPECT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        std::shared_ptr<FrameHandler> frameHandler =
+                std::make_shared<FrameHandler>(pCam, cam, pDisplay, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Activate the display
+        ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME).isOk());
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler->startStream());
+
+        // Wait a while to let the data flow
+        static const int kSecondsToWait = 5;
+        const int streamTimeMs =
+                kSecondsToWait * kSecondsToMilliseconds - kMaxStreamStartMilliseconds;
+        const unsigned minimumFramesExpected =
+                streamTimeMs * kMinimumFramesPerSecond / kSecondsToMilliseconds;
+        sleep(kSecondsToWait);
+        unsigned framesReceived = 0;
+        unsigned framesDisplayed = 0;
+        frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+        EXPECT_EQ(framesReceived, framesDisplayed);
+        EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::NOT_VISIBLE).isOk());
+
+        // Shut down the streamer
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+        mActiveCameras.clear();
+    }
+
+    // Explicitly release the display
+    ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+}
+
+/*
+ * MultiCameraStream:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera.
+ */
+TEST_P(EvsAidlTest, MultiCameraStream) {
+    LOG(INFO) << "Starting MultiCameraStream test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        // Create two camera clients.
+        std::shared_ptr<IEvsCamera> pCam0;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam0).isOk());
+        EXPECT_NE(pCam0, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam0);
+
+        std::shared_ptr<IEvsCamera> pCam1;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+        EXPECT_NE(pCam1, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam1);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        std::shared_ptr<FrameHandler> frameHandler0 =
+                std::make_shared<FrameHandler>(pCam0, cam, nullptr, FrameHandler::eAutoReturn);
+        std::shared_ptr<FrameHandler> frameHandler1 =
+                std::make_shared<FrameHandler>(pCam1, cam, nullptr, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandler0, nullptr);
+        EXPECT_NE(frameHandler1, nullptr);
+
+        // Start the camera's video stream via client 0
+        ASSERT_TRUE(frameHandler0->startStream());
+        ASSERT_TRUE(frameHandler1->startStream());
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Wait a bit, then ensure both clients get at least the required minimum number of frames
+        sleep(5);
+        nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+        unsigned framesReceived0 = 0, framesReceived1 = 0;
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+        framesReceived0 = framesReceived0 - 1;  // Back out the first frame we already waited for
+        framesReceived1 = framesReceived1 - 1;  // Back out the first frame we already waited for
+        nsecs_t runTime = end - firstFrame;
+        float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+        float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+        LOG(INFO) << "Measured camera rate " << std::scientific << framesPerSecond0 << " fps and "
+                  << framesPerSecond1 << " fps";
+        EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+        EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+        // Shutdown one client
+        frameHandler0->shutdown();
+
+        // Read frame counters again
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+        // Wait a bit again
+        sleep(5);
+        unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+        frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+        EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+        EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+        // Shutdown another
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
+        mActiveCameras.clear();
+
+        // TODO(b/145459970, b/145457727): below sleep() is added to ensure the
+        // destruction of active camera objects; this may be related with two
+        // issues.
+        sleep(1);
+    }
+}
+
+/*
+ * CameraParameter:
+ * Verify that a client can adjust a camera parameter.
+ */
+TEST_P(EvsAidlTest, CameraParameter) {
+    LOG(INFO) << "Starting CameraParameter test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            LOG(INFO) << "Skip a logical device " << cam.id;
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        // Create a camera client
+        std::shared_ptr<IEvsCamera> pCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+        EXPECT_NE(pCam, nullptr);
+
+        // Store a camera
+        mActiveCameras.push_back(pCam);
+
+        // Get the parameter list
+        std::vector<CameraParam> cmds;
+        ASSERT_TRUE(pCam->getParameterList(&cmds).isOk());
+        if (cmds.size() < 1) {
+            continue;
+        }
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        std::shared_ptr<FrameHandler> frameHandler =
+                std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler->startStream());
+
+        // Ensure the stream starts
+        frameHandler->waitForFrameCount(1);
+
+        // Set current client is the primary client
+        ASSERT_TRUE(pCam->setPrimaryClient().isOk());
+        for (auto& cmd : cmds) {
+            // Get a valid parameter value range
+            ParameterRange range;
+            ASSERT_TRUE(pCam->getIntParameterRange(cmd, &range).isOk());
+
+            std::vector<int32_t> values;
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                ASSERT_TRUE(pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+                for (auto&& v : values) {
+                    EXPECT_EQ(v, 0);
+                }
+            }
+
+            // Try to program a parameter with a random value [minVal, maxVal]
+            int32_t val0 = range.min + (std::rand() % (range.max - range.min));
+
+            // Rounding down
+            val0 = val0 - (val0 % range.step);
+            values.clear();
+            ASSERT_TRUE(pCam->setIntParameter(cmd, val0, &values).isOk());
+
+            values.clear();
+            ASSERT_TRUE(pCam->getIntParameter(cmd, &values).isOk());
+            for (auto&& v : values) {
+                EXPECT_EQ(val0, v) << "Values are not matched.";
+            }
+        }
+        ASSERT_TRUE(pCam->unsetPrimaryClient().isOk());
+
+        // Shutdown
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+        mActiveCameras.clear();
+    }
+}
+
+/*
+ * CameraPrimaryClientRelease
+ * Verify that non-primary client gets notified when the primary client either
+ * terminates or releases a role.
+ */
+TEST_P(EvsAidlTest, CameraPrimaryClientRelease) {
+    LOG(INFO) << "Starting CameraPrimaryClientRelease test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            LOG(INFO) << "Skip a logical device " << cam.id;
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        // Create two camera clients.
+        std::shared_ptr<IEvsCamera> pPrimaryCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pPrimaryCam).isOk());
+        EXPECT_NE(pPrimaryCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pPrimaryCam);
+
+        std::shared_ptr<IEvsCamera> pSecondaryCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pSecondaryCam).isOk());
+        EXPECT_NE(pSecondaryCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pSecondaryCam);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        std::shared_ptr<FrameHandler> frameHandlerPrimary = std::make_shared<FrameHandler>(
+                pPrimaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+        std::shared_ptr<FrameHandler> frameHandlerSecondary = std::make_shared<FrameHandler>(
+                pSecondaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandlerPrimary, nullptr);
+        EXPECT_NE(frameHandlerSecondary, nullptr);
+
+        // Set one client as the primary client
+        ASSERT_TRUE(pPrimaryCam->setPrimaryClient().isOk());
+
+        // Try to set another client as the primary client.
+        ASSERT_FALSE(pSecondaryCam->setPrimaryClient().isOk());
+
+        // Start the camera's video stream via a primary client client.
+        ASSERT_TRUE(frameHandlerPrimary->startStream());
+
+        // Ensure the stream starts
+        frameHandlerPrimary->waitForFrameCount(1);
+
+        // Start the camera's video stream via another client
+        ASSERT_TRUE(frameHandlerSecondary->startStream());
+
+        // Ensure the stream starts
+        frameHandlerSecondary->waitForFrameCount(1);
+
+        // Non-primary client expects to receive a primary client role relesed
+        // notification.
+        EvsEventDesc aTargetEvent = {};
+        EvsEventDesc aNotification = {};
+
+        bool listening = false;
+        std::mutex eventLock;
+        std::condition_variable eventCond;
+        std::thread listener =
+                std::thread([&aNotification, &frameHandlerSecondary, &listening, &eventCond]() {
+                    // Notify that a listening thread is running.
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                    if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification, true)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                });
+
+        // Wait until a listening thread starts.
+        std::unique_lock<std::mutex> lock(eventLock);
+        auto timer = std::chrono::system_clock::now();
+        while (!listening) {
+            timer += 1s;
+            eventCond.wait_until(lock, timer);
+        }
+        lock.unlock();
+
+        // Release a primary client role.
+        ASSERT_TRUE(pPrimaryCam->unsetPrimaryClient().isOk());
+
+        // Join a listening thread.
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify change notifications.
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast<EvsEventType>(aNotification.aType));
+
+        // Non-primary becomes a primary client.
+        ASSERT_TRUE(pSecondaryCam->setPrimaryClient().isOk());
+
+        // Previous primary client fails to become a primary client.
+        ASSERT_FALSE(pPrimaryCam->setPrimaryClient().isOk());
+
+        listening = false;
+        listener = std::thread([&aNotification, &frameHandlerPrimary, &listening, &eventCond]() {
+            // Notify that a listening thread is running.
+            listening = true;
+            eventCond.notify_all();
+
+            EvsEventDesc aTargetEvent;
+            aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+            if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification, true)) {
+                LOG(WARNING) << "A timer is expired before a target event is fired.";
+            }
+        });
+
+        // Wait until a listening thread starts.
+        timer = std::chrono::system_clock::now();
+        lock.lock();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        // Closing current primary client.
+        frameHandlerSecondary->shutdown();
+
+        // Join a listening thread.
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify change notifications.
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast<EvsEventType>(aNotification.aType));
+
+        // Closing streams.
+        frameHandlerPrimary->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pPrimaryCam).isOk());
+        ASSERT_TRUE(mEnumerator->closeCamera(pSecondaryCam).isOk());
+        mActiveCameras.clear();
+    }
+}
+
+/*
+ * MultiCameraParameter:
+ * Verify that primary and non-primary clients behave as expected when they try to adjust
+ * camera parameters.
+ */
+TEST_P(EvsAidlTest, MultiCameraParameter) {
+    LOG(INFO) << "Starting MultiCameraParameter test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            LOG(INFO) << "Skip a logical device " << cam.id;
+            continue;
+        }
+
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        // Create two camera clients.
+        std::shared_ptr<IEvsCamera> pPrimaryCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pPrimaryCam).isOk());
+        EXPECT_NE(pPrimaryCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pPrimaryCam);
+
+        std::shared_ptr<IEvsCamera> pSecondaryCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pSecondaryCam).isOk());
+        EXPECT_NE(pSecondaryCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pSecondaryCam);
+
+        // Get the parameter list
+        std::vector<CameraParam> camPrimaryCmds, camSecondaryCmds;
+        ASSERT_TRUE(pPrimaryCam->getParameterList(&camPrimaryCmds).isOk());
+        ASSERT_TRUE(pSecondaryCam->getParameterList(&camSecondaryCmds).isOk());
+        if (camPrimaryCmds.size() < 1 || camSecondaryCmds.size() < 1) {
+            // Skip a camera device if it does not support any parameter.
+            continue;
+        }
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        std::shared_ptr<FrameHandler> frameHandlerPrimary = std::make_shared<FrameHandler>(
+                pPrimaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+        std::shared_ptr<FrameHandler> frameHandlerSecondary = std::make_shared<FrameHandler>(
+                pSecondaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandlerPrimary, nullptr);
+        EXPECT_NE(frameHandlerSecondary, nullptr);
+
+        // Set one client as the primary client.
+        ASSERT_TRUE(pPrimaryCam->setPrimaryClient().isOk());
+
+        // Try to set another client as the primary client.
+        ASSERT_FALSE(pSecondaryCam->setPrimaryClient().isOk());
+
+        // Start the camera's video stream via a primary client client.
+        ASSERT_TRUE(frameHandlerPrimary->startStream());
+
+        // Ensure the stream starts
+        frameHandlerPrimary->waitForFrameCount(1);
+
+        // Start the camera's video stream via another client
+        ASSERT_TRUE(frameHandlerSecondary->startStream());
+
+        // Ensure the stream starts
+        frameHandlerSecondary->waitForFrameCount(1);
+
+        int32_t val0 = 0;
+        std::vector<int32_t> values;
+        EvsEventDesc aNotification0 = {};
+        EvsEventDesc aNotification1 = {};
+        for (auto& cmd : camPrimaryCmds) {
+            // Get a valid parameter value range
+            ParameterRange range;
+            ASSERT_TRUE(pPrimaryCam->getIntParameterRange(cmd, &range).isOk());
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                values.clear();
+                ASSERT_TRUE(
+                        pPrimaryCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+                for (auto&& v : values) {
+                    EXPECT_EQ(v, 0);
+                }
+            }
+
+            // Calculate a parameter value to program.
+            val0 = range.min + (std::rand() % (range.max - range.min));
+            val0 = val0 - (val0 % range.step);
+
+            // Prepare and start event listeners.
+            bool listening0 = false;
+            bool listening1 = false;
+            std::condition_variable eventCond;
+            std::thread listener0 = std::thread([cmd, val0, &aNotification0, &frameHandlerPrimary,
+                                                 &listening0, &listening1, &eventCond]() {
+                listening0 = true;
+                if (listening1) {
+                    eventCond.notify_all();
+                }
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            });
+            std::thread listener1 = std::thread([cmd, val0, &aNotification1, &frameHandlerSecondary,
+                                                 &listening0, &listening1, &eventCond]() {
+                listening1 = true;
+                if (listening0) {
+                    eventCond.notify_all();
+                }
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            });
+
+            // Wait until a listening thread starts.
+            std::mutex eventLock;
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening0 || !listening1) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to program a parameter
+            values.clear();
+            ASSERT_TRUE(pPrimaryCam->setIntParameter(cmd, val0, &values).isOk());
+            for (auto&& v : values) {
+                EXPECT_EQ(val0, v) << "Values are not matched.";
+            }
+
+            // Join a listening thread.
+            if (listener0.joinable()) {
+                listener0.join();
+            }
+            if (listener1.joinable()) {
+                listener1.join();
+            }
+
+            // Verify a change notification
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification0.aType));
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification1.aType));
+            ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification0.payload[0]));
+            ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification1.payload[0]));
+            for (auto&& v : values) {
+                ASSERT_EQ(v, static_cast<int32_t>(aNotification0.payload[1]));
+                ASSERT_EQ(v, static_cast<int32_t>(aNotification1.payload[1]));
+            }
+
+            // Clients expects to receive a parameter change notification
+            // whenever a primary client client adjusts it.
+            values.clear();
+            ASSERT_TRUE(pPrimaryCam->getIntParameter(cmd, &values).isOk());
+            for (auto&& v : values) {
+                EXPECT_EQ(val0, v) << "Values are not matched.";
+            }
+        }
+
+        // Try to adjust a parameter via non-primary client
+        values.clear();
+        ASSERT_FALSE(pSecondaryCam->setIntParameter(camSecondaryCmds[0], val0, &values).isOk());
+
+        // Non-primary client attempts to be a primary client
+        ASSERT_FALSE(pSecondaryCam->setPrimaryClient().isOk());
+
+        // Primary client retires from a primary client role
+        bool listening = false;
+        std::condition_variable eventCond;
+        std::thread listener =
+                std::thread([&aNotification0, &frameHandlerSecondary, &listening, &eventCond]() {
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                    if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification0, true)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                });
+
+        std::mutex eventLock;
+        auto timer = std::chrono::system_clock::now();
+        std::unique_lock<std::mutex> lock(eventLock);
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        ASSERT_TRUE(pPrimaryCam->unsetPrimaryClient().isOk());
+
+        if (listener.joinable()) {
+            listener.join();
+        }
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast<EvsEventType>(aNotification0.aType));
+
+        // Try to adjust a parameter after being retired
+        values.clear();
+        ASSERT_FALSE(pPrimaryCam->setIntParameter(camPrimaryCmds[0], val0, &values).isOk());
+
+        // Non-primary client becomes a primary client
+        ASSERT_TRUE(pSecondaryCam->setPrimaryClient().isOk());
+
+        // Try to adjust a parameter via new primary client
+        for (auto& cmd : camSecondaryCmds) {
+            // Get a valid parameter value range
+            ParameterRange range;
+            ASSERT_TRUE(pSecondaryCam->getIntParameterRange(cmd, &range).isOk());
+
+            values.clear();
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                values.clear();
+                ASSERT_TRUE(
+                        pSecondaryCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+                for (auto&& v : values) {
+                    EXPECT_EQ(v, 0);
+                }
+            }
+
+            // Calculate a parameter value to program.  This is being rounding down.
+            val0 = range.min + (std::rand() % (range.max - range.min));
+            val0 = val0 - (val0 % range.step);
+
+            // Prepare and start event listeners.
+            bool listening0 = false;
+            bool listening1 = false;
+            std::condition_variable eventCond;
+            std::thread listener0 = std::thread([&]() {
+                listening0 = true;
+                if (listening1) {
+                    eventCond.notify_all();
+                }
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            });
+            std::thread listener1 = std::thread([&]() {
+                listening1 = true;
+                if (listening0) {
+                    eventCond.notify_all();
+                }
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            });
+
+            // Wait until a listening thread starts.
+            std::mutex eventLock;
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening0 || !listening1) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to program a parameter
+            values.clear();
+            ASSERT_TRUE(pSecondaryCam->setIntParameter(cmd, val0, &values).isOk());
+
+            // Clients expects to receive a parameter change notification
+            // whenever a primary client client adjusts it.
+            values.clear();
+            ASSERT_TRUE(pSecondaryCam->getIntParameter(cmd, &values).isOk());
+            for (auto&& v : values) {
+                EXPECT_EQ(val0, v) << "Values are not matched.";
+            }
+
+            // Join a listening thread.
+            if (listener0.joinable()) {
+                listener0.join();
+            }
+            if (listener1.joinable()) {
+                listener1.join();
+            }
+
+            // Verify a change notification
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification0.aType));
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification1.aType));
+            ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification0.payload[0]));
+            ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification1.payload[0]));
+            for (auto&& v : values) {
+                ASSERT_EQ(v, static_cast<int32_t>(aNotification0.payload[1]));
+                ASSERT_EQ(v, static_cast<int32_t>(aNotification1.payload[1]));
+            }
+        }
+
+        // New primary client retires from the role
+        ASSERT_TRUE(pSecondaryCam->unsetPrimaryClient().isOk());
+
+        // Shutdown
+        frameHandlerPrimary->shutdown();
+        frameHandlerSecondary->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pPrimaryCam).isOk());
+        ASSERT_TRUE(mEnumerator->closeCamera(pSecondaryCam).isOk());
+        mActiveCameras.clear();
+    }
+}
+
+/*
+ * HighPriorityCameraClient:
+ * EVS client, which owns the display, is priortized and therefore can take over
+ * a primary client role from other EVS clients without the display.
+ */
+TEST_P(EvsAidlTest, HighPriorityCameraClient) {
+    LOG(INFO) << "Starting HighPriorityCameraClient test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Request available display IDs
+    uint8_t targetDisplayId = 0;
+    std::vector<uint8_t> displayIds;
+    ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+    EXPECT_GT(displayIds.size(), 0);
+    targetDisplayId = displayIds[0];
+
+    // Request exclusive access to the EVS display
+    std::shared_ptr<IEvsDisplay> pDisplay;
+    ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+    EXPECT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        // Create two clients
+        std::shared_ptr<IEvsCamera> pCam0;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam0).isOk());
+        EXPECT_NE(pCam0, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam0);
+
+        std::shared_ptr<IEvsCamera> pCam1;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+        EXPECT_NE(pCam1, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam1);
+
+        // Get the parameter list; this test will use the first command in both
+        // lists.
+        std::vector<CameraParam> cam0Cmds, cam1Cmds;
+        ASSERT_TRUE(pCam0->getParameterList(&cam0Cmds).isOk());
+        ASSERT_TRUE(pCam1->getParameterList(&cam1Cmds).isOk());
+        if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) {
+            // Cannot execute this test.
+            return;
+        }
+
+        // Set up a frame receiver object which will fire up its own thread.
+        std::shared_ptr<FrameHandler> frameHandler0 =
+                std::make_shared<FrameHandler>(pCam0, cam, nullptr, FrameHandler::eAutoReturn);
+        std::shared_ptr<FrameHandler> frameHandler1 =
+                std::make_shared<FrameHandler>(pCam1, cam, nullptr, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandler0, nullptr);
+        EXPECT_NE(frameHandler1, nullptr);
+
+        // Activate the display
+        ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME).isOk());
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler0->startStream());
+        ASSERT_TRUE(frameHandler1->startStream());
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        // Client 1 becomes a primary client and programs a parameter.
+
+        // Get a valid parameter value range
+        ParameterRange range;
+        ASSERT_TRUE(pCam1->getIntParameterRange(cam1Cmds[0], &range).isOk());
+
+        // Client1 becomes a primary client
+        ASSERT_TRUE(pCam1->setPrimaryClient().isOk());
+
+        std::vector<int32_t> values;
+        EvsEventDesc aTargetEvent = {};
+        EvsEventDesc aNotification = {};
+        bool listening = false;
+        std::mutex eventLock;
+        std::condition_variable eventCond;
+        if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            std::thread listener =
+                    std::thread([&frameHandler0, &aNotification, &listening, &eventCond] {
+                        listening = true;
+                        eventCond.notify_all();
+
+                        EvsEventDesc aTargetEvent;
+                        aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                        aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+                        aTargetEvent.payload[1] = 0;
+                        if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+                            LOG(WARNING) << "A timer is expired before a target event is fired.";
+                        }
+                    });
+
+            // Wait until a lister starts.
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to turn off auto-focus
+            ASSERT_TRUE(pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+            for (auto&& v : values) {
+                EXPECT_EQ(v, 0);
+            }
+
+            // Join a listener
+            if (listener.joinable()) {
+                listener.join();
+            }
+
+            // Make sure AUTO_FOCUS is off.
+            ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                      EvsEventType::PARAMETER_CHANGED);
+        }
+
+        // Try to program a parameter with a random value [minVal, maxVal] after
+        // rounding it down.
+        int32_t val0 = range.min + (std::rand() % (range.max - range.min));
+        val0 = val0 - (val0 % range.step);
+
+        std::thread listener = std::thread(
+                [&frameHandler1, &aNotification, &listening, &eventCond, &cam1Cmds, val0] {
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                });
+
+        // Wait until a lister starts.
+        listening = false;
+        std::unique_lock<std::mutex> lock(eventLock);
+        auto timer = std::chrono::system_clock::now();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        values.clear();
+        ASSERT_TRUE(pCam1->setIntParameter(cam1Cmds[0], val0, &values).isOk());
+        for (auto&& v : values) {
+            EXPECT_EQ(val0, v);
+        }
+
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify a change notification
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]), cam1Cmds[0]);
+        for (auto&& v : values) {
+            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        listener = std::thread([&frameHandler1, &aNotification, &listening, &eventCond] {
+            listening = true;
+            eventCond.notify_all();
+
+            EvsEventDesc aTargetEvent;
+            aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+            if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
+                LOG(WARNING) << "A timer is expired before a target event is fired.";
+            }
+        });
+
+        // Wait until a lister starts.
+        listening = false;
+        lock.lock();
+        timer = std::chrono::system_clock::now();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        // Client 0 steals a primary client role
+        ASSERT_TRUE(pCam0->forcePrimaryClient(pDisplay).isOk());
+
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::MASTER_RELEASED);
+
+        // Client 0 programs a parameter
+        val0 = range.min + (std::rand() % (range.max - range.min));
+
+        // Rounding down
+        val0 = val0 - (val0 % range.step);
+
+        if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            std::thread listener =
+                    std::thread([&frameHandler1, &aNotification, &listening, &eventCond] {
+                        listening = true;
+                        eventCond.notify_all();
+
+                        EvsEventDesc aTargetEvent;
+                        aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                        aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+                        aTargetEvent.payload[1] = 0;
+                        if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+                            LOG(WARNING) << "A timer is expired before a target event is fired.";
+                        }
+                    });
+
+            // Wait until a lister starts.
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to turn off auto-focus
+            values.clear();
+            ASSERT_TRUE(pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+            for (auto&& v : values) {
+                EXPECT_EQ(v, 0);
+            }
+
+            // Join a listener
+            if (listener.joinable()) {
+                listener.join();
+            }
+
+            // Make sure AUTO_FOCUS is off.
+            ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                      EvsEventType::PARAMETER_CHANGED);
+        }
+
+        listener = std::thread(
+                [&frameHandler0, &aNotification, &listening, &eventCond, &cam0Cmds, val0] {
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                });
+
+        // Wait until a lister starts.
+        listening = false;
+        timer = std::chrono::system_clock::now();
+        lock.lock();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        values.clear();
+        ASSERT_TRUE(pCam0->setIntParameter(cam0Cmds[0], val0, &values).isOk());
+
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
+        // Verify a change notification
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]), cam0Cmds[0]);
+        for (auto&& v : values) {
+            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::NOT_VISIBLE).isOk());
+
+        // Shut down the streamer
+        frameHandler0->shutdown();
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
+        mActiveCameras.clear();
+    }
+
+    // Explicitly release the display
+    ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+}
+
+/*
+ * CameraUseStreamConfigToDisplay:
+ * End to end test of data flowing from the camera to the display.  Similar to
+ * CameraToDisplayRoundTrip test case but this case retrieves available stream
+ * configurations from EVS and uses one of them to start a video stream.
+ */
+TEST_P(EvsAidlTest, CameraUseStreamConfigToDisplay) {
+    LOG(INFO) << "Starting CameraUseStreamConfigToDisplay test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Request available display IDs
+    uint8_t targetDisplayId = 0;
+    std::vector<uint8_t> displayIds;
+    ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+    EXPECT_GT(displayIds.size(), 0);
+    targetDisplayId = displayIds[0];
+
+    // Request exclusive access to the EVS display
+    std::shared_ptr<IEvsDisplay> pDisplay;
+    ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+    EXPECT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        // choose a configuration that has a frame rate faster than minReqFps.
+        Stream targetCfg = {};
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        bool foundCfg = false;
+        if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()),
+                                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                        &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
+            for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+                    if (ptr->width * ptr->height > maxArea && ptr->framerate >= minReqFps) {
+                        targetCfg.width = ptr->width;
+                        targetCfg.height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        }
+        targetCfg.format = static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+        if (!foundCfg) {
+            // Current EVS camera does not provide stream configurations in the
+            // metadata.
+            continue;
+        }
+
+        std::shared_ptr<IEvsCamera> pCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+        EXPECT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        std::shared_ptr<FrameHandler> frameHandler =
+                std::make_shared<FrameHandler>(pCam, cam, pDisplay, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Activate the display
+        ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME).isOk());
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler->startStream());
+
+        // Wait a while to let the data flow
+        static const int kSecondsToWait = 5;
+        const int streamTimeMs =
+                kSecondsToWait * kSecondsToMilliseconds - kMaxStreamStartMilliseconds;
+        const unsigned minimumFramesExpected =
+                streamTimeMs * kMinimumFramesPerSecond / kSecondsToMilliseconds;
+        sleep(kSecondsToWait);
+        unsigned framesReceived = 0;
+        unsigned framesDisplayed = 0;
+        frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+        EXPECT_EQ(framesReceived, framesDisplayed);
+        EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::NOT_VISIBLE).isOk());
+
+        // Shut down the streamer
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+        mActiveCameras.clear();
+    }
+
+    // Explicitly release the display
+    ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+}
+
+/*
+ * MultiCameraStreamUseConfig:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera with same configuration.
+ */
+TEST_P(EvsAidlTest, MultiCameraStreamUseConfig) {
+    LOG(INFO) << "Starting MultiCameraStream test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        // choose a configuration that has a frame rate faster than minReqFps.
+        Stream targetCfg = {};
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        bool foundCfg = false;
+        if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()),
+                                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                        &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
+            for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+                    if (ptr->width * ptr->height > maxArea && ptr->framerate >= minReqFps) {
+                        targetCfg.width = ptr->width;
+                        targetCfg.height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        }
+        targetCfg.format = static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+        if (!foundCfg) {
+            LOG(INFO) << "Device " << cam.id
+                      << " does not provide a list of supported stream configurations, skipped";
+            continue;
+        }
+
+        // Create the first camera client with a selected stream configuration.
+        std::shared_ptr<IEvsCamera> pCam0;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam0).isOk());
+        EXPECT_NE(pCam0, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam0);
+
+        // Try to create the second camera client with different stream
+        // configuration.
+        int32_t id = targetCfg.id;
+        targetCfg.id += 1;  // EVS manager sees only the stream id.
+        std::shared_ptr<IEvsCamera> pCam1;
+        ASSERT_FALSE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+
+        // Try again with same stream configuration.
+        targetCfg.id = id;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+        EXPECT_NE(pCam1, nullptr);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        std::shared_ptr<FrameHandler> frameHandler0 =
+                std::make_shared<FrameHandler>(pCam0, cam, nullptr, FrameHandler::eAutoReturn);
+        std::shared_ptr<FrameHandler> frameHandler1 =
+                std::make_shared<FrameHandler>(pCam1, cam, nullptr, FrameHandler::eAutoReturn);
+        EXPECT_NE(frameHandler0, nullptr);
+        EXPECT_NE(frameHandler1, nullptr);
+
+        // Start the camera's video stream via client 0
+        ASSERT_TRUE(frameHandler0->startStream());
+        ASSERT_TRUE(frameHandler1->startStream());
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Wait a bit, then ensure both clients get at least the required minimum number of frames
+        sleep(5);
+        nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+        unsigned framesReceived0 = 0, framesReceived1 = 0;
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+        framesReceived0 = framesReceived0 - 1;  // Back out the first frame we already waited for
+        framesReceived1 = framesReceived1 - 1;  // Back out the first frame we already waited for
+        nsecs_t runTime = end - firstFrame;
+        float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+        float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+        LOG(INFO) << "Measured camera rate " << std::scientific << framesPerSecond0 << " fps and "
+                  << framesPerSecond1 << " fps";
+        EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+        EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+        // Shutdown one client
+        frameHandler0->shutdown();
+
+        // Read frame counters again
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+        // Wait a bit again
+        sleep(5);
+        unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+        frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+        EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+        EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+        // Shutdown another
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
+        mActiveCameras.clear();
+    }
+}
+
+/*
+ * LogicalCameraMetadata:
+ * Opens logical camera reported by the enumerator and validate its metadata by
+ * checking its capability and locating supporting physical camera device
+ * identifiers.
+ */
+TEST_P(EvsAidlTest, LogicalCameraMetadata) {
+    LOG(INFO) << "Starting LogicalCameraMetadata test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Open and close each camera twice
+    for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (isLogicalCam) {
+            ASSERT_GE(devices.size(), 1) << "Logical camera device must have at least one physical "
+                                            "camera device ID in its metadata.";
+        }
+    }
+}
+
+/*
+ * CameraStreamExternalBuffering:
+ * This is same with CameraStreamBuffering except frame buffers are allocated by
+ * the test client and then imported by EVS framework.
+ */
+TEST_P(EvsAidlTest, CameraStreamExternalBuffering) {
+    LOG(INFO) << "Starting CameraStreamExternalBuffering test";
+
+    // Arbitrary constant (should be > 1 and not too big)
+    static const unsigned int kBuffersToHold = 3;
+
+    // Get the camera list
+    loadCameraList();
+
+    // Acquire the graphics buffer allocator
+    android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
+    const auto usage =
+            GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+    // Test each reported camera
+    for (auto&& cam : mCameraInfo) {
+        // Read a target resolution from the metadata
+        Stream targetCfg = getFirstStreamConfiguration(
+                reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        // Allocate buffers to use
+        std::vector<BufferDesc> buffers;
+        buffers.resize(kBuffersToHold);
+        for (auto i = 0; i < kBuffersToHold; ++i) {
+            unsigned pixelsPerLine;
+            buffer_handle_t memHandle = nullptr;
+            android::status_t result =
+                    alloc.allocate(targetCfg.width, targetCfg.height,
+                                   static_cast<android::PixelFormat>(targetCfg.format),
+                                   /* layerCount = */ 1, usage, &memHandle, &pixelsPerLine,
+                                   /* graphicBufferId = */ 0,
+                                   /* requestorName = */ "CameraStreamExternalBufferingTest");
+            if (result != android::NO_ERROR) {
+                LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
+                // Release previous allocated buffers
+                for (auto j = 0; j < i; j++) {
+                    alloc.free(::android::dupFromAidl(buffers[i].buffer.handle));
+                }
+                return;
+            } else {
+                BufferDesc buf;
+                HardwareBufferDescription* pDesc =
+                        reinterpret_cast<HardwareBufferDescription*>(&buf.buffer.description);
+                pDesc->width = targetCfg.width;
+                pDesc->height = targetCfg.height;
+                pDesc->layers = 1;
+                pDesc->format = targetCfg.format;
+                pDesc->usage = static_cast<BufferUsage>(usage);
+                pDesc->stride = pixelsPerLine;
+                buf.buffer.handle = ::android::dupToAidl(memHandle);
+                buf.bufferId = i;  // Unique number to identify this buffer
+                buffers[i] = std::move(buf);
+            }
+        }
+
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+
+        std::shared_ptr<IEvsCamera> pCam;
+        ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+        EXPECT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        mActiveCameras.push_back(pCam);
+
+        // Request to import buffers
+        int delta = 0;
+        auto status = pCam->importExternalBuffers(buffers, &delta);
+        if (isLogicalCam) {
+            ASSERT_FALSE(status.isOk());
+            continue;
+        }
+
+        ASSERT_TRUE(status.isOk());
+        EXPECT_GE(delta, kBuffersToHold);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        std::shared_ptr<FrameHandler> frameHandler =
+                std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eNoAutoReturn);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler->startStream());
+
+        // Check that the video stream stalls once we've gotten exactly the number of buffers
+        // we requested since we told the frameHandler not to return them.
+        sleep(1);  // 1 second should be enough for at least 5 frames to be delivered worst case
+        unsigned framesReceived = 0;
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        ASSERT_LE(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+
+        // Give back one buffer
+        EXPECT_TRUE(frameHandler->returnHeldBuffer());
+
+        // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+        // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+        unsigned framesReceivedAfter = 0;
+        usleep(110 * kMillisecondsToMicroseconds);
+        frameHandler->getFramesCounters(&framesReceivedAfter, nullptr);
+        EXPECT_EQ(framesReceived + 1, framesReceivedAfter) << "Stream should've resumed";
+
+        // Even when the camera pointer goes out of scope, the FrameHandler object will
+        // keep the stream alive unless we tell it to shutdown.
+        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+        // we have to break that cycle in order for either of them to get cleaned up.
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+        mActiveCameras.clear();
+        // Release buffers
+        for (auto& b : buffers) {
+            alloc.free(::android::dupFromAidl(b.buffer.handle));
+        }
+        buffers.resize(0);
+    }
+}
+
+/*
+ * UltrasonicsArrayOpenClean:
+ * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a
+ * call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays
+ * can be reopened.
+ */
+TEST_P(EvsAidlTest, UltrasonicsArrayOpenClean) {
+    LOG(INFO) << "Starting UltrasonicsArrayOpenClean test";
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // Open and close each ultrasonics array twice
+    for (auto&& ultraInfo : mUltrasonicsArraysInfo) {
+        for (int pass = 0; pass < 2; pass++) {
+            std::shared_ptr<IEvsUltrasonicsArray> pUltrasonicsArray;
+            ASSERT_TRUE(
+                    mEnumerator
+                            ->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId, &pUltrasonicsArray)
+                            .isOk());
+            EXPECT_NE(pUltrasonicsArray, nullptr);
+
+            // Verify that this ultrasonics array self-identifies correctly
+            UltrasonicsArrayDesc desc;
+            ASSERT_TRUE(pUltrasonicsArray->getUltrasonicArrayInfo(&desc).isOk());
+            EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId);
+            LOG(DEBUG) << "Found ultrasonics array " << ultraInfo.ultrasonicsArrayId;
+
+            // Explicitly close the ultrasonics array so resources are released right away
+            ASSERT_TRUE(mEnumerator->closeUltrasonicsArray(pUltrasonicsArray).isOk());
+        }
+    }
+}
+
+// Starts a stream and verifies all data received is valid.
+TEST_P(EvsAidlTest, UltrasonicsVerifyStreamData) {
+    LOG(INFO) << "Starting UltrasonicsVerifyStreamData";
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : mUltrasonicsArraysInfo) {
+        LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
+
+        std::shared_ptr<IEvsUltrasonicsArray> pUltrasonicsArray;
+        ASSERT_TRUE(
+                mEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId, &pUltrasonicsArray)
+                        .isOk());
+        EXPECT_NE(pUltrasonicsArray, nullptr);
+
+        std::shared_ptr<FrameHandlerUltrasonics> frameHandler =
+                std::make_shared<FrameHandlerUltrasonics>(pUltrasonicsArray);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Start stream.
+        ASSERT_TRUE(pUltrasonicsArray->startStream(frameHandler).isOk());
+
+        // Wait 5 seconds to receive frames.
+        sleep(5);
+
+        // Stop stream.
+        ASSERT_TRUE(pUltrasonicsArray->stopStream().isOk());
+
+        EXPECT_GT(frameHandler->getReceiveFramesCount(), 0);
+        EXPECT_TRUE(frameHandler->areAllFramesValid());
+
+        // Explicitly close the ultrasonics array so resources are released right away
+        ASSERT_TRUE(mEnumerator->closeUltrasonicsArray(pUltrasonicsArray).isOk());
+    }
+}
+
+// Sets frames in flight before and after start of stream and verfies success.
+TEST_P(EvsAidlTest, UltrasonicsSetFramesInFlight) {
+    LOG(INFO) << "Starting UltrasonicsSetFramesInFlight";
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : mUltrasonicsArraysInfo) {
+        LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
+
+        std::shared_ptr<IEvsUltrasonicsArray> pUltrasonicsArray;
+        ASSERT_TRUE(
+                mEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId, &pUltrasonicsArray)
+                        .isOk());
+        EXPECT_NE(pUltrasonicsArray, nullptr);
+
+        ASSERT_TRUE(pUltrasonicsArray->setMaxFramesInFlight(10).isOk());
+
+        std::shared_ptr<FrameHandlerUltrasonics> frameHandler =
+                std::make_shared<FrameHandlerUltrasonics>(pUltrasonicsArray);
+        EXPECT_NE(frameHandler, nullptr);
+
+        // Start stream.
+        ASSERT_TRUE(pUltrasonicsArray->startStream(frameHandler).isOk());
+        ASSERT_TRUE(pUltrasonicsArray->setMaxFramesInFlight(5).isOk());
+
+        // Stop stream.
+        ASSERT_TRUE(pUltrasonicsArray->stopStream().isOk());
+
+        // Explicitly close the ultrasonics array so resources are released right away
+        ASSERT_TRUE(mEnumerator->closeUltrasonicsArray(pUltrasonicsArray).isOk());
+    }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EvsAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, EvsAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IEvsEnumerator::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
deleted file mode 100644
index 3307bd6..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (C) 2017 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.
-
-// Vehicle HAL Protobuf library
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_library_static {
-    name: "android.hardware.automotive.vehicle@2.0-libproto-native",
-    visibility: [
-        "//hardware/interfaces/automotive/vehicle/2.0/default:__subpackages__",
-        "//device/generic/car/emulator/vhal_v2_0:__subpackages__",
-    ],
-    vendor: true,
-    host_supported: true,
-    proto: {
-        export_proto_headers: true,
-        type: "lite",
-    },
-    strip: {
-        keep_symbols: true,
-    },
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    srcs: ["VehicleHalProto.proto"],
-}
-
-filegroup {
-    name: "vhal-proto-src",
-    visibility: [
-        "//device/google/trout/hal/vehicle/2.0:__subpackages__",
-    ],
-    srcs: [
-        "VehicleHalProto.proto",
-    ],
-}
-
-genrule {
-    name: "DefaultVehicleHalProtoStub_h",
-    tools: [
-        "aprotoc",
-        "protoc-gen-grpc-cpp-plugin",
-    ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
-    srcs: [
-        "VehicleHalProto.proto",
-    ],
-    out: [
-        "VehicleHalProto.pb.h",
-        "VehicleHalProto.grpc.pb.h",
-    ],
-}
-
-genrule {
-    name: "DefaultVehicleHalProtoStub_cc",
-    tools: [
-        "aprotoc",
-        "protoc-gen-grpc-cpp-plugin",
-    ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
-    srcs: [
-        "VehicleHalProto.proto",
-    ],
-    out: [
-        "VehicleHalProto.pb.cc",
-        "VehicleHalProto.grpc.pb.cc",
-    ],
-}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
deleted file mode 100644
index 58daca6..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package vhal_proto;
-
-// CMD messages are from workstation --> VHAL
-// RESP messages are from VHAL --> workstation
-enum MsgType {
-    GET_CONFIG_CMD                      = 0;
-    GET_CONFIG_RESP                     = 1;
-    GET_CONFIG_ALL_CMD                  = 2;
-    GET_CONFIG_ALL_RESP                 = 3;
-    GET_PROPERTY_CMD                    = 4;
-    GET_PROPERTY_RESP                   = 5;
-    GET_PROPERTY_ALL_CMD                = 6;
-    GET_PROPERTY_ALL_RESP               = 7;
-    SET_PROPERTY_CMD                    = 8;
-    SET_PROPERTY_RESP                   = 9;
-    SET_PROPERTY_ASYNC                  = 10;
-    DEBUG_CMD                           = 11;
-    DEBUG_RESP                          = 12;
-}
-enum Status {
-    RESULT_OK                           = 0;
-    ERROR_UNKNOWN                       = 1;
-    ERROR_UNIMPLEMENTED_CMD             = 2;
-    ERROR_INVALID_PROPERTY              = 3;
-    ERROR_INVALID_AREA_ID               = 4;
-    ERROR_PROPERTY_UNINITIALIZED        = 5;
-    ERROR_WRITE_ONLY_PROPERTY           = 6;
-    ERROR_MEMORY_ALLOC_FAILED           = 7;
-    ERROR_INVALID_OPERATION             = 8;
-}
-
-enum VehiclePropStatus {
-    AVAILABLE                           = 0;
-    UNAVAILABLE                         = 1;
-    ERROR                               = 2;
-}
-
-message VehicleAreaConfig {
-    required int32  area_id             = 1;
-    optional sint32 min_int32_value     = 2;
-    optional sint32 max_int32_value     = 3;
-    optional sint64 min_int64_value     = 4;
-    optional sint64 max_int64_value     = 5;
-    optional float  min_float_value     = 6;
-    optional float  max_float_value     = 7;
-}
-
-message VehiclePropConfig {
-    required int32             prop                = 1;
-    optional int32             access              = 2;
-    optional int32             change_mode         = 3;
-    optional int32             value_type          = 4;
-    optional int32             supported_areas     = 5;     // Deprecated - DO NOT USE
-    repeated VehicleAreaConfig area_configs        = 6;
-    optional int32             config_flags        = 7;
-    repeated int32             config_array        = 8;
-    optional string            config_string       = 9;
-    optional float             min_sample_rate     = 10;
-    optional float             max_sample_rate     = 11;
-};
-
-message VehiclePropValue {
-    // common data
-    required int32  prop                = 1;
-    optional int32  value_type          = 2;
-    optional int64  timestamp           = 3;    // required for valid data from HAL, skipped for set
-    optional VehiclePropStatus  status  = 10;   // required for valid data from HAL, skipped for set
-
-    // values
-    optional int32  area_id             = 4;
-    repeated sint32 int32_values        = 5;    // this also covers boolean value.
-    repeated sint64 int64_values        = 6;
-    repeated float  float_values        = 7;
-    optional string string_value        = 8;
-    optional bytes  bytes_value         = 9;
-};
-
-// This structure is used to notify what values to get from the Vehicle HAL
-message VehiclePropGet {
-    required int32 prop                 = 1;
-    optional int32 area_id              = 2;
-};
-
-message EmulatorMessage {
-    required MsgType           msg_type       = 1;
-    optional Status            status         = 2; // Only for RESP messages
-    repeated VehiclePropGet    prop           = 3; // Provided for getConfig, getProperty commands
-    repeated VehiclePropConfig config         = 4;
-    repeated VehiclePropValue  value          = 5;
-    repeated string            debug_commands = 6; // Required for debug command
-    optional string            debug_result   = 7; // Required for debug RESP messages
-};
diff --git a/automotive/vehicle/OWNERS b/automotive/vehicle/OWNERS
new file mode 100644
index 0000000..429ec39
--- /dev/null
+++ b/automotive/vehicle/OWNERS
@@ -0,0 +1,3 @@
+ericjeong@google.com
+keunyoung@google.com
+shanyu@google.com
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.aidl
index 82f98d8..1031ebb 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.aidl
@@ -23,6 +23,7 @@
      * This requests Android to enter its normal operating state.
      * This may be sent after the AP has reported
      * VehicleApPowerStateReport#DEEP_SLEEP_EXIT,
+     * VehicleApPowerStateReport#HIBERNATION_EXIT,
      * VehicleApPowerStateReport#SHUTDOWN_CANCELLED, or
      * VehicleApPowerStateReport#WAIT_FOR_VHAL.
      */
@@ -31,6 +32,7 @@
      * The power controller issues this request to shutdown the system.
      * This may be sent after the AP has reported
      * VehicleApPowerStateReport#DEEP_SLEEP_EXIT,
+     * VehicleApPowerStateReport#HIBERNATION_EXIT,
      * VehicleApPowerStateReport#ON,
      * VehicleApPowerStateReport#SHUTDOWN_CANCELLED,
      * VehicleApPowerStateReport#SHUTDOWN_POSTPONE,
@@ -59,6 +61,7 @@
      * Completes the shutdown process.
      * This may be sent after the AP has reported
      * VehicleApPowerStateReport#DEEP_SLEEP_ENTRY or
+     * VehicleApPowerStateReport#HIBERNATION_ENTRY or
      * VehicleApPowerStateReport#SHUTDOWN_START. The AP will not report new
      * state information after receiving this request.
      */
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 46a526c..578d045 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -23,7 +23,9 @@
 #include <IVehicleHardware.h>
 #include <VehicleHalTypes.h>
 #include <VehiclePropertyStore.h>
+#include <android-base/parseint.h>
 #include <android-base/result.h>
+#include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
 
 #include <map>
@@ -37,16 +39,8 @@
 namespace vehicle {
 namespace fake {
 
-class FakeVehicleHardware final : public IVehicleHardware {
+class FakeVehicleHardware : public IVehicleHardware {
   public:
-    using SetValuesCallback = std::function<void(
-            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>&)>;
-    using GetValuesCallback = std::function<void(
-            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>&)>;
-    using OnPropertyChangeCallback = std::function<void(
-            const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&)>;
-    using OnPropertySetErrorCallback = std::function<void(const std::vector<SetValueErrorEvent>&)>;
-
     FakeVehicleHardware();
 
     explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
@@ -59,7 +53,7 @@
     // are sent to vehicle bus or before property set confirmation is received. The callback is
     // safe to be called after the function returns and is safe to be called in a different thread.
     ::aidl::android::hardware::automotive::vehicle::StatusCode setValues(
-            SetValuesCallback&& callback,
+            std::shared_ptr<const SetValuesCallback> callback,
             const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
                     requests) override;
 
@@ -67,7 +61,7 @@
     // The callback is safe to be called after the function returns and is safe to be called in a
     // different thread.
     ::aidl::android::hardware::automotive::vehicle::StatusCode getValues(
-            GetValuesCallback&& callback,
+            std::shared_ptr<const GetValuesCallback> callback,
             const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
                     requests) const override;
 
@@ -78,24 +72,36 @@
     ::aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override;
 
     // Register a callback that would be called when there is a property change event from vehicle.
-    void registerOnPropertyChangeEvent(OnPropertyChangeCallback&& callback) override;
+    void registerOnPropertyChangeEvent(
+            std::unique_ptr<const PropertyChangeCallback> callback) override;
 
     // Register a callback that would be called when there is a property set error event from
     // vehicle.
-    void registerOnPropertySetErrorEvent(OnPropertySetErrorCallback&& callback) override;
+    void registerOnPropertySetErrorEvent(
+            std::unique_ptr<const PropertySetErrorCallback> callback) override;
+
+  protected:
+    // mValuePool is also used in mServerSidePropStore.
+    const std::shared_ptr<VehiclePropValuePool> mValuePool;
+    const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
+
+    ::android::base::Result<VehiclePropValuePool::RecyclableType> getValue(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+    ::android::base::Result<void> setValue(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
   private:
     // Expose private methods to unit test.
     friend class FakeVehicleHardwareTestHelper;
 
-    // mValuePool is also used in mServerSidePropStore.
-    const std::shared_ptr<VehiclePropValuePool> mValuePool;
-    const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
     const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
     const std::unique_ptr<FakeUserHal> mFakeUserHal;
     std::mutex mCallbackLock;
-    OnPropertyChangeCallback mOnPropertyChangeCallback GUARDED_BY(mCallbackLock);
-    OnPropertySetErrorCallback mOnPropertySetErrorCallback GUARDED_BY(mCallbackLock);
+    std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback
+            GUARDED_BY(mCallbackLock);
+    std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback
+            GUARDED_BY(mCallbackLock);
 
     void init();
     // Stores the initial value to property store.
@@ -124,6 +130,35 @@
     ::android::base::Result<VehiclePropValuePool::RecyclableType> getUserHalProp(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
     bool isHvacPropAndHvacNotAvailable(int32_t propId);
+
+    std::string dumpAllProperties();
+    std::string dumpOnePropertyByConfig(
+            int rowNumber,
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config);
+    std::string dumpOnePropertyById(int32_t propId, int32_t areaId);
+    std::string dumpHelp();
+    std::string dumpListProperties();
+    std::string dumpSpecificProperty(const std::vector<std::string>& options);
+    std::string dumpSetProperties(const std::vector<std::string>& options);
+
+    template <typename T>
+    ::android::base::Result<T> safelyParseInt(int index, const std::string& s) {
+        T out;
+        if (!::android::base::ParseInt(s, &out)) {
+            return ::android::base::Error() << ::android::base::StringPrintf(
+                           "non-integer argument at index %d: %s\n", index, s.c_str());
+        }
+        return out;
+    }
+    ::android::base::Result<float> safelyParseFloat(int index, const std::string& s);
+    std::vector<std::string> getOptionValues(const std::vector<std::string>& options,
+                                             size_t* index);
+    ::android::base::Result<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
+    parseSetPropOptions(const std::vector<std::string>& options);
+    ::android::base::Result<std::vector<uint8_t>> parseHexString(const std::string& s);
+
+    ::android::base::Result<void> checkArgumentsSize(const std::vector<std::string>& options,
+                                                     size_t minSize);
 };
 
 }  // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 5b2003e..097257e 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "FakeVehicleHardware"
+#define FAKE_VEHICLEHARDWARE_DEBUG false  // STOPSHIP if true.
+
 #include "FakeVehicleHardware.h"
 
 #include <DefaultConfig.h>
@@ -22,7 +25,9 @@
 #include <PropertyUtils.h>
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
+#include <android-base/parsedouble.h>
 #include <android-base/properties.h>
+#include <android-base/strings.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
 
@@ -56,12 +61,31 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
+using ::android::base::EqualsIgnoreCase;
 using ::android::base::Error;
+using ::android::base::ParseFloat;
 using ::android::base::Result;
+using ::android::base::StartsWith;
+using ::android::base::StringPrintf;
 
 const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
 const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";
 
+// A list of supported options for "--set" command.
+const std::unordered_set<std::string> SET_PROP_OPTIONS = {
+        // integer.
+        "-i",
+        // 64bit integer.
+        "-i64",
+        // float.
+        "-f",
+        // string.
+        "-s",
+        // bytes in hex format, e.g. 0xDEADBEEF.
+        "-b",
+        // Area id in integer.
+        "-a"};
+
 }  // namespace
 
 void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
@@ -379,131 +403,435 @@
     return {};
 }
 
-StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback&& callback,
+StatusCode FakeVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
                                           const std::vector<SetValueRequest>& requests) {
-    std::vector<VehiclePropValue> updatedValues;
     std::vector<SetValueResult> results;
     for (auto& request : requests) {
         const VehiclePropValue& value = request.value;
         int propId = value.prop;
 
-        ALOGD("Set value for property ID: %d", propId);
+        if (FAKE_VEHICLEHARDWARE_DEBUG) {
+            ALOGD("Set value for property ID: %d", propId);
+        }
 
         SetValueResult setValueResult;
         setValueResult.requestId = request.requestId;
-        setValueResult.status = StatusCode::OK;
 
-        bool isSpecialValue = false;
-        auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
-
-        if (isSpecialValue) {
-            if (!setSpecialValueResult.ok()) {
-                ALOGE("failed to set special value for property ID: %d, error: %s, status: %d",
-                      propId, getErrorMsg(setSpecialValueResult).c_str(),
-                      getIntErrorCode(setSpecialValueResult));
-                setValueResult.status = getErrorCode(setSpecialValueResult);
-            }
-
-            // Special values are already handled.
-            results.push_back(std::move(setValueResult));
-            continue;
+        if (auto result = setValue(value); !result.ok()) {
+            ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(),
+                  getIntErrorCode(result));
+            setValueResult.status = getErrorCode(result);
+        } else {
+            setValueResult.status = StatusCode::OK;
         }
 
-        auto updatedValue = mValuePool->obtain(value);
-        int64_t timestamp = elapsedRealtimeNano();
-        updatedValue->timestamp = timestamp;
-
-        auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
-        if (!writeResult.ok()) {
-            ALOGE("failed to write value into property store, error: %s, code: %d",
-                  getErrorMsg(writeResult).c_str(), getIntErrorCode(writeResult));
-            setValueResult.status = getErrorCode(writeResult);
-        }
         results.push_back(std::move(setValueResult));
     }
 
     // In the real vhal, the values will be sent to Car ECU. We just pretend it is done here and
     // send back the updated property values to client.
-    callback(std::move(results));
+    (*callback)(std::move(results));
 
     return StatusCode::OK;
 }
 
-StatusCode FakeVehicleHardware::getValues(FakeVehicleHardware::GetValuesCallback&& callback,
+Result<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
+    bool isSpecialValue = false;
+    auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
+
+    if (isSpecialValue) {
+        if (!setSpecialValueResult.ok()) {
+            return Error(getIntErrorCode(setSpecialValueResult))
+                   << StringPrintf("failed to set special value for property ID: %d, error: %s",
+                                   value.prop, getErrorMsg(setSpecialValueResult).c_str());
+        }
+        return {};
+    }
+
+    auto updatedValue = mValuePool->obtain(value);
+    int64_t timestamp = elapsedRealtimeNano();
+    updatedValue->timestamp = timestamp;
+
+    auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+    if (!writeResult.ok()) {
+        return Error(getIntErrorCode(writeResult))
+               << StringPrintf("failed to write value into property store, error: %s",
+                               getErrorMsg(writeResult).c_str());
+    }
+
+    return {};
+}
+
+StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
                                           const std::vector<GetValueRequest>& requests) const {
     std::vector<GetValueResult> results;
     for (auto& request : requests) {
         const VehiclePropValue& value = request.prop;
-        ALOGD("getValues(%d)", value.prop);
+
+        if (FAKE_VEHICLEHARDWARE_DEBUG) {
+            ALOGD("getValues(%d)", value.prop);
+        }
 
         GetValueResult getValueResult;
         getValueResult.requestId = request.requestId;
-        bool isSpecialValue = false;
 
-        auto result = maybeGetSpecialValue(value, &isSpecialValue);
-        if (isSpecialValue) {
-            if (!result.ok()) {
-                ALOGE("failed to get special value: %d, error: %s, code: %d", value.prop,
-                      getErrorMsg(result).c_str(), getIntErrorCode(result));
-                getValueResult.status = getErrorCode(result);
-            } else {
-                getValueResult.status = StatusCode::OK;
-                getValueResult.prop = *result.value();
-            }
-            results.push_back(std::move(getValueResult));
-            continue;
-        }
-
-        auto readResult = mServerSidePropStore->readValue(value);
-        if (!readResult.ok()) {
-            StatusCode errorCode = getErrorCode(readResult);
-            if (errorCode == StatusCode::NOT_AVAILABLE) {
-                ALOGW("%s", "value has not been set yet");
-            } else {
-                ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(readResult).c_str(),
-                      toInt(errorCode));
-            }
-            getValueResult.status = errorCode;
+        auto result = getValue(value);
+        if (!result.ok()) {
+            ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(result).c_str(),
+                  getIntErrorCode(result));
+            getValueResult.status = getErrorCode(result);
         } else {
             getValueResult.status = StatusCode::OK;
-            getValueResult.prop = *readResult.value();
+            getValueResult.prop = *result.value();
         }
         results.push_back(std::move(getValueResult));
     }
 
-    callback(std::move(results));
+    // In a real VHAL implementation, getValue would be async and we would call the callback after
+    // we actually received the values from vehicle bus. Here we are getting the result
+    // synchronously so we could call the callback here.
+    (*callback)(std::move(results));
 
     return StatusCode::OK;
 }
 
-DumpResult FakeVehicleHardware::dump(const std::vector<std::string>&) {
+Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::getValue(
+        const VehiclePropValue& value) const {
+    bool isSpecialValue = false;
+    auto result = maybeGetSpecialValue(value, &isSpecialValue);
+    if (isSpecialValue) {
+        if (!result.ok()) {
+            return Error(getIntErrorCode(result))
+                   << StringPrintf("failed to get special value: %d, error: %s", value.prop,
+                                   getErrorMsg(result).c_str());
+        } else {
+            return std::move(result);
+        }
+    }
+
+    auto readResult = mServerSidePropStore->readValue(value);
+    if (!readResult.ok()) {
+        StatusCode errorCode = getErrorCode(readResult);
+        if (errorCode == StatusCode::NOT_AVAILABLE) {
+            return Error(toInt(errorCode)) << "value has not been set yet";
+        } else {
+            return Error(toInt(errorCode))
+                   << "failed to get value, error: " << getErrorMsg(readResult);
+        }
+    }
+
+    return std::move(readResult);
+}
+
+DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
     DumpResult result;
-    // TODO(b/201830716): Implement this.
+    result.callerShouldDumpState = false;
+    if (options.size() == 0) {
+        // We only want caller to dump default state when there is no options.
+        result.callerShouldDumpState = true;
+        result.buffer = dumpAllProperties();
+        return result;
+    }
+    std::string option = options[0];
+    if (EqualsIgnoreCase(option, "--help")) {
+        result.buffer = dumpHelp();
+        return result;
+    } else if (EqualsIgnoreCase(option, "--list")) {
+        result.buffer = dumpListProperties();
+    } else if (EqualsIgnoreCase(option, "--get")) {
+        result.buffer = dumpSpecificProperty(options);
+    } else if (EqualsIgnoreCase(option, "--set")) {
+        result.buffer = dumpSetProperties(options);
+    } else {
+        result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
+    }
     return result;
 }
 
+std::string FakeVehicleHardware::dumpHelp() {
+    return "Usage: \n\n"
+           "[no args]: dumps (id and value) all supported properties \n"
+           "--help: shows this help\n"
+           "--list: lists the ids of all supported properties\n"
+           "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n"
+           "--set <PROP> [-i INT_VALUE [INT_VALUE ...]] [-i64 INT64_VALUE [INT64_VALUE ...]] "
+           "[-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
+           "[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. "
+           "Notice that the string, bytes and area value can be set just once, while the other can"
+           " have multiple values (so they're used in the respective array), "
+           "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n";
+}
+
+std::string FakeVehicleHardware::dumpAllProperties() {
+    auto configs = mServerSidePropStore->getAllConfigs();
+    if (configs.size() == 0) {
+        return "no properties to dump\n";
+    }
+    std::string msg = StringPrintf("dumping %zu properties\n", configs.size());
+    int rowNumber = 1;
+    for (const VehiclePropConfig& config : configs) {
+        msg += dumpOnePropertyByConfig(rowNumber++, config);
+    }
+    return msg;
+}
+
+std::string FakeVehicleHardware::dumpOnePropertyByConfig(int rowNumber,
+                                                         const VehiclePropConfig& config) {
+    size_t numberAreas = config.areaConfigs.size();
+    std::string msg = "";
+    if (numberAreas == 0) {
+        msg += StringPrintf("%d: ", rowNumber);
+        msg += dumpOnePropertyById(config.prop, /* areaId= */ 0);
+        return msg;
+    }
+    for (size_t j = 0; j < numberAreas; ++j) {
+        if (numberAreas > 1) {
+            msg += StringPrintf("%d-%zu: ", rowNumber, j);
+        } else {
+            msg += StringPrintf("%d: ", rowNumber);
+        }
+        msg += dumpOnePropertyById(config.prop, config.areaConfigs[j].areaId);
+    }
+    return msg;
+}
+
+std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
+    VehiclePropValue value = {
+            .prop = propId,
+            .areaId = areaId,
+    };
+    bool isSpecialValue = false;
+    auto result = maybeGetSpecialValue(value, &isSpecialValue);
+    if (!isSpecialValue) {
+        result = mServerSidePropStore->readValue(value);
+    }
+    if (!result.ok()) {
+        return StringPrintf("failed to read property value: %d, error: %s, code: %d\n", propId,
+                            getErrorMsg(result).c_str(), getIntErrorCode(result));
+
+    } else {
+        return result.value()->toString() + "\n";
+    }
+}
+
+std::string FakeVehicleHardware::dumpListProperties() {
+    auto configs = mServerSidePropStore->getAllConfigs();
+    if (configs.size() == 0) {
+        return "no properties to list\n";
+    }
+    int rowNumber = 1;
+    std::string msg = StringPrintf("listing %zu properties\n", configs.size());
+    for (const auto& config : configs) {
+        msg += StringPrintf("%d: %d\n", rowNumber++, config.prop);
+    }
+    return msg;
+}
+
+Result<void> FakeVehicleHardware::checkArgumentsSize(const std::vector<std::string>& options,
+                                                     size_t minSize) {
+    size_t size = options.size();
+    if (size >= minSize) {
+        return {};
+    }
+    return Error() << StringPrintf("Invalid number of arguments: required at least %zu, got %zu\n",
+                                   minSize, size);
+}
+
+std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
+    if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
+        return getErrorMsg(result);
+    }
+
+    // options[0] is the command itself...
+    int rowNumber = 1;
+    size_t size = options.size();
+    std::string msg = "";
+    for (size_t i = 1; i < size; ++i) {
+        auto propResult = safelyParseInt<int32_t>(i, options[i]);
+        if (!propResult.ok()) {
+            msg += getErrorMsg(propResult);
+            continue;
+        }
+        int32_t prop = propResult.value();
+        auto result = mServerSidePropStore->getConfig(prop);
+        if (!result.ok()) {
+            msg += StringPrintf("No property %d\n", prop);
+            continue;
+        }
+        msg += dumpOnePropertyByConfig(rowNumber++, *result.value());
+    }
+    return msg;
+}
+
+std::vector<std::string> FakeVehicleHardware::getOptionValues(
+        const std::vector<std::string>& options, size_t* index) {
+    std::vector<std::string> values;
+    while (*index < options.size()) {
+        std::string option = options[*index];
+        if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
+            return std::move(values);
+        }
+        values.push_back(option);
+        (*index)++;
+    }
+    return std::move(values);
+}
+
+Result<VehiclePropValue> FakeVehicleHardware::parseSetPropOptions(
+        const std::vector<std::string>& options) {
+    // Options format:
+    // --set PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...] [-b b1 b2...] [-a a]
+    size_t optionIndex = 1;
+    auto result = safelyParseInt<int32_t>(optionIndex, options[optionIndex]);
+    if (!result.ok()) {
+        return Error() << StringPrintf("Property value: \"%s\" is not a valid int: %s\n",
+                                       options[optionIndex].c_str(), getErrorMsg(result).c_str());
+    }
+    VehiclePropValue prop = {};
+    prop.prop = result.value();
+    prop.status = VehiclePropertyStatus::AVAILABLE;
+    optionIndex++;
+    std::unordered_set<std::string> parsedOptions;
+
+    while (optionIndex < options.size()) {
+        std::string type = options[optionIndex];
+        optionIndex++;
+        size_t currentIndex = optionIndex;
+        std::vector<std::string> values = getOptionValues(options, &optionIndex);
+        if (parsedOptions.find(type) != parsedOptions.end()) {
+            return Error() << StringPrintf("Duplicate \"%s\" options\n", type.c_str());
+        }
+        parsedOptions.insert(type);
+        if (EqualsIgnoreCase(type, "-i")) {
+            if (values.size() == 0) {
+                return Error() << "No values specified when using \"-i\"\n";
+            }
+            prop.value.int32Values.resize(values.size());
+            for (size_t i = 0; i < values.size(); i++) {
+                auto int32Result = safelyParseInt<int32_t>(currentIndex + i, values[i]);
+                if (!int32Result.ok()) {
+                    return Error()
+                           << StringPrintf("Value: \"%s\" is not a valid int: %s\n",
+                                           values[i].c_str(), getErrorMsg(int32Result).c_str());
+                }
+                prop.value.int32Values[i] = int32Result.value();
+            }
+        } else if (EqualsIgnoreCase(type, "-i64")) {
+            if (values.size() == 0) {
+                return Error() << "No values specified when using \"-i64\"\n";
+            }
+            prop.value.int64Values.resize(values.size());
+            for (size_t i = 0; i < values.size(); i++) {
+                auto int64Result = safelyParseInt<int64_t>(currentIndex + i, values[i]);
+                if (!int64Result.ok()) {
+                    return Error()
+                           << StringPrintf("Value: \"%s\" is not a valid int64: %s\n",
+                                           values[i].c_str(), getErrorMsg(int64Result).c_str());
+                }
+                prop.value.int64Values[i] = int64Result.value();
+            }
+        } else if (EqualsIgnoreCase(type, "-f")) {
+            if (values.size() == 0) {
+                return Error() << "No values specified when using \"-f\"\n";
+            }
+            prop.value.floatValues.resize(values.size());
+            for (size_t i = 0; i < values.size(); i++) {
+                auto floatResult = safelyParseFloat(currentIndex + i, values[i]);
+                if (!floatResult.ok()) {
+                    return Error()
+                           << StringPrintf("Value: \"%s\" is not a valid float: %s\n",
+                                           values[i].c_str(), getErrorMsg(floatResult).c_str());
+                }
+                prop.value.floatValues[i] = floatResult.value();
+            }
+        } else if (EqualsIgnoreCase(type, "-s")) {
+            if (values.size() != 1) {
+                return Error() << "Expect exact one value when using \"-s\"\n";
+            }
+            prop.value.stringValue = values[0];
+        } else if (EqualsIgnoreCase(type, "-b")) {
+            if (values.size() != 1) {
+                return Error() << "Expect exact one value when using \"-b\"\n";
+            }
+            auto bytesResult = parseHexString(values[0]);
+            if (!bytesResult.ok()) {
+                return Error() << StringPrintf("value: \"%s\" is not a valid hex string: %s\n",
+                                               values[0].c_str(), getErrorMsg(bytesResult).c_str());
+            }
+            prop.value.byteValues = std::move(bytesResult.value());
+        } else if (EqualsIgnoreCase(type, "-a")) {
+            if (values.size() != 1) {
+                return Error() << "Expect exact one value when using \"-a\"\n";
+            }
+            auto int32Result = safelyParseInt<int32_t>(currentIndex, values[0]);
+            if (!int32Result.ok()) {
+                return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n",
+                                               values[0].c_str(), getErrorMsg(int32Result).c_str());
+            }
+            prop.areaId = int32Result.value();
+        } else {
+            return Error() << StringPrintf("Unknown option: %s\n", type.c_str());
+        }
+    }
+
+    return prop;
+}
+
+std::string FakeVehicleHardware::dumpSetProperties(const std::vector<std::string>& options) {
+    if (auto result = checkArgumentsSize(options, 3); !result.ok()) {
+        return getErrorMsg(result);
+    }
+
+    auto parseResult = parseSetPropOptions(options);
+    if (!parseResult.ok()) {
+        return getErrorMsg(parseResult);
+    }
+    VehiclePropValue prop = std::move(parseResult.value());
+    ALOGD("Dump: Setting property: %s", prop.toString().c_str());
+
+    bool isSpecialValue = false;
+    auto setResult = maybeSetSpecialValue(prop, &isSpecialValue);
+
+    if (!isSpecialValue) {
+        auto updatedValue = mValuePool->obtain(prop);
+        updatedValue->timestamp = elapsedRealtimeNano();
+        setResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+    }
+
+    if (setResult.ok()) {
+        return StringPrintf("Set property: %s\n", prop.toString().c_str());
+    }
+    return StringPrintf("failed to set property: %s, error: %s\n", prop.toString().c_str(),
+                        getErrorMsg(setResult).c_str());
+}
+
 StatusCode FakeVehicleHardware::checkHealth() {
-    // TODO(b/201830716): Implement this.
+    // Always return OK for checkHealth.
     return StatusCode::OK;
 }
 
-void FakeVehicleHardware::registerOnPropertyChangeEvent(OnPropertyChangeCallback&& callback) {
+void FakeVehicleHardware::registerOnPropertyChangeEvent(
+        std::unique_ptr<const PropertyChangeCallback> callback) {
     std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
     mOnPropertyChangeCallback = std::move(callback);
 }
 
-void FakeVehicleHardware::registerOnPropertySetErrorEvent(OnPropertySetErrorCallback&& callback) {
+void FakeVehicleHardware::registerOnPropertySetErrorEvent(
+        std::unique_ptr<const PropertySetErrorCallback> callback) {
     std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
     mOnPropertySetErrorCallback = std::move(callback);
 }
 
 void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
     std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
-    if (mOnPropertyChangeCallback != nullptr) {
-        std::vector<VehiclePropValue> updatedValues;
-        updatedValues.push_back(value);
-        mOnPropertyChangeCallback(std::move(updatedValues));
+
+    if (mOnPropertyChangeCallback == nullptr) {
+        return;
     }
+
+    std::vector<VehiclePropValue> updatedValues;
+    updatedValues.push_back(value);
+    (*mOnPropertyChangeCallback)(std::move(updatedValues));
 }
 
 void FakeVehicleHardware::maybeOverrideProperties(const char* overrideDir) {
@@ -539,6 +867,49 @@
     }
 }
 
+Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
+    float out;
+    if (!ParseFloat(s, &out)) {
+        return Error() << StringPrintf("non-float argument at index %d: %s\n", index, s.c_str());
+    }
+    return out;
+}
+
+Result<std::vector<uint8_t>> FakeVehicleHardware::parseHexString(const std::string& s) {
+    std::vector<uint8_t> bytes;
+    if (s.size() % 2 != 0) {
+        return Error() << StringPrintf("invalid hex string: %s, should have even size\n",
+                                       s.c_str());
+    }
+    if (!StartsWith(s, "0x")) {
+        return Error() << StringPrintf("hex string should start with \"0x\", got %s\n", s.c_str());
+    }
+    std::string subs = s.substr(2);
+    std::transform(subs.begin(), subs.end(), subs.begin(),
+                   [](unsigned char c) { return std::tolower(c); });
+
+    bool highDigit = true;
+    for (size_t i = 0; i < subs.size(); i++) {
+        char c = subs[i];
+        uint8_t v;
+        if (c >= '0' && c <= '9') {
+            v = c - '0';
+        } else if (c >= 'a' && c <= 'f') {
+            v = c - 'a' + 10;
+        } else {
+            return Error() << StringPrintf("invalid character %c in hex string %s\n", c,
+                                           subs.c_str());
+        }
+        if (highDigit) {
+            bytes.push_back(v * 16);
+        } else {
+            bytes[bytes.size() - 1] += v;
+        }
+        highDigit = !highDigit;
+    }
+    return bytes;
+}
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 88834f3..0812c2a 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -24,6 +24,7 @@
 
 #include <android-base/expected.h>
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <utils/Log.h>
@@ -52,13 +53,16 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::base::expected;
+using ::android::base::StringPrintf;
 using ::android::base::unexpected;
 using ::testing::ContainerEq;
+using ::testing::ContainsRegex;
 using ::testing::Eq;
 using ::testing::IsSubsetOf;
 using ::testing::WhenSortedBy;
 
 constexpr int INVALID_PROP_ID = 0;
+constexpr char CAR_MAKE[] = "Default Car";
 
 }  // namespace
 
@@ -76,24 +80,25 @@
 class FakeVehicleHardwareTest : public ::testing::Test {
   protected:
     void SetUp() override {
-        getHardware()->registerOnPropertyChangeEvent(
+        auto callback = std::make_unique<IVehicleHardware::PropertyChangeCallback>(
                 [this](const std::vector<VehiclePropValue>& values) {
-                    return onPropertyChangeEvent(values);
+                    onPropertyChangeEvent(values);
                 });
+        getHardware()->registerOnPropertyChangeEvent(std::move(callback));
+        mSetValuesCallback = std::make_shared<IVehicleHardware::SetValuesCallback>(
+                [this](std::vector<SetValueResult> results) { onSetValues(results); });
+        mGetValuesCallback = std::make_shared<IVehicleHardware::GetValuesCallback>(
+                [this](std::vector<GetValueResult> results) { onGetValues(results); });
     }
 
     FakeVehicleHardware* getHardware() { return &mHardware; }
 
     StatusCode setValues(const std::vector<SetValueRequest>& requests) {
-        return getHardware()->setValues(
-                [this](const std::vector<SetValueResult> results) { return onSetValues(results); },
-                requests);
+        return getHardware()->setValues(mSetValuesCallback, requests);
     }
 
     StatusCode getValues(const std::vector<GetValueRequest>& requests) {
-        return getHardware()->getValues(
-                [this](const std::vector<GetValueResult> results) { return onGetValues(results); },
-                requests);
+        return getHardware()->getValues(mGetValuesCallback, requests);
     }
 
     StatusCode setValue(const VehiclePropValue& value) {
@@ -153,7 +158,7 @@
         return toInt(result.error());
     }
 
-    void onSetValues(const std::vector<SetValueResult> results) {
+    void onSetValues(std::vector<SetValueResult> results) {
         for (auto& result : results) {
             mSetValueResults.push_back(result);
         }
@@ -161,7 +166,7 @@
 
     const std::vector<SetValueResult>& getSetValueResults() { return mSetValueResults; }
 
-    void onGetValues(const std::vector<GetValueResult> results) {
+    void onGetValues(std::vector<GetValueResult> results) {
         for (auto& result : results) {
             mGetValueResults.push_back(result);
         }
@@ -169,7 +174,7 @@
 
     const std::vector<GetValueResult>& getGetValueResults() { return mGetValueResults; }
 
-    void onPropertyChangeEvent(const std::vector<VehiclePropValue>& values) {
+    void onPropertyChangeEvent(std::vector<VehiclePropValue> values) {
         for (auto& value : values) {
             mChangedProperties.push_back(value);
         }
@@ -245,6 +250,8 @@
     std::vector<SetValueResult> mSetValueResults;
     std::vector<GetValueResult> mGetValueResults;
     std::vector<VehiclePropValue> mChangedProperties;
+    std::shared_ptr<IVehicleHardware::SetValuesCallback> mSetValuesCallback;
+    std::shared_ptr<IVehicleHardware::GetValuesCallback> mGetValuesCallback;
 };
 
 TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
@@ -367,9 +374,9 @@
 
 TEST_F(FakeVehicleHardwareTest, testRegisterOnPropertyChangeEvent) {
     // We have already registered this callback in Setup, here we are registering again.
-    getHardware()->registerOnPropertyChangeEvent(std::bind(
-            &FakeVehicleHardwareTest_testRegisterOnPropertyChangeEvent_Test::onPropertyChangeEvent,
-            this, std::placeholders::_1));
+    auto callback = std::make_unique<IVehicleHardware::PropertyChangeCallback>(
+            [this](const std::vector<VehiclePropValue>& values) { onPropertyChangeEvent(values); });
+    getHardware()->registerOnPropertyChangeEvent(std::move(callback));
 
     auto testValues = getTestPropValues();
     std::vector<SetValueRequest> requests;
@@ -1200,6 +1207,261 @@
                          }));
 }
 
+TEST_F(FakeVehicleHardwareTest, testDumpAllProperties) {
+    std::vector<std::string> options;
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_TRUE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer, ContainsRegex("dumping .+ properties"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpHelp) {
+    std::vector<std::string> options;
+    options.push_back("--help");
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer, ContainsRegex("Usage: "));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpListProperties) {
+    std::vector<std::string> options;
+    options.push_back("--list");
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer, ContainsRegex("listing .+ properties"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificProperties) {
+    std::vector<std::string> options;
+    options.push_back("--get");
+    std::string prop1 = std::to_string(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+    std::string prop2 = std::to_string(toInt(VehicleProperty::TIRE_PRESSURE));
+    options.push_back(prop1);
+    options.push_back(prop2);
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer,
+                ContainsRegex(StringPrintf("1:.*prop: %s.*\n2-0:.*prop: %s.*\n2-1:.*prop: %s.*\n",
+                                           prop1.c_str(), prop2.c_str(), prop2.c_str())));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesInvalidProp) {
+    std::vector<std::string> options;
+    options.push_back("--get");
+    std::string prop1 = std::to_string(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+    std::string prop2 = std::to_string(INVALID_PROP_ID);
+    options.push_back(prop1);
+    options.push_back(prop2);
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer, ContainsRegex(StringPrintf("1:.*prop: %s.*\nNo property %d\n",
+                                                          prop1.c_str(), INVALID_PROP_ID)));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesNoArg) {
+    std::vector<std::string> options;
+    options.push_back("--get");
+
+    // No arguments.
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer, ContainsRegex("Invalid number of arguments"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpInvalidOptions) {
+    std::vector<std::string> options;
+    options.push_back("--invalid");
+
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
+}
+
+struct SetPropTestCase {
+    std::string test_name;
+    std::vector<std::string> options;
+    bool success;
+    std::string errorMsg = "";
+};
+
+class FakeVehicleHardwareSetPropTest : public FakeVehicleHardwareTest,
+                                       public testing::WithParamInterface<SetPropTestCase> {};
+
+TEST_P(FakeVehicleHardwareSetPropTest, cmdSetOneProperty) {
+    const SetPropTestCase& tc = GetParam();
+
+    DumpResult result = getHardware()->dump(tc.options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_NE(result.buffer, "");
+    if (tc.success) {
+        ASSERT_THAT(result.buffer, ContainsRegex("Set property:"));
+    } else {
+        ASSERT_THAT(result.buffer, ContainsRegex(tc.errorMsg));
+    }
+}
+
+std::vector<SetPropTestCase> GenSetPropParams() {
+    std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
+    return {
+            {"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, true},
+            {"success_set_bytes", {"--set", infoMakeProperty, "-b", "0xdeadbeef"}, true},
+            {"success_set_bytes_caps", {"--set", infoMakeProperty, "-b", "0xDEADBEEF"}, true},
+            {"success_set_int", {"--set", infoMakeProperty, "-i", "2147483647"}, true},
+            {"success_set_ints",
+             {"--set", infoMakeProperty, "-i", "2147483647", "0", "-2147483648"},
+             true},
+            {"success_set_int64",
+             {"--set", infoMakeProperty, "-i64", "-9223372036854775808"},
+             true},
+            {"success_set_int64s",
+             {"--set", infoMakeProperty, "-i64", "-9223372036854775808", "0",
+              "9223372036854775807"},
+             true},
+            {"success_set_float", {"--set", infoMakeProperty, "-f", "1.175494351E-38"}, true},
+            {"success_set_floats",
+             {"--set", infoMakeProperty, "-f", "-3.402823466E+38", "0", "3.402823466E+38"},
+             true},
+            {"success_set_area", {"--set", infoMakeProperty, "-a", "2147483647"}, true},
+            {"fail_no_options", {"--set", infoMakeProperty}, false, "Invalid number of arguments"},
+            {"fail_less_than_4_options",
+             {"--set", infoMakeProperty, "-i"},
+             false,
+             "No values specified"},
+            {"fail_unknown_options", {"--set", infoMakeProperty, "-abcd"}, false, "Unknown option"},
+            {"fail_invalid_property",
+             {"--set", "not valid", "-s", CAR_MAKE},
+             false,
+             "not a valid int"},
+            {"fail_duplicate_string",
+             {"--set", infoMakeProperty, "-s", CAR_MAKE, "-s", CAR_MAKE},
+             false,
+             "Duplicate \"-s\" options"},
+            {"fail_multiple_strings",
+             {"--set", infoMakeProperty, "-s", CAR_MAKE, CAR_MAKE},
+             false,
+             "Expect exact one value"},
+            {"fail_no_string_value",
+             {"--set", infoMakeProperty, "-s", "-a", "1234"},
+             false,
+             "Expect exact one value"},
+            {"fail_duplicate_bytes",
+             {"--set", infoMakeProperty, "-b", "0xdeadbeef", "-b", "0xdeadbeef"},
+             false,
+             "Duplicate \"-b\" options"},
+            {"fail_multiple_bytes",
+             {"--set", infoMakeProperty, "-b", "0xdeadbeef", "0xdeadbeef"},
+             false,
+             "Expect exact one value"},
+            {"fail_invalid_bytes",
+             {"--set", infoMakeProperty, "-b", "0xgood"},
+             false,
+             "not a valid hex string"},
+            {"fail_invalid_bytes_no_prefix",
+             {"--set", infoMakeProperty, "-b", "deadbeef"},
+             false,
+             "not a valid hex string"},
+            {"fail_invalid_int",
+             {"--set", infoMakeProperty, "-i", "abc"},
+             false,
+             "not a valid int"},
+            {"fail_int_out_of_range",
+             {"--set", infoMakeProperty, "-i", "2147483648"},
+             false,
+             "not a valid int"},
+            {"fail_no_int_value",
+             {"--set", infoMakeProperty, "-i", "-s", CAR_MAKE},
+             false,
+             "No values specified"},
+            {"fail_invalid_int64",
+             {"--set", infoMakeProperty, "-i64", "abc"},
+             false,
+             "not a valid int64"},
+            {"fail_int64_out_of_range",
+             {"--set", infoMakeProperty, "-i64", "-9223372036854775809"},
+             false,
+             "not a valid int64"},
+            {"fail_no_int64_value",
+             {"--set", infoMakeProperty, "-i64", "-s", CAR_MAKE},
+             false,
+             "No values specified"},
+            {"fail_invalid_float",
+             {"--set", infoMakeProperty, "-f", "abc"},
+             false,
+             "not a valid float"},
+            {"fail_float_out_of_range",
+             {"--set", infoMakeProperty, "-f", "-3.402823466E+39"},
+             false,
+             "not a valid float"},
+            {"fail_no_float_value",
+             {"--set", infoMakeProperty, "-f", "-s", CAR_MAKE},
+             false,
+             "No values specified"},
+            {"fail_multiple_areas",
+             {"--set", infoMakeProperty, "-a", "2147483648", "0"},
+             false,
+             "Expect exact one value"},
+            {"fail_invalid_area",
+             {"--set", infoMakeProperty, "-a", "abc"},
+             false,
+             "not a valid int"},
+            {"fail_area_out_of_range",
+             {"--set", infoMakeProperty, "-a", "2147483648"},
+             false,
+             "not a valid int"},
+            {"fail_no_area_value",
+             {"--set", infoMakeProperty, "-a", "-s", CAR_MAKE},
+             false,
+             "Expect exact one value"},
+    };
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        FakeVehicleHardwareSetPropTests, FakeVehicleHardwareSetPropTest,
+        testing::ValuesIn(GenSetPropParams()),
+        [](const testing::TestParamInfo<FakeVehicleHardwareSetPropTest::ParamType>& info) {
+            return info.param.test_name;
+        });
+
+TEST_F(FakeVehicleHardwareTest, SetComplexPropTest) {
+    std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
+    getHardware()->dump({"--set", infoMakeProperty,      "-s",   CAR_MAKE,
+                         "-b",    "0xdeadbeef",          "-i",   "2147483647",
+                         "0",     "-2147483648",         "-i64", "-9223372036854775808",
+                         "0",     "9223372036854775807", "-f",   "-3.402823466E+38",
+                         "0",     "3.402823466E+38",     "-a",   "123"});
+    VehiclePropValue requestProp;
+    requestProp.prop = toInt(VehicleProperty::INFO_MAKE);
+    requestProp.areaId = 123;
+    auto result = getValue(requestProp);
+    ASSERT_TRUE(result.ok());
+    VehiclePropValue value = result.value();
+    ASSERT_EQ(value.prop, toInt(VehicleProperty::INFO_MAKE));
+    ASSERT_EQ(value.areaId, 123);
+    ASSERT_STREQ(CAR_MAKE, value.value.stringValue.c_str());
+    uint8_t bytes[] = {0xde, 0xad, 0xbe, 0xef};
+    ASSERT_FALSE(memcmp(bytes, value.value.byteValues.data(), sizeof(bytes)));
+    ASSERT_EQ(3u, value.value.int32Values.size());
+    ASSERT_EQ(2147483647, value.value.int32Values[0]);
+    ASSERT_EQ(0, value.value.int32Values[1]);
+    ASSERT_EQ(-2147483648, value.value.int32Values[2]);
+    ASSERT_EQ(3u, value.value.int64Values.size());
+    // -9223372036854775808 is not a valid literal since '-' and '9223372036854775808' would be two
+    // tokens and the later does not fit in unsigned long long.
+    ASSERT_EQ(-9223372036854775807 - 1, value.value.int64Values[0]);
+    ASSERT_EQ(0, value.value.int64Values[1]);
+    ASSERT_EQ(9223372036854775807, value.value.int64Values[2]);
+    ASSERT_EQ(3u, value.value.floatValues.size());
+    ASSERT_EQ(-3.402823466E+38f, value.value.floatValues[0]);
+    ASSERT_EQ(0.0f, value.value.floatValues[1]);
+    ASSERT_EQ(3.402823466E+38f, value.value.floatValues[2]);
+}
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index 2e12327..4b9de2d 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -19,6 +19,7 @@
 
 #include <VehicleHalTypes.h>
 
+#include <memory>
 #include <vector>
 
 namespace android {
@@ -49,6 +50,14 @@
 // with a VehicleHardware through this interface.
 class IVehicleHardware {
   public:
+    using SetValuesCallback = std::function<void(
+            std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>)>;
+    using GetValuesCallback = std::function<void(
+            std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>)>;
+    using PropertyChangeCallback = std::function<void(
+            std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>)>;
+    using PropertySetErrorCallback = std::function<void(std::vector<SetValueErrorEvent>)>;
+
     virtual ~IVehicleHardware() = default;
 
     // Get all the property configs.
@@ -59,9 +68,7 @@
     // are sent to vehicle bus or before property set confirmation is received. The callback is
     // safe to be called after the function returns and is safe to be called in a different thread.
     virtual ::aidl::android::hardware::automotive::vehicle::StatusCode setValues(
-            std::function<void(const std::vector<
-                               ::aidl::android::hardware::automotive::vehicle::SetValueResult>&)>&&
-                    callback,
+            std::shared_ptr<const SetValuesCallback> callback,
             const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
                     requests) = 0;
 
@@ -69,9 +76,7 @@
     // The callback is safe to be called after the function returns and is safe to be called in a
     // different thread.
     virtual ::aidl::android::hardware::automotive::vehicle::StatusCode getValues(
-            std::function<void(const std::vector<
-                               ::aidl::android::hardware::automotive::vehicle::GetValueResult>&)>&&
-                    callback,
+            std::shared_ptr<const GetValuesCallback> callback,
             const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
                     requests) const = 0;
 
@@ -83,13 +88,12 @@
 
     // Register a callback that would be called when there is a property change event from vehicle.
     virtual void registerOnPropertyChangeEvent(
-            std::function<void(const std::vector<::aidl::android::hardware::automotive::vehicle::
-                                                         VehiclePropValue>&)>&& callback) = 0;
+            std::unique_ptr<const PropertyChangeCallback> callback) = 0;
 
     // Register a callback that would be called when there is a property set error event from
     // vehicle.
     virtual void registerOnPropertySetErrorEvent(
-            std::function<void(const std::vector<SetValueErrorEvent>&)>&& callback) = 0;
+            std::unique_ptr<const PropertySetErrorCallback> callback) = 0;
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 013d177..a7fcdcf 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -37,6 +37,7 @@
 #include <aidl/android/hardware/automotive/vehicle/SetValueResult.h>
 #include <aidl/android/hardware/automotive/vehicle/SetValueResults.h>
 #include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
+#include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReport.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleArea.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 63eb747..0f0ccf1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -67,24 +67,30 @@
 }
 
 inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
-        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
+        int32_t propId, int32_t areaId,
         const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
     if (config.areaConfigs.size() == 0) {
         return nullptr;
     }
 
-    if (isGlobalProp(propValue.prop)) {
+    if (isGlobalProp(propId)) {
         return &(config.areaConfigs[0]);
     }
 
     for (const auto& c : config.areaConfigs) {
-        if (c.areaId == propValue.areaId) {
+        if (c.areaId == areaId) {
             return &c;
         }
     }
     return nullptr;
 }
 
+inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
+    return getAreaConfig(propValue.prop, propValue.areaId, config);
+}
+
 inline std::unique_ptr<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
 createVehiclePropValueVec(::aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,
                           size_t vecSize) {
@@ -213,7 +219,7 @@
 ::ndk::ScopedAStatus toScopedAStatus(
         const ::android::base::Result<T>& result,
         ::aidl::android::hardware::automotive::vehicle::StatusCode status,
-        std::string additionalErrorMsg) {
+        const std::string& additionalErrorMsg) {
     if (result.ok()) {
         return ::ndk::ScopedAStatus::ok();
     }
@@ -236,10 +242,50 @@
 
 template <class T>
 ::ndk::ScopedAStatus toScopedAStatus(const ::android::base::Result<T>& result,
-                                     std::string additionalErrorMsg) {
+                                     const std::string& additionalErrorMsg) {
     return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
 }
 
+// Check whether the value is valid according to config.
+// We check for the following:
+// *  If the type is INT32, {@code value.int32Values} must contain one element.
+// *  If the type is INT32_VEC, {@code value.int32Values} must contain at least one element.
+// *  If the type is INT64, {@code value.int64Values} must contain one element.
+// *  If the type is INT64_VEC, {@code value.int64Values} must contain at least one element.
+// *  If the type is FLOAT, {@code value.floatValues} must contain one element.
+// *  If the type is FLOAT_VEC, {@code value.floatValues} must contain at least one element.
+// *  If the type is MIXED, see checkVendorMixedPropValue.
+::android::base::Result<void> checkPropValue(
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
+
+// Check whether the Mixed type value is valid according to config.
+// We check for the following:
+// *  configArray[1] + configArray[2] + configArray[3] must be equal to the number of
+//    {@code value.int32Values} elements.
+// *  configArray[4] + configArray[5] must be equal to the number of {@code value.int64Values}
+//    elements.
+// *  configArray[6] + configArray[7] must be equal to the number of {@code value.floatValues}
+//    elements.
+// *  configArray[8] must be equal to the number of {@code value.byteValues} elements.
+::android::base::Result<void> checkVendorMixedPropValue(
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
+
+// Check whether the value is within the configured range.
+// We check for the following types:
+// *  If type is INT32 or INT32_VEC, all {@code value.int32Values} elements must be within
+//    {@code minInt32Value} and {@code maxInt32Value} if either of them is not 0.
+// *  If type is INT64 or INT64_VEC, all {@code value.int64Values} elements must be within
+//    {@code minInt64Value} and {@code maxInt64Value} if either of them is not 0.
+// *  If type is FLOAT or FLOAT_VEC, all {@code value.floatValues} elements must be within
+//    {@code minFloatValues} and {@code maxFloatValues} if either of them is not 0.
+// We don't check other types. If more checks are required, they should be added in VehicleHardware
+// implementation.
+::android::base::Result<void> checkValueRange(
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+        const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* config);
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 1a79230..c1fa896 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -21,9 +21,11 @@
 
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
-#include <android-base/format.h>
+#include <android-base/stringprintf.h>
 #include <math/HashCombine.h>
 
+#include <inttypes.h>
+
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -36,13 +38,14 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::base::Error;
 using ::android::base::Result;
+using ::android::base::StringPrintf;
 
 bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
     return area == other.area && token == other.token;
 }
 
 std::string VehiclePropertyStore::RecordId::toString() const {
-    return ::fmt::format("RecordID{{.areaId={:d}, .token={:d}}}", area, token);
+    return StringPrintf("RecordID{{.areaId=% " PRId32 ", .token=%" PRId64 "}", area, token);
 }
 
 size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId) const {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
new file mode 100644
index 0000000..5abde8d
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
+using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+
+Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
+    int32_t property = value.prop;
+    VehiclePropertyType type = getPropType(property);
+    switch (type) {
+        case VehiclePropertyType::BOOLEAN:
+            [[fallthrough]];
+        case VehiclePropertyType::INT32:
+            if (value.value.int32Values.size() != 1) {
+                return Error() << "expect 1 int32Values for INT32 type";
+            }
+            break;
+        case VehiclePropertyType::INT32_VEC:
+            if (value.value.int32Values.size() < 1) {
+                return Error() << "expect >=1 int32Values for INT32_VEC type";
+            }
+            break;
+        case VehiclePropertyType::INT64:
+            if (value.value.int64Values.size() != 1) {
+                return Error() << "expect 1 int64Values for INT64 type";
+            }
+            break;
+        case VehiclePropertyType::INT64_VEC:
+            if (value.value.int64Values.size() < 1) {
+                return Error() << "expect >=1 int64Values for INT64_VEC type";
+            }
+            break;
+        case VehiclePropertyType::FLOAT:
+            if (value.value.floatValues.size() != 1) {
+                return Error() << "expect 1 floatValues for FLOAT type";
+            }
+            break;
+        case VehiclePropertyType::FLOAT_VEC:
+            if (value.value.floatValues.size() < 1) {
+                return Error() << "expect >=1 floatValues for FLOAT_VEC type";
+            }
+            break;
+        case VehiclePropertyType::BYTES:
+            // We allow setting an empty bytes array.
+            break;
+        case VehiclePropertyType::STRING:
+            // We allow setting an empty string.
+            break;
+        case VehiclePropertyType::MIXED:
+            if (getPropGroup(property) == VehiclePropertyGroup::VENDOR) {
+                // We only checks vendor mixed properties.
+                return checkVendorMixedPropValue(value, config);
+            }
+            break;
+        default:
+            return Error() << "unknown property type: " << toInt(type);
+    }
+    return {};
+}
+
+Result<void> checkVendorMixedPropValue(const VehiclePropValue& value,
+                                       const VehiclePropConfig* config) {
+    auto configArray = config->configArray;
+    // configArray[0], 1 indicates the property has a String value, we allow the string value to
+    // be empty.
+
+    size_t int32Count = 0;
+    // configArray[1], 1 indicates the property has a Boolean value.
+    if (configArray[1] == 1) {
+        int32Count++;
+    }
+    // configArray[2], 1 indicates the property has an Integer value.
+    if (configArray[2] == 1) {
+        int32Count++;
+    }
+    // configArray[3], the number indicates the size of Integer[] in the property.
+    int32Count += static_cast<size_t>(configArray[3]);
+    size_t int32Size = value.value.int32Values.size();
+    if (int32Size != int32Count) {
+        return Error() << "invalid mixed property, got " << int32Size << " int32Values, expect "
+                       << int32Count;
+    }
+
+    size_t int64Count = 0;
+    // configArray[4], 1 indicates the property has a Long value.
+    if (configArray[4] == 1) {
+        int64Count++;
+    }
+    // configArray[5], the number indicates the size of Long[] in the property.
+    int64Count += static_cast<size_t>(configArray[5]);
+    size_t int64Size = value.value.int64Values.size();
+    if (int64Size != int64Count) {
+        return Error() << "invalid mixed property, got " << int64Size << " int64Values, expect "
+                       << int64Count;
+    }
+
+    size_t floatCount = 0;
+    // configArray[6], 1 indicates the property has a Float value.
+    if (configArray[6] == 1) {
+        floatCount++;
+    }
+    // configArray[7], the number indicates the size of Float[] in the property.
+    floatCount += static_cast<size_t>(configArray[7]);
+    size_t floatSize = value.value.floatValues.size();
+    if (floatSize != floatCount) {
+        return Error() << "invalid mixed property, got " << floatSize << " floatValues, expect "
+                       << floatCount;
+    }
+
+    // configArray[8], the number indicates the size of byte[] in the property.
+    size_t byteSize = value.value.byteValues.size();
+    size_t byteCount = static_cast<size_t>(configArray[8]);
+    if (byteCount != 0 && byteSize != byteCount) {
+        return Error() << "invalid mixed property, got " << byteSize << " byteValues, expect "
+                       << byteCount;
+    }
+    return {};
+}
+
+Result<void> checkValueRange(const VehiclePropValue& value, const VehicleAreaConfig* areaConfig) {
+    if (areaConfig == nullptr) {
+        return {};
+    }
+    int32_t property = value.prop;
+    VehiclePropertyType type = getPropType(property);
+    switch (type) {
+        case VehiclePropertyType::INT32:
+            [[fallthrough]];
+        case VehiclePropertyType::INT32_VEC:
+            if (areaConfig->minInt32Value == 0 && areaConfig->maxInt32Value == 0) {
+                break;
+            }
+            for (int32_t int32Value : value.value.int32Values) {
+                if (int32Value < areaConfig->minInt32Value ||
+                    int32Value > areaConfig->maxInt32Value) {
+                    return Error() << "int32Value: " << int32Value
+                                   << " out of range, min: " << areaConfig->minInt32Value
+                                   << " max: " << areaConfig->maxInt32Value;
+                }
+            }
+            break;
+        case VehiclePropertyType::INT64:
+            [[fallthrough]];
+        case VehiclePropertyType::INT64_VEC:
+            if (areaConfig->minInt64Value == 0 && areaConfig->maxInt64Value == 0) {
+                break;
+            }
+            for (int64_t int64Value : value.value.int64Values) {
+                if (int64Value < areaConfig->minInt64Value ||
+                    int64Value > areaConfig->maxInt64Value) {
+                    return Error() << "int64Value: " << int64Value
+                                   << " out of range, min: " << areaConfig->minInt64Value
+                                   << " max: " << areaConfig->maxInt64Value;
+                }
+            }
+            break;
+        case VehiclePropertyType::FLOAT:
+            [[fallthrough]];
+        case VehiclePropertyType::FLOAT_VEC:
+            if (areaConfig->minFloatValue == 0.f && areaConfig->maxFloatValue == 0.f) {
+                break;
+            }
+            for (float floatValue : value.value.floatValues) {
+                if (floatValue < areaConfig->minFloatValue ||
+                    floatValue > areaConfig->maxFloatValue) {
+                    return Error() << "floatValue: " << floatValue
+                                   << " out of range, min: " << areaConfig->minFloatValue
+                                   << " max: " << areaConfig->maxFloatValue;
+                }
+            }
+            break;
+        default:
+            // We don't check the rest of property types. Additional logic needs to be added if
+            // required in VehicleHardware, e.g. you might want to check the range for mixed
+            // property.
+            break;
+    }
+    return {};
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
index dd43712..250b331 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
@@ -27,6 +27,7 @@
         "libgtest",
         "libgmock",
     ],
+    header_libs: ["VehicleHalTestUtilHeaders"],
     defaults: ["VehicleHalDefaults"],
     test_suites: ["device-tests"],
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 131eb3b..de8b26d 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -16,6 +16,7 @@
 
 #include <ConcurrentQueue.h>
 #include <PropertyUtils.h>
+#include <TestPropertyUtils.h>
 #include <VehicleUtils.h>
 
 #include <gtest/gtest.h>
@@ -29,6 +30,8 @@
 namespace automotive {
 namespace vehicle {
 
+namespace {
+
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -37,6 +40,427 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
+struct InvalidPropValueTestCase {
+    std::string name;
+    VehiclePropValue value;
+    bool valid = false;
+    VehiclePropConfig config;
+};
+
+constexpr int32_t int32Prop = toInt(VehicleProperty::INFO_MODEL_YEAR);
+constexpr int32_t int32VecProp = toInt(VehicleProperty::INFO_FUEL_TYPE);
+constexpr int32_t int64Prop = toInt(VehicleProperty::ANDROID_EPOCH_TIME);
+constexpr int32_t int64VecProp = toInt(VehicleProperty::WHEEL_TICK);
+constexpr int32_t floatProp = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE);
+constexpr int32_t floatVecProp = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION);
+
+std::vector<InvalidPropValueTestCase> getInvalidPropValuesTestCases() {
+    return std::vector<InvalidPropValueTestCase>(
+            {
+                    InvalidPropValueTestCase{
+                            .name = "int32_normal",
+                            .value =
+                                    {
+                                            .prop = int32Prop,
+                                            .value.int32Values = {0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_no_value",
+                            .value =
+                                    {
+                                            .prop = int32Prop,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_more_than_one_value",
+                            .value =
+                                    {
+                                            .prop = int32Prop,
+                                            .value.int32Values = {0, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_vec_normal",
+                            .value =
+                                    {
+                                            .prop = int32VecProp,
+                                            .value.int32Values = {0, 1},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_vec_no_value",
+                            .value =
+                                    {
+                                            .prop = int32VecProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_normal",
+                            .value =
+                                    {
+                                            .prop = int64Prop,
+                                            .value.int64Values = {0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_no_value",
+                            .value =
+                                    {
+                                            .prop = int64Prop,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_more_than_one_value",
+                            .value =
+                                    {
+                                            .prop = int64Prop,
+                                            .value.int64Values = {0, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_vec_normal",
+                            .value =
+                                    {
+                                            .prop = int64VecProp,
+                                            .value.int64Values = {0, 1},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_vec_no_value",
+                            .value =
+                                    {
+                                            .prop = int64VecProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_normal",
+                            .value =
+                                    {
+                                            .prop = floatProp,
+                                            .value.floatValues = {0.0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_no_value",
+                            .value =
+                                    {
+                                            .prop = floatProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_more_than_one_value",
+                            .value =
+                                    {
+                                            .prop = floatProp,
+                                            .value.floatValues = {0.0, 1.0},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_vec_normal",
+                            .value =
+                                    {
+                                            .prop = floatVecProp,
+                                            .value.floatValues = {0.0, 1.0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_vec_no_value",
+                            .value =
+                                    {
+                                            .prop = floatVecProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_normal",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_int32_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_int64_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_float_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_byte_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0),
+                                                                 static_cast<uint8_t>(1)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+            });
+}
+
+struct InvalidValueRangeTestCase {
+    std::string name;
+    VehiclePropValue value;
+    bool valid = false;
+    VehicleAreaConfig config;
+};
+
+std::vector<InvalidValueRangeTestCase> getInvalidValueRangeTestCases() {
+    return std::vector<InvalidValueRangeTestCase>({{
+            InvalidValueRangeTestCase{
+                    .name = "int32_normal",
+                    .value =
+                            {
+                                    .prop = int32Prop,
+                                    .value.int32Values = {0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int32_vec_normal",
+                    .value =
+                            {
+                                    .prop = int32VecProp,
+                                    .value.int32Values = {0, 1},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int32_vec_underflow",
+                    .value =
+                            {
+                                    .prop = int32VecProp,
+                                    .value.int32Values = {-1, 1},
+                            },
+
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int32_vec_overflow",
+                    .value =
+                            {
+                                    .prop = int32VecProp,
+                                    .value.int32Values = {0, 100},
+                            },
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_normal",
+                    .value =
+                            {
+                                    .prop = int64Prop,
+                                    .value.int64Values = {0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_vec_normal",
+                    .value =
+                            {
+                                    .prop = int64VecProp,
+                                    .value.int64Values = {0, 1},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_vec_underflow",
+                    .value =
+                            {
+                                    .prop = int64VecProp,
+                                    .value.int64Values = {-1, 1},
+                            },
+
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_vec_overflow",
+                    .value =
+                            {
+                                    .prop = int64VecProp,
+                                    .value.int64Values = {0, 100},
+                            },
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_normal",
+                    .value =
+                            {
+                                    .prop = floatProp,
+                                    .value.floatValues = {0.0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_vec_normal",
+                    .value =
+                            {
+                                    .prop = floatVecProp,
+                                    .value.floatValues = {0.0, 10.0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_vec_underflow",
+                    .value =
+                            {
+                                    .prop = floatVecProp,
+                                    .value.floatValues = {-0.1, 1.1},
+                            },
+
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_vec_overflow",
+                    .value =
+                            {
+                                    .prop = floatVecProp,
+                                    .value.floatValues = {0.0, 10.1},
+                            },
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+    }});
+}
+
+}  // namespace
+
 TEST(VehicleUtilsTest, testToInt) {
     int areaGlobal = toInt(VehicleArea::GLOBAL);
 
@@ -335,6 +759,40 @@
     t.join();
 }
 
+class InvalidPropValueTest : public testing::TestWithParam<InvalidPropValueTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(InvalidPropValueTests, InvalidPropValueTest,
+                         testing::ValuesIn(getInvalidPropValuesTestCases()),
+                         [](const testing::TestParamInfo<InvalidPropValueTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(InvalidPropValueTest, testCheckPropValue) {
+    InvalidPropValueTestCase tc = GetParam();
+
+    // Config is not used for non-mixed types.
+    auto result = checkPropValue(tc.value, &tc.config);
+
+    ASSERT_EQ(tc.valid, result.ok());
+}
+
+class InvalidValueRangeTest : public testing::TestWithParam<InvalidValueRangeTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(InvalidValueRangeTests, InvalidValueRangeTest,
+                         testing::ValuesIn(getInvalidValueRangeTestCases()),
+                         [](const testing::TestParamInfo<InvalidValueRangeTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(InvalidValueRangeTest, testCheckValueRange) {
+    InvalidValueRangeTestCase tc = GetParam();
+
+    // Config is not used for non-mixed types.
+    auto result = checkValueRange(tc.value, &tc.config);
+
+    ASSERT_EQ(tc.valid, result.ok());
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 79d3ebd..0132e6f 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -19,7 +19,7 @@
 }
 
 cc_binary {
-    name: "android.hardware.automotive.vehicle-aidl-default-service",
+    name: "android.hardware.automotive.vehicle@V1-default-service",
     vendor: true,
     defaults: [
         "FakeVehicleHardwareDefaults",
@@ -56,6 +56,9 @@
     srcs: [
         "src/ConnectedClient.cpp",
         "src/DefaultVehicleHal.cpp",
+        "src/PendingRequestPool.cpp",
+        "src/RecurrentTimer.cpp",
+        "src/SubscriptionManager.cpp",
     ],
     static_libs: [
         "VehicleHalUtils",
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 43a9603..15a6278 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -17,6 +17,9 @@
 #ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_
 #define android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_
 
+#include "PendingRequestPool.h"
+
+#include <IVehicleHardware.h>
 #include <VehicleHalTypes.h>
 
 #include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
@@ -39,15 +42,33 @@
 // This class is thread-safe.
 class ConnectedClient {
   public:
-    ConnectedClient(
-            std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
-                    callback);
+    using CallbackType =
+            std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+
+    ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
 
     virtual ~ConnectedClient() = default;
 
+    // Gets the unique ID for this client.
+    const void* id();
+
+    // Adds client requests. The requests would be registered as pending requests until
+    // {@code tryFinishRequests} is called for them.
+    // Returns {@code INVALID_ARG} error if any of the requestIds are duplicate with one of the
+    // pending request IDs or {@code TRY_AGAIN} error if the pending request pool is full and could
+    // no longer add requests.
+    ::android::base::Result<void> addRequests(const std::unordered_set<int64_t>& requestIds);
+
+    // Marks the requests as finished. Returns a list of request IDs that was pending and has been
+    // finished. It must be a set of the requested request IDs.
+    std::unordered_set<int64_t> tryFinishRequests(const std::unordered_set<int64_t>& requestIds);
+
   protected:
-    const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
-            mCallback;
+    // Gets the callback to be called when the request for this client has timeout.
+    virtual std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() = 0;
+
+    const std::shared_ptr<PendingRequestPool> mRequestPool;
+    const CallbackType mCallback;
 };
 
 // A class to represent a client that calls {@code IVehicle.setValues} or {@code
@@ -55,12 +76,10 @@
 template <class ResultType, class ResultsType>
 class GetSetValuesClient final : public ConnectedClient {
   public:
-    GetSetValuesClient(
-            std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
-                    callback);
+    GetSetValuesClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
 
     // Sends the results to this client.
-    void sendResults(const std::vector<ResultType>& results);
+    void sendResults(std::vector<ResultType>&& results);
 
     // Sends each result separately to this client. Each result would be sent through one callback
     // invocation.
@@ -69,11 +88,47 @@
     // Gets the callback to be called when the request for this client has finished.
     std::shared_ptr<const std::function<void(std::vector<ResultType>)>> getResultCallback();
 
+  protected:
+    // Gets the callback to be called when the request for this client has timeout.
+    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override;
+
   private:
     // The following members are only initialized during construction.
+    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback;
     std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback;
 };
 
+// A class to represent a client that calls {@code IVehicle.subscribe}.
+class SubscriptionClient final : public ConnectedClient {
+  public:
+    SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
+
+    // Gets the callback to be called when the request for this client has finished.
+    std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
+
+    // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
+    // callback.
+    static void sendUpdatedValues(
+            CallbackType callback,
+            std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
+                    updatedValues);
+
+  protected:
+    // Gets the callback to be called when the request for this client has timeout.
+    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override;
+
+  private:
+    // The following members are only initialized during construction.
+    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback;
+    std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback;
+    std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback;
+
+    static void onGetValueResults(
+            const void* clientId, CallbackType callback,
+            std::shared_ptr<PendingRequestPool> requestPool,
+            std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult> results);
+};
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 43bdca2..5e7adfc 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -17,13 +17,20 @@
 #ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
 #define android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
 
+#include "ConnectedClient.h"
+#include "ParcelableUtils.h"
+#include "PendingRequestPool.h"
+#include "SubscriptionManager.h"
+
 #include <IVehicleHardware.h>
-#include <LargeParcelableBase.h>
 #include <VehicleUtils.h>
 #include <aidl/android/hardware/automotive/vehicle/BnVehicle.h>
+#include <android-base/expected.h>
+#include <android-base/thread_annotations.h>
 #include <android/binder_auto_utils.h>
 
 #include <memory>
+#include <mutex>
 #include <unordered_map>
 #include <vector>
 
@@ -32,64 +39,24 @@
 namespace automotive {
 namespace vehicle {
 
-// private namespace
-namespace defaultvehiclehal_impl {
-
-constexpr int INVALID_MEMORY_FD = -1;
-
-template <class T>
-::ndk::ScopedAStatus toScopedAStatus(
-        const ::android::base::Result<T>& result,
-        ::aidl::android::hardware::automotive::vehicle::StatusCode status) {
-    if (result.ok()) {
-        return ::ndk::ScopedAStatus::ok();
-    }
-    return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(toInt(status),
-                                                                     getErrorMsg(result).c_str());
-}
-
-template <class T>
-::ndk::ScopedAStatus toScopedAStatus(const ::android::base::Result<T>& result) {
-    return toScopedAStatus(result, getErrorCode(result));
-}
-
-template <class T1, class T2>
-::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector<T1>& values, T2* output) {
-    auto result = ::android::automotive::car_binder_lib::LargeParcelableBase::
-            parcelableVectorToStableLargeParcelable(values);
-    if (!result.ok()) {
-        return toScopedAStatus(
-                result, ::aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR);
-    }
-    auto& fd = result.value();
-    if (fd == nullptr) {
-        output->payloads = values;
-    } else {
-        // Move the returned ScopedFileDescriptor pointer to ScopedFileDescriptor value in
-        // 'sharedMemoryFd' field.
-        output->sharedMemoryFd.set(fd->get());
-        *(fd->getR()) = INVALID_MEMORY_FD;
-    }
-    return ::ndk::ScopedAStatus::ok();
-}
-
-}  // namespace defaultvehiclehal_impl
-
 class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::vehicle::BnVehicle {
   public:
+    using CallbackType =
+            std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+
     explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
 
+    ~DefaultVehicleHal();
+
     ::ndk::ScopedAStatus getAllPropConfigs(
             ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
             override;
     ::ndk::ScopedAStatus getValues(
-            const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
-                    callback,
+            const CallbackType& callback,
             const ::aidl::android::hardware::automotive::vehicle::GetValueRequests& requests)
             override;
     ::ndk::ScopedAStatus setValues(
-            const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
-                    callback,
+            const CallbackType& callback,
             const ::aidl::android::hardware::automotive::vehicle::SetValueRequests& requests)
             override;
     ::ndk::ScopedAStatus getPropConfigs(
@@ -97,27 +64,182 @@
             ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
             override;
     ::ndk::ScopedAStatus subscribe(
-            const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
-                    callback,
+            const CallbackType& callback,
             const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options,
             int32_t maxSharedMemoryFileCount) override;
-    ::ndk::ScopedAStatus unsubscribe(
-            const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
-                    callback,
-            const std::vector<int32_t>& propIds) override;
-    ::ndk::ScopedAStatus returnSharedMemory(
-            const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
-                    callback,
-            int64_t sharedMemoryId) override;
+    ::ndk::ScopedAStatus unsubscribe(const CallbackType& callback,
+                                     const std::vector<int32_t>& propIds) override;
+    ::ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
+                                            int64_t sharedMemoryId) override;
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
     IVehicleHardware* getHardware();
 
   private:
-    const std::unique_ptr<IVehicleHardware> mVehicleHardware;
+    // friend class for unit testing.
+    friend class DefaultVehicleHalTest;
+
+    using GetValuesClient =
+            GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::GetValueResult,
+                               ::aidl::android::hardware::automotive::vehicle::GetValueResults>;
+    using SetValuesClient =
+            GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::SetValueResult,
+                               ::aidl::android::hardware::automotive::vehicle::SetValueResults>;
+
+    // A thread safe class to maintain an increasing request ID for each subscribe client. This
+    // class is safe to pass to async callbacks.
+    class SubscribeIdByClient {
+      public:
+        int64_t getId(const CallbackType& callback);
+
+      private:
+        std::mutex mLock;
+        std::unordered_map<const AIBinder*, int64_t> mIds GUARDED_BY(mLock);
+    };
+
+    // A thread safe class to store all subscribe clients. This class is safe to pass to async
+    // callbacks.
+    class SubscriptionClients {
+      public:
+        SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {}
+
+        std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback);
+
+        void removeClient(const AIBinder* clientId);
+
+        size_t countClients();
+
+      private:
+        std::mutex mLock;
+        std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>> mClients
+                GUARDED_BY(mLock);
+        // PendingRequestPool is thread-safe.
+        std::shared_ptr<PendingRequestPool> mPendingRequestPool;
+    };
+
+    // A wrapper for linkToDeath to enable stubbing for test.
+    class ILinkToDeath {
+      public:
+        virtual ~ILinkToDeath() = default;
+
+        virtual binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                            void* cookie) = 0;
+    };
+
+    // A real implementation for ILinkToDeath.
+    class AIBinderLinkToDeathImpl final : public ILinkToDeath {
+      public:
+        binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                    void* cookie) override;
+    };
+
+    // OnBinderDiedContext is a type used as a cookie passed deathRecipient. The deathRecipient's
+    // onBinderDied function takes only a cookie as input and we have to store all the contexts
+    // as the cookie.
+    struct OnBinderDiedContext {
+        DefaultVehicleHal* vhal;
+        const AIBinder* clientId;
+    };
+
+    // The default timeout of get or set value requests is 30s.
+    // TODO(b/214605968): define TIMEOUT_IN_NANO in IVehicle and allow getValues/setValues/subscribe
+    // to specify custom timeouts.
+    static constexpr int64_t TIMEOUT_IN_NANO = 30'000'000'000;
+    // heart beat event interval: 3s
+    static constexpr int64_t HEART_BEAT_INTERVAL_IN_NANO = 3'000'000'000;
+    const std::shared_ptr<IVehicleHardware> mVehicleHardware;
+
+    // mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
+    // lock guard them.
     std::unordered_map<int32_t, ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
             mConfigsByPropId;
+    // Only modified in constructor, so thread-safe.
     std::unique_ptr<::ndk::ScopedFileDescriptor> mConfigFile;
+    // PendingRequestPool is thread-safe.
+    std::shared_ptr<PendingRequestPool> mPendingRequestPool;
+    // SubscriptionManager is thread-safe.
+    std::shared_ptr<SubscriptionManager> mSubscriptionManager;
+
+    std::mutex mLock;
+    std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
+            GUARDED_BY(mLock);
+    std::unordered_map<const AIBinder*, std::shared_ptr<GetValuesClient>> mGetValuesClients
+            GUARDED_BY(mLock);
+    std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>> mSetValuesClients
+            GUARDED_BY(mLock);
+    // SubscriptionClients is thread-safe.
+    std::shared_ptr<SubscriptionClients> mSubscriptionClients;
+    // mLinkToDeathImpl is only going to be changed in test.
+    std::unique_ptr<ILinkToDeath> mLinkToDeathImpl;
+
+    // RecurrentTimer is thread-safe.
+    RecurrentTimer mRecurrentTimer;
+
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+    ::android::base::Result<void> checkProperty(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+
+    ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+                    requests);
+
+    ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+                    requests);
+
+    ::android::base::Result<void> checkSubscribeOptions(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
+                    options);
+
+    ::android::base::Result<void> checkReadPermission(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+    ::android::base::Result<void> checkWritePermission(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+    ::android::base::Result<
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
+    getConfig(int32_t propId) const;
+
+    void onBinderDiedWithContext(const AIBinder* clientId);
+
+    void onBinderUnlinkedWithContext(const AIBinder* clientId);
+
+    void monitorBinderLifeCycle(const CallbackType& callback);
+
+    bool checkDumpPermission();
+
+    template <class T>
+    static std::shared_ptr<T> getOrCreateClient(
+            std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
+            const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+
+    static void getValueFromHardwareCallCallback(
+            std::weak_ptr<IVehicleHardware> vehicleHardware,
+            std::shared_ptr<SubscribeIdByClient> subscribeIdByClient,
+            std::shared_ptr<SubscriptionClients> subscriptionClients, const CallbackType& callback,
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+
+    static void onPropertyChangeEvent(
+            std::weak_ptr<SubscriptionManager> subscriptionManager,
+            const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
+                    updatedValues);
+
+    static void checkHealth(std::weak_ptr<IVehicleHardware> hardware,
+                            std::weak_ptr<SubscriptionManager> subscriptionManager);
+
+    static void onBinderDied(void* cookie);
+
+    static void onBinderUnlinked(void* cookie);
+
+    // Test-only
+    // Set the default timeout for pending requests.
+    void setTimeout(int64_t timeoutInNano);
+
+    // Test-only
+    void setLinkToDeathImpl(std::unique_ptr<ILinkToDeath> impl);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h
index dcb15b9..7b2111b 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h
@@ -29,22 +29,27 @@
 namespace automotive {
 namespace vehicle {
 
+// Turns the values into a stable large parcelable that could be sent via binder.
+// If values is small enough, it would be put into output.payloads, otherwise a shared memory file
+// would be created and output.sharedMemoryFd would be filled in.
 template <class T1, class T2>
 ::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector<T1>&& values, T2* output) {
+    output->payloads = std::move(values);
     auto result = ::android::automotive::car_binder_lib::LargeParcelableBase::
-            parcelableVectorToStableLargeParcelable(values);
+            parcelableToStableLargeParcelable(*output);
     if (!result.ok()) {
         return toScopedAStatus(
                 result, ::aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR);
     }
     auto& fd = result.value();
-    if (fd == nullptr) {
-        // If we no longer needs values, move it inside the payloads to avoid copying.
-        output->payloads = std::move(values);
-    } else {
+    if (fd != nullptr) {
         // Move the returned ScopedFileDescriptor pointer to ScopedFileDescriptor value in
         // 'sharedMemoryFd' field.
+        output->payloads.clear();
         output->sharedMemoryFd = std::move(*fd);
+    } else {
+        output->sharedMemoryFd = ::ndk::ScopedFileDescriptor();
+        // Do not modify payloads.
     }
     return ::ndk::ScopedAStatus::ok();
 }
@@ -57,12 +62,13 @@
     return vectorToStableLargeParcelable(std::move(valuesCopy), output);
 }
 
-template <class T1, class T2>
-::android::base::expected<std::vector<T1>, ::ndk::ScopedAStatus> stableLargeParcelableToVector(
-        const T2& largeParcelable) {
-    ::android::base::Result<std::optional<std::vector<T1>>> result =
-            ::android::automotive::car_binder_lib::LargeParcelableBase::
-                    stableLargeParcelableToParcelableVector<T1>(largeParcelable.sharedMemoryFd);
+template <class T>
+::android::base::expected<
+        ::android::automotive::car_binder_lib::LargeParcelableBase::BorrowedOwnedObject<T>,
+        ::ndk::ScopedAStatus>
+fromStableLargeParcelable(const T& largeParcelable) {
+    auto result = ::android::automotive::car_binder_lib::LargeParcelableBase::
+            stableLargeParcelableToParcelable(largeParcelable);
 
     if (!result.ok()) {
         return ::android::base::unexpected(toScopedAStatus(
@@ -70,15 +76,7 @@
                 "failed to parse large parcelable"));
     }
 
-    if (!result.value().has_value()) {
-        return ::android::base::unexpected(
-                ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-                        toInt(::aidl::android::hardware::automotive::vehicle::StatusCode::
-                                      INVALID_ARG),
-                        "empty request"));
-    }
-
-    return std::move(result.value().value());
+    return std::move(result.value());
 }
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h b/automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h
new file mode 100644
index 0000000..efb3315
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_PendingRequestPool_H_
+#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_PendingRequestPool_H_
+
+#include <android-base/result.h>
+#include <android-base/thread_annotations.h>
+
+#include <atomic>
+#include <list>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+// A thread-safe pending request pool that tracks whether each request has timed-out.
+class PendingRequestPool final {
+  public:
+    using TimeoutCallbackFunc = std::function<void(const std::unordered_set<int64_t>&)>;
+
+    explicit PendingRequestPool(int64_t timeoutInSec);
+
+    ~PendingRequestPool();
+
+    // Adds a list of requests to the request pool.
+    // The clientId is the key for all the requests. It could be a number or an address to a data
+    // structure that represents a client. The caller must maintain this data structure.
+    // All the request IDs must be unique for one client, if any of the requestIds is duplicate with
+    // any pending request IDs for the client, this function returns error and no requests would be
+    // added. Otherwise, they would be added to the request pool.
+    // The callback would be called if requests are not finished within {@code mTimeoutInNano}
+    // seconds.
+    android::base::Result<void> addRequests(const void* clientId,
+                                            const std::unordered_set<int64_t>& requestIds,
+                                            std::shared_ptr<const TimeoutCallbackFunc> callback);
+
+    // Checks whether the request is currently pending.
+    bool isRequestPending(const void* clientId, int64_t requestId) const;
+
+    // Tries to mark the requests as finished and remove them from the pool if the request is
+    // currently pending. Returns the list of request that is pending and has been finished
+    // successfully. This function would try to finish any valid requestIds even though some of the
+    // requestIds are not valid.
+    std::unordered_set<int64_t> tryFinishRequests(const void* clientId,
+                                                  const std::unordered_set<int64_t>& requestIds);
+
+    // Returns how many pending requests in the pool, for testing purpose.
+    size_t countPendingRequests(const void* clientId) const;
+
+    size_t countPendingRequests() const;
+
+  private:
+    // The maximum number of pending requests allowed per client. If exceeds this number, adding
+    // more requests would fail. This is to prevent spamming from client.
+    static constexpr size_t MAX_PENDING_REQUEST_PER_CLIENT = 10000;
+
+    struct PendingRequest {
+        std::unordered_set<int64_t> requestIds;
+        int64_t timeoutTimestamp;
+        std::shared_ptr<const TimeoutCallbackFunc> callback;
+    };
+
+    int64_t mTimeoutInNano;
+    mutable std::mutex mLock;
+    std::unordered_map<const void*, std::list<PendingRequest>> mPendingRequestsByClient
+            GUARDED_BY(mLock);
+    std::thread mThread;
+    std::atomic<bool> mThreadStop = false;
+    std::condition_variable mCv;
+    std::mutex mCvLock;
+
+    bool isRequestPendingLocked(const void* clientId, int64_t requestId) const REQUIRES(mLock);
+
+    // Checks whether the requests in the pool has timed-out, run periodically in a separate thread.
+    void checkTimeout();
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_aidl_impl_vhal_include_PendingRequestPool_H_
diff --git a/automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h b/automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h
new file mode 100644
index 0000000..5f0f716
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_
+#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_
+
+#include <android-base/thread_annotations.h>
+
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+// A thread-safe recurrent timer.
+class RecurrentTimer final {
+  public:
+    // The class for the function that would be called recurrently.
+    using Callback = std::function<void()>;
+
+    RecurrentTimer();
+
+    ~RecurrentTimer();
+
+    // Registers a recurrent callback for a given interval.
+    // Registering the same callback twice will override the interval provided before.
+    void registerTimerCallback(int64_t intervalInNano, std::shared_ptr<Callback> callback);
+
+    // Unregisters a previously registered recurrent callback.
+    void unregisterTimerCallback(std::shared_ptr<Callback> callback);
+
+  private:
+    // friend class for unit testing.
+    friend class RecurrentTimerTest;
+
+    struct CallbackInfo {
+        std::shared_ptr<Callback> callback;
+        int64_t interval;
+        int64_t nextTime;
+        // A flag to indicate whether this CallbackInfo is already outdated and should be ignored.
+        // The reason we need this flag is because we cannot easily remove an element from a heap.
+        bool outdated = false;
+
+        static bool cmp(const std::unique_ptr<CallbackInfo>& lhs,
+                        const std::unique_ptr<CallbackInfo>& rhs);
+    };
+
+    std::mutex mLock;
+    std::thread mThread;
+    std::condition_variable mCond;
+    bool mStopRequested GUARDED_BY(mLock) = false;
+    // A map to map each callback to its current active CallbackInfo in the mCallbackQueue.
+    std::unordered_map<std::shared_ptr<Callback>, CallbackInfo*> mCallbacks GUARDED_BY(mLock);
+    // A min-heap sorted by nextTime. Note that because we cannot remove arbitrary element from the
+    // heap, a single Callback can have multiple entries in this queue, all but one should be valid.
+    // The rest should be mark as outdated. The valid one is one stored in mCallbacks.
+    std::vector<std::unique_ptr<CallbackInfo>> mCallbackQueue GUARDED_BY(mLock);
+
+    void loop();
+
+    // Mark the callbackInfo as outdated and should be ignored when popped from the heap.
+    void markOutdatedLocked(CallbackInfo* callback) REQUIRES(mLock);
+    // Remove all outdated callbackInfos from the top of the heap. This function must be called
+    // each time we might introduce outdated elements to the top. We must make sure the heap is
+    // always valid from the top.
+    void removeInvalidCallbackLocked() REQUIRES(mLock);
+    // Pops the next closest callback (must be valid) from the heap.
+    std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock);
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
new file mode 100644
index 0000000..e739c8c
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
+#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
+
+#include "RecurrentTimer.h"
+
+#include <VehicleHalTypes.h>
+
+#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
+#include <android-base/result.h>
+#include <android-base/thread_annotations.h>
+
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+// A thread-safe subscription manager that manages all VHAL subscriptions.
+class SubscriptionManager final {
+  public:
+    using ClientIdType = const AIBinder*;
+    using CallbackType =
+            std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+    using GetValueFunc = std::function<void(
+            const CallbackType& callback,
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)>;
+
+    explicit SubscriptionManager(GetValueFunc&& action);
+    ~SubscriptionManager();
+
+    // Subscribes to properties according to {@code SubscribeOptions}. Note that all option must
+    // contain non-empty areaIds field, which contains all area IDs to subscribe. As a result,
+    // the options here is different from the options passed from VHAL client.
+    // Returns error if any of the subscribe options is not valid. If error is returned, no
+    // properties would be subscribed.
+    // Returns ok if all the options are parsed correctly and all the properties are subscribed.
+    ::android::base::Result<void> subscribe(
+            const CallbackType& callback,
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
+                    options,
+            bool isContinuousProperty);
+
+    // Unsubscribes from the properties for the client.
+    // Returns error if the client was not subscribed before or one of the given property was not
+    // subscribed. If error is returned, no property would be unsubscribed.
+    // Returns ok if all the requested properties for the client are unsubscribed.
+    ::android::base::Result<void> unsubscribe(ClientIdType client,
+                                              const std::vector<int32_t>& propIds);
+
+    // Unsubscribes from all the properties for the client.
+    // Returns error if the client was not subscribed before. If error is returned, no property
+    // would be unsubscribed.
+    // Returns ok if all the properties for the client are unsubscribed.
+    ::android::base::Result<void> unsubscribe(ClientIdType client);
+
+    // For a list of updated properties, returns a map that maps clients subscribing to
+    // the updated properties to a list of updated values. This would only return on-change property
+    // clients that should be informed for the given updated values.
+    std::unordered_map<
+            CallbackType,
+            std::vector<const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue*>>
+    getSubscribedClients(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
+                    updatedValues);
+
+    // Checks whether the sample rate is valid.
+    static bool checkSampleRate(float sampleRate);
+
+  private:
+    // Friend class for testing.
+    friend class DefaultVehicleHalTest;
+
+    struct PropIdAreaId {
+        int32_t propId;
+        int32_t areaId;
+
+        bool operator==(const PropIdAreaId& other) const;
+    };
+
+    struct PropIdAreaIdHash {
+        size_t operator()(const PropIdAreaId& propIdAreaId) const;
+    };
+
+    // A class to represent a registered subscription.
+    class Subscription {
+      public:
+        Subscription() = default;
+
+        Subscription(const Subscription&) = delete;
+
+        virtual ~Subscription() = default;
+
+        virtual bool isOnChange();
+    };
+
+    // A subscription for OnContinuous property. The registered action would be called recurrently
+    // until this class is destructed.
+    class RecurrentSubscription final : public Subscription {
+      public:
+        explicit RecurrentSubscription(std::shared_ptr<RecurrentTimer> timer,
+                                       std::function<void()>&& action, int64_t interval);
+        ~RecurrentSubscription();
+
+        bool isOnChange() override;
+
+      private:
+        std::shared_ptr<std::function<void()>> mAction;
+        std::shared_ptr<RecurrentTimer> mTimer;
+    };
+
+    // A subscription for OnChange property.
+    class OnChangeSubscription final : public Subscription {
+      public:
+        bool isOnChange() override;
+    };
+
+    mutable std::mutex mLock;
+    std::unordered_map<PropIdAreaId, std::unordered_map<ClientIdType, CallbackType>,
+                       PropIdAreaIdHash>
+            mClientsByPropIdArea GUARDED_BY(mLock);
+    std::unordered_map<ClientIdType, std::unordered_map<PropIdAreaId, std::unique_ptr<Subscription>,
+                                                        PropIdAreaIdHash>>
+            mSubscriptionsByClient GUARDED_BY(mLock);
+    // RecurrentTimer is thread-safe.
+    std::shared_ptr<RecurrentTimer> mTimer;
+    const GetValueFunc mGetValue;
+
+    static ::android::base::Result<int64_t> getInterval(float sampleRate);
+
+    // Checks whether the manager is empty. For testing purpose.
+    bool isEmpty();
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 656dfaf..098bfee 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -84,9 +84,9 @@
 // Send all the GetValue/SetValue results through callback in a single callback invocation.
 template <class ResultType, class ResultsType>
 void sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback,
-                              const std::vector<ResultType>& results) {
+                              std::vector<ResultType>&& results) {
     ResultsType parcelableResults;
-    ScopedAStatus status = vectorToStableLargeParcelable(results, &parcelableResults);
+    ScopedAStatus status = vectorToStableLargeParcelable(std::move(results), &parcelableResults);
     if (status.isOk()) {
         if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
             !callbackStatus.isOk()) {
@@ -99,7 +99,55 @@
     ALOGE("failed to marshal result into large parcelable, error: "
           "%s, code: %d",
           status.getMessage(), statusCode);
-    sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback, results);
+    sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback,
+                                                                parcelableResults.payloads);
+}
+
+// The timeout callback for GetValues/SetValues.
+template <class ResultType, class ResultsType>
+void onTimeout(
+        std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+        const std::unordered_set<int64_t>& timeoutIds) {
+    std::vector<ResultType> timeoutResults;
+    for (int64_t requestId : timeoutIds) {
+        ALOGD("hardware request timeout, request ID: %" PRId64, requestId);
+        timeoutResults.push_back({
+                .requestId = requestId,
+                .status = StatusCode::TRY_AGAIN,
+        });
+    }
+    sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(timeoutResults));
+}
+
+// The on-results callback for GetValues/SetValues.
+template <class ResultType, class ResultsType>
+void getOrSetValuesCallback(
+        const void* clientId,
+        std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+        std::vector<ResultType>&& results, std::shared_ptr<PendingRequestPool> requestPool) {
+    std::unordered_set<int64_t> requestIds;
+    for (const auto& result : results) {
+        requestIds.insert(result.requestId);
+    }
+
+    auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds);
+
+    auto it = results.begin();
+    while (it != results.end()) {
+        int64_t requestId = it->requestId;
+        if (finishedRequests.find(requestId) == finishedRequests.end()) {
+            ALOGD("no pending request for the result from hardware, "
+                  "possibly already time-out, ID: %" PRId64,
+                  requestId);
+            it = results.erase(it);
+        } else {
+            it++;
+        }
+    }
+
+    if (!results.empty()) {
+        sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(results));
+    }
 }
 
 // Specify the functions for GetValues and SetValues types.
@@ -109,27 +157,64 @@
         std::shared_ptr<IVehicleCallback> callback, const SetValueResult& result);
 
 template void sendGetOrSetValueResults<GetValueResult, GetValueResults>(
-        std::shared_ptr<IVehicleCallback> callback, const std::vector<GetValueResult>& results);
+        std::shared_ptr<IVehicleCallback> callback, std::vector<GetValueResult>&& results);
 template void sendGetOrSetValueResults<SetValueResult, SetValueResults>(
-        std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results);
+        std::shared_ptr<IVehicleCallback> callback, std::vector<SetValueResult>&& results);
 
 template void sendGetOrSetValueResultsSeparately<GetValueResult, GetValueResults>(
         std::shared_ptr<IVehicleCallback> callback, const std::vector<GetValueResult>& results);
 template void sendGetOrSetValueResultsSeparately<SetValueResult, SetValueResults>(
         std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results);
 
+template void onTimeout<GetValueResult, GetValueResults>(
+        std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+        const std::unordered_set<int64_t>& timeoutIds);
+template void onTimeout<SetValueResult, SetValueResults>(
+        std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+        const std::unordered_set<int64_t>& timeoutIds);
+
+template void getOrSetValuesCallback<GetValueResult, GetValueResults>(
+        const void* clientId,
+        std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+        std::vector<GetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
+template void getOrSetValuesCallback<SetValueResult, SetValueResults>(
+        const void* clientId,
+        std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+        std::vector<SetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
+
 }  // namespace
 
-ConnectedClient::ConnectedClient(std::shared_ptr<IVehicleCallback> callback)
-    : mCallback(callback) {}
+ConnectedClient::ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool,
+                                 std::shared_ptr<IVehicleCallback> callback)
+    : mRequestPool(requestPool), mCallback(callback) {}
+
+const void* ConnectedClient::id() {
+    return reinterpret_cast<const void*>(this);
+}
+
+Result<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) {
+    return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback());
+}
+
+std::unordered_set<int64_t> ConnectedClient::tryFinishRequests(
+        const std::unordered_set<int64_t>& requestIds) {
+    return mRequestPool->tryFinishRequests(id(), requestIds);
+}
 
 template <class ResultType, class ResultsType>
 GetSetValuesClient<ResultType, ResultsType>::GetSetValuesClient(
-        std::shared_ptr<IVehicleCallback> callback)
-    : ConnectedClient(callback) {
+        std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback)
+    : ConnectedClient(requestPool, callback) {
+    mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>(
+            [callback](const std::unordered_set<int64_t>& timeoutIds) {
+                return onTimeout<ResultType, ResultsType>(callback, timeoutIds);
+            });
+    auto requestPoolCopy = mRequestPool;
+    const void* clientId = id();
     mResultCallback = std::make_shared<const std::function<void(std::vector<ResultType>)>>(
-            [callback](std::vector<ResultType> results) {
-                return sendGetOrSetValueResults<ResultType, ResultsType>(callback, results);
+            [clientId, callback, requestPoolCopy](std::vector<ResultType> results) {
+                return getOrSetValuesCallback<ResultType, ResultsType>(
+                        clientId, callback, std::move(results), requestPoolCopy);
             });
 }
 
@@ -140,9 +225,14 @@
 }
 
 template <class ResultType, class ResultsType>
-void GetSetValuesClient<ResultType, ResultsType>::sendResults(
-        const std::vector<ResultType>& results) {
-    return sendGetOrSetValueResults<ResultType, ResultsType>(mCallback, results);
+std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc>
+GetSetValuesClient<ResultType, ResultsType>::getTimeoutCallback() {
+    return mTimeoutCallback;
+}
+
+template <class ResultType, class ResultsType>
+void GetSetValuesClient<ResultType, ResultsType>::sendResults(std::vector<ResultType>&& results) {
+    return sendGetOrSetValueResults<ResultType, ResultsType>(mCallback, std::move(results));
 }
 
 template <class ResultType, class ResultsType>
@@ -154,6 +244,100 @@
 template class GetSetValuesClient<GetValueResult, GetValueResults>;
 template class GetSetValuesClient<SetValueResult, SetValueResults>;
 
+SubscriptionClient::SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool,
+                                       std::shared_ptr<IVehicleCallback> callback)
+    : ConnectedClient(requestPool, callback) {
+    mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>(
+            [](std::unordered_set<int64_t> timeoutIds) {
+                for (int64_t id : timeoutIds) {
+                    ALOGW("subscribe: requests with IDs: %" PRId64
+                          " has timed-out, not client informed, "
+                          "possibly one of recurrent requests for this subscription failed",
+                          id);
+                }
+            });
+    auto requestPoolCopy = mRequestPool;
+    const void* clientId = reinterpret_cast<const void*>(this);
+    mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>(
+            [clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) {
+                onGetValueResults(clientId, callback, requestPoolCopy, results);
+            });
+}
+
+std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>>
+SubscriptionClient::getResultCallback() {
+    return mResultCallback;
+}
+
+std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc>
+SubscriptionClient::getTimeoutCallback() {
+    return mTimeoutCallback;
+}
+
+void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,
+                                           std::vector<VehiclePropValue>&& updatedValues) {
+    if (updatedValues.empty()) {
+        return;
+    }
+
+    // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
+    VehiclePropValues vehiclePropValues;
+    int32_t sharedMemoryFileCount = 0;
+    ScopedAStatus status =
+            vectorToStableLargeParcelable(std::move(updatedValues), &vehiclePropValues);
+    if (!status.isOk()) {
+        int statusCode = status.getServiceSpecificError();
+        ALOGE("subscribe: failed to marshal result into large parcelable, error: "
+              "%s, code: %d",
+              status.getMessage(), statusCode);
+        return;
+    }
+
+    if (ScopedAStatus callbackStatus =
+                callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
+        !callbackStatus.isOk()) {
+        ALOGE("subscribe: failed to call callback, error: %s, code: %d", status.getMessage(),
+              status.getServiceSpecificError());
+    }
+}
+
+void SubscriptionClient::onGetValueResults(const void* clientId,
+                                           std::shared_ptr<IVehicleCallback> callback,
+                                           std::shared_ptr<PendingRequestPool> requestPool,
+                                           std::vector<GetValueResult> results) {
+    std::unordered_set<int64_t> requestIds;
+    for (const auto& result : results) {
+        requestIds.insert(result.requestId);
+    }
+
+    auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds);
+    std::vector<VehiclePropValue> propValues;
+    for (auto& result : results) {
+        int64_t requestId = result.requestId;
+        if (finishedRequests.find(requestId) == finishedRequests.end()) {
+            ALOGE("subscribe[%" PRId64
+                  "]: no pending request for the result from hardware, "
+                  "possibly already time-out",
+                  requestId);
+            continue;
+        }
+        if (result.status != StatusCode::OK) {
+            ALOGE("subscribe[%" PRId64
+                  "]: hardware returns non-ok status for getValues, status: "
+                  "%d",
+                  requestId, toInt(result.status));
+            continue;
+        }
+        if (!result.prop.has_value()) {
+            ALOGE("subscribe[%" PRId64 "]: no prop value in getValues result", requestId);
+            continue;
+        }
+        propValues.push_back(std::move(result.prop.value()));
+    }
+
+    sendUpdatedValues(callback, std::move(propValues));
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index fd9e331..c0a66da 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -21,32 +21,98 @@
 #include <LargeParcelableBase.h>
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
+
 #include <android-base/result.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_ibinder.h>
+#include <private/android_filesystem_config.h>
 #include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <inttypes.h>
+#include <set>
+#include <unordered_set>
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace vehicle {
 
+namespace {
+
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
-using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::automotive::car_binder_lib::LargeParcelableBase;
+using ::android::base::Error;
+using ::android::base::expected;
 using ::android::base::Result;
+using ::android::base::StringPrintf;
+
+using ::ndk::ScopedAIBinder_DeathRecipient;
 using ::ndk::ScopedAStatus;
 
+std::string toString(const std::unordered_set<int64_t>& values) {
+    std::string str = "";
+    for (auto it = values.begin(); it != values.end(); it++) {
+        str += std::to_string(*it);
+        if (std::next(it, 1) != values.end()) {
+            str += ", ";
+        }
+    }
+    return str;
+}
+
+}  // namespace
+
+std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient(
+        const CallbackType& callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return getOrCreateClient(&mClients, callback, mPendingRequestPool);
+}
+
+int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    // This would be initialized to 0 if callback does not exist in the map.
+    int64_t subscribeId = (mIds[callback->asBinder().get()])++;
+    return subscribeId;
+}
+
+void DefaultVehicleHal::SubscriptionClients::removeClient(const AIBinder* clientId) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mClients.erase(clientId);
+}
+
+size_t DefaultVehicleHal::SubscriptionClients::countClients() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mClients.size();
+}
+
 DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware)
-    : mVehicleHardware(std::move(hardware)) {
+    : mVehicleHardware(std::move(hardware)),
+      mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) {
     auto configs = mVehicleHardware->getAllPropertyConfigs();
     for (auto& config : configs) {
         mConfigsByPropId[config.prop] = config;
     }
-    auto result = LargeParcelableBase::parcelableVectorToStableLargeParcelable(configs);
+    VehiclePropConfigs vehiclePropConfigs;
+    vehiclePropConfigs.payloads = std::move(configs);
+    auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
     if (!result.ok()) {
         ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
               getErrorMsg(result).c_str(), getIntErrorCode(result));
@@ -56,10 +122,173 @@
     if (result.value() != nullptr) {
         mConfigFile = std::move(result.value());
     }
+
+    mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);
+
+    auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>();
+    // Make a weak copy of IVehicleHardware because subscriptionManager uses IVehicleHardware and
+    // IVehicleHardware uses subscriptionManager. We want to avoid cyclic reference.
+    std::weak_ptr<IVehicleHardware> hardwareCopy = mVehicleHardware;
+    SubscriptionManager::GetValueFunc getValueFunc = std::bind(
+            &DefaultVehicleHal::getValueFromHardwareCallCallback, hardwareCopy, subscribeIdByClient,
+            mSubscriptionClients, std::placeholders::_1, std::placeholders::_2);
+    mSubscriptionManager = std::make_shared<SubscriptionManager>(std::move(getValueFunc));
+
+    std::weak_ptr<SubscriptionManager> subscriptionManagerCopy = mSubscriptionManager;
+    mVehicleHardware->registerOnPropertyChangeEvent(
+            std::make_unique<IVehicleHardware::PropertyChangeCallback>(
+                    [subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
+                        onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
+                    }));
+
+    // Register heartbeat event.
+    mRecurrentTimer.registerTimerCallback(
+            HEART_BEAT_INTERVAL_IN_NANO,
+            std::make_shared<std::function<void()>>([hardwareCopy, subscriptionManagerCopy]() {
+                checkHealth(hardwareCopy, subscriptionManagerCopy);
+            }));
+
+    mLinkToDeathImpl = std::make_unique<AIBinderLinkToDeathImpl>();
+    mDeathRecipient = ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(&DefaultVehicleHal::onBinderDied));
+    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(),
+                                          &DefaultVehicleHal::onBinderUnlinked);
+}
+
+DefaultVehicleHal::~DefaultVehicleHal() {
+    // Delete the deathRecipient so that onBinderDied would not be called to reference 'this'.
+    mDeathRecipient = ScopedAIBinder_DeathRecipient();
+}
+
+void DefaultVehicleHal::onPropertyChangeEvent(
+        std::weak_ptr<SubscriptionManager> subscriptionManager,
+        const std::vector<VehiclePropValue>& updatedValues) {
+    auto manager = subscriptionManager.lock();
+    if (manager == nullptr) {
+        ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+        return;
+    }
+    auto updatedValuesByClients = manager->getSubscribedClients(updatedValues);
+    for (const auto& [callback, valuePtrs] : updatedValuesByClients) {
+        std::vector<VehiclePropValue> values;
+        for (const VehiclePropValue* valuePtr : valuePtrs) {
+            values.push_back(*valuePtr);
+        }
+        SubscriptionClient::sendUpdatedValues(callback, std::move(values));
+    }
+}
+
+template <class T>
+std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
+        std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
+        const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool) {
+    const AIBinder* clientId = callback->asBinder().get();
+    if (clients->find(clientId) == clients->end()) {
+        (*clients)[clientId] = std::make_shared<T>(pendingRequestPool, callback);
+    }
+    return (*clients)[clientId];
+}
+
+void DefaultVehicleHal::monitorBinderLifeCycle(const CallbackType& callback) {
+    AIBinder* clientId = callback->asBinder().get();
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        if (mOnBinderDiedContexts.find(clientId) != mOnBinderDiedContexts.end()) {
+            // Already registered.
+            return;
+        }
+    }
+
+    std::unique_ptr<OnBinderDiedContext> context = std::make_unique<OnBinderDiedContext>(
+            OnBinderDiedContext{.vhal = this, .clientId = clientId});
+    binder_status_t status = mLinkToDeathImpl->linkToDeath(clientId, mDeathRecipient.get(),
+                                                           static_cast<void*>(context.get()));
+    if (status == STATUS_OK) {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        // Insert into a map to keep the context object alive.
+        mOnBinderDiedContexts[clientId] = std::move(context);
+    } else {
+        ALOGE("failed to call linkToDeath on client binder, status: %d", static_cast<int>(status));
+    }
+}
+
+void DefaultVehicleHal::onBinderDied(void* cookie) {
+    OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
+    context->vhal->onBinderDiedWithContext(context->clientId);
+}
+
+void DefaultVehicleHal::onBinderDiedWithContext(const AIBinder* clientId) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mSetValuesClients.erase(clientId);
+    mGetValuesClients.erase(clientId);
+    mSubscriptionClients->removeClient(clientId);
+    mSubscriptionManager->unsubscribe(clientId);
+}
+
+void DefaultVehicleHal::onBinderUnlinked(void* cookie) {
+    // Delete the context associated with this cookie.
+    OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
+    context->vhal->onBinderUnlinkedWithContext(context->clientId);
+}
+
+void DefaultVehicleHal::onBinderUnlinkedWithContext(const AIBinder* clientId) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mOnBinderDiedContexts.erase(clientId);
+}
+
+template std::shared_ptr<DefaultVehicleHal::GetValuesClient>
+DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::GetValuesClient>(
+        std::unordered_map<const AIBinder*, std::shared_ptr<GetValuesClient>>* clients,
+        const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+template std::shared_ptr<DefaultVehicleHal::SetValuesClient>
+DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>(
+        std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>>* clients,
+        const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+template std::shared_ptr<SubscriptionClient>
+DefaultVehicleHal::getOrCreateClient<SubscriptionClient>(
+        std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>>* clients,
+        const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+
+void DefaultVehicleHal::getValueFromHardwareCallCallback(
+        std::weak_ptr<IVehicleHardware> vehicleHardware,
+        std::shared_ptr<SubscribeIdByClient> subscribeIdByClient,
+        std::shared_ptr<SubscriptionClients> subscriptionClients, const CallbackType& callback,
+        const VehiclePropValue& value) {
+    int64_t subscribeId = subscribeIdByClient->getId(callback);
+    auto client = subscriptionClients->getClient(callback);
+    if (auto addRequestResult = client->addRequests({subscribeId}); !addRequestResult.ok()) {
+        ALOGE("subscribe[%" PRId64 "]: too many pending requests, ignore the getValue request",
+              subscribeId);
+        return;
+    }
+
+    std::vector<GetValueRequest> hardwareRequests = {{
+            .requestId = subscribeId,
+            .prop = value,
+    }};
+
+    std::shared_ptr<IVehicleHardware> hardware = vehicleHardware.lock();
+    if (hardware == nullptr) {
+        ALOGW("the IVehicleHardware is destroyed, DefaultVehicleHal is ending");
+        return;
+    }
+    if (StatusCode status = hardware->getValues(client->getResultCallback(), hardwareRequests);
+        status != StatusCode::OK) {
+        // If the hardware returns error, finish all the pending requests for this request because
+        // we never expect hardware to call callback for these requests.
+        client->tryFinishRequests({subscribeId});
+        ALOGE("subscribe[%" PRId64 "]: failed to get value from VehicleHardware, code: %d",
+              subscribeId, toInt(status));
+    }
+}
+
+void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) {
+    mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
 }
 
 ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
     if (mConfigFile != nullptr) {
+        output->payloads.clear();
         output->sharedMemoryFd.set(dup(mConfigFile->get()));
         return ScopedAStatus::ok();
     }
@@ -70,18 +299,235 @@
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus DefaultVehicleHal::getValues(const std::shared_ptr<IVehicleCallback>&,
-                                           const GetValueRequests&) {
-    // TODO(b/200737967): implement this.
+Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
+    auto it = mConfigsByPropId.find(propId);
+    if (it == mConfigsByPropId.end()) {
+        return Error() << "no config for property, ID: " << propId;
+    }
+    return &(it->second);
+}
+
+Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
+    int32_t propId = propValue.prop;
+    auto result = getConfig(propId);
+    if (!result.ok()) {
+        return result.error();
+    }
+    const VehiclePropConfig* config = result.value();
+    const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, *config);
+    if (!isGlobalProp(propId) && areaConfig == nullptr) {
+        // Ignore areaId for global property. For non global property, check whether areaId is
+        // allowed. areaId must appear in areaConfig.
+        return Error() << "invalid area ID: " << propValue.areaId << " for prop ID: " << propId
+                       << ", not listed in config";
+    }
+    if (auto result = checkPropValue(propValue, config); !result.ok()) {
+        return Error() << "invalid property value: " << propValue.toString()
+                       << ", error: " << getErrorMsg(result);
+    }
+    if (auto result = checkValueRange(propValue, areaConfig); !result.ok()) {
+        return Error() << "property value out of range: " << propValue.toString()
+                       << ", error: " << getErrorMsg(result);
+    }
+    return {};
+}
+
+ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,
+                                           const GetValueRequests& requests) {
+    monitorBinderLifeCycle(callback);
+
+    expected<LargeParcelableBase::BorrowedOwnedObject<GetValueRequests>, ScopedAStatus>
+            deserializedResults = fromStableLargeParcelable(requests);
+    if (!deserializedResults.ok()) {
+        ALOGE("getValues: failed to parse getValues requests");
+        return std::move(deserializedResults.error());
+    }
+    const std::vector<GetValueRequest>& getValueRequests =
+            deserializedResults.value().getObject()->payloads;
+
+    auto maybeRequestIds = checkDuplicateRequests(getValueRequests);
+    if (!maybeRequestIds.ok()) {
+        ALOGE("getValues: duplicate request ID");
+        return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG);
+    }
+
+    // A list of failed result we already know before sending to hardware.
+    std::vector<GetValueResult> failedResults;
+    // The list of requests that we would send to hardware.
+    std::vector<GetValueRequest> hardwareRequests;
+
+    for (const auto& request : getValueRequests) {
+        if (auto result = checkReadPermission(request.prop); !result.ok()) {
+            ALOGW("property does not support reading: %s", getErrorMsg(result).c_str());
+            failedResults.push_back(GetValueResult{
+                    .requestId = request.requestId,
+                    .status = getErrorCode(result),
+                    .prop = {},
+            });
+        } else {
+            hardwareRequests.push_back(request);
+        }
+    }
+
+    // The set of request Ids that we would send to hardware.
+    std::unordered_set<int64_t> hardwareRequestIds;
+    for (const auto& request : hardwareRequests) {
+        hardwareRequestIds.insert(request.requestId);
+    }
+
+    std::shared_ptr<GetValuesClient> client;
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        client = getOrCreateClient(&mGetValuesClients, callback, mPendingRequestPool);
+    }
+    // Register the pending hardware requests and also check for duplicate request Ids.
+    if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
+        ALOGE("getValues[%s]: failed to add pending requests, error: %s",
+              toString(hardwareRequestIds).c_str(), getErrorMsg(addRequestResult).c_str());
+        return toScopedAStatus(addRequestResult);
+    }
+
+    if (!failedResults.empty()) {
+        // First send the failed results we already know back to the client.
+        client->sendResults(std::move(failedResults));
+    }
+
+    if (hardwareRequests.empty()) {
+        return ScopedAStatus::ok();
+    }
+
+    if (StatusCode status =
+                mVehicleHardware->getValues(client->getResultCallback(), hardwareRequests);
+        status != StatusCode::OK) {
+        // If the hardware returns error, finish all the pending requests for this request because
+        // we never expect hardware to call callback for these requests.
+        client->tryFinishRequests(hardwareRequestIds);
+        ALOGE("getValues[%s]: failed to get value from VehicleHardware, status: %d",
+              toString(hardwareRequestIds).c_str(), toInt(status));
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                toInt(status), "failed to get value from VehicleHardware");
+    }
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus DefaultVehicleHal::setValues(const std::shared_ptr<IVehicleCallback>&,
-                                           const SetValueRequests&) {
-    // TODO(b/200737967): implement this.
+ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback,
+                                           const SetValueRequests& requests) {
+    monitorBinderLifeCycle(callback);
+
+    expected<LargeParcelableBase::BorrowedOwnedObject<SetValueRequests>, ScopedAStatus>
+            deserializedResults = fromStableLargeParcelable(requests);
+    if (!deserializedResults.ok()) {
+        ALOGE("setValues: failed to parse setValues requests");
+        return std::move(deserializedResults.error());
+    }
+    const std::vector<SetValueRequest>& setValueRequests =
+            deserializedResults.value().getObject()->payloads;
+
+    // A list of failed result we already know before sending to hardware.
+    std::vector<SetValueResult> failedResults;
+    // The list of requests that we would send to hardware.
+    std::vector<SetValueRequest> hardwareRequests;
+
+    auto maybeRequestIds = checkDuplicateRequests(setValueRequests);
+    if (!maybeRequestIds.ok()) {
+        ALOGE("setValues: duplicate request ID");
+        return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG);
+    }
+
+    for (auto& request : setValueRequests) {
+        int64_t requestId = request.requestId;
+        if (auto result = checkWritePermission(request.value); !result.ok()) {
+            ALOGW("property does not support writing: %s", getErrorMsg(result).c_str());
+            failedResults.push_back(SetValueResult{
+                    .requestId = requestId,
+                    .status = getErrorCode(result),
+            });
+            continue;
+        }
+        if (auto result = checkProperty(request.value); !result.ok()) {
+            ALOGW("setValues[%" PRId64 "]: property is not valid: %s", requestId,
+                  getErrorMsg(result).c_str());
+            failedResults.push_back(SetValueResult{
+                    .requestId = requestId,
+                    .status = StatusCode::INVALID_ARG,
+            });
+            continue;
+        }
+
+        hardwareRequests.push_back(request);
+    }
+
+    // The set of request Ids that we would send to hardware.
+    std::unordered_set<int64_t> hardwareRequestIds;
+    for (const auto& request : hardwareRequests) {
+        hardwareRequestIds.insert(request.requestId);
+    }
+
+    std::shared_ptr<SetValuesClient> client;
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        client = getOrCreateClient(&mSetValuesClients, callback, mPendingRequestPool);
+    }
+
+    // Register the pending hardware requests and also check for duplicate request Ids.
+    if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
+        ALOGE("setValues[%s], failed to add pending requests, error: %s",
+              toString(hardwareRequestIds).c_str(), getErrorMsg(addRequestResult).c_str());
+        return toScopedAStatus(addRequestResult, StatusCode::INVALID_ARG);
+    }
+
+    if (!failedResults.empty()) {
+        // First send the failed results we already know back to the client.
+        client->sendResults(std::move(failedResults));
+    }
+
+    if (hardwareRequests.empty()) {
+        return ScopedAStatus::ok();
+    }
+
+    if (StatusCode status =
+                mVehicleHardware->setValues(client->getResultCallback(), hardwareRequests);
+        status != StatusCode::OK) {
+        // If the hardware returns error, finish all the pending requests for this request because
+        // we never expect hardware to call callback for these requests.
+        client->tryFinishRequests(hardwareRequestIds);
+        ALOGE("setValues[%s], failed to set value to VehicleHardware, status: %d",
+              toString(hardwareRequestIds).c_str(), toInt(status));
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                toInt(status), "failed to set value to VehicleHardware");
+    }
+
     return ScopedAStatus::ok();
 }
 
+#define CHECK_DUPLICATE_REQUESTS(PROP_NAME)                                                      \
+    do {                                                                                         \
+        std::vector<int64_t> requestIds;                                                         \
+        std::set<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> requestProps; \
+        for (const auto& request : requests) {                                                   \
+            const auto& prop = request.PROP_NAME;                                                \
+            if (requestProps.count(prop) != 0) {                                                 \
+                return ::android::base::Error()                                                  \
+                       << "duplicate request for property: " << prop.toString();                 \
+            }                                                                                    \
+            requestProps.insert(prop);                                                           \
+            requestIds.push_back(request.requestId);                                             \
+        }                                                                                        \
+        return requestIds;                                                                       \
+    } while (0);
+
+::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests(
+        const std::vector<GetValueRequest>& requests) {
+    CHECK_DUPLICATE_REQUESTS(prop);
+}
+
+::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests(
+        const std::vector<SetValueRequest>& requests) {
+    CHECK_DUPLICATE_REQUESTS(value);
+}
+
+#undef CHECK_DUPLICATE_REQUESTS
+
 ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
                                                 VehiclePropConfigs* output) {
     std::vector<VehiclePropConfig> configs;
@@ -90,23 +536,118 @@
             configs.push_back(mConfigsByPropId[prop]);
         }
     }
-    return defaultvehiclehal_impl::vectorToStableLargeParcelable(configs, output);
+    return vectorToStableLargeParcelable(std::move(configs), output);
 }
 
-ScopedAStatus DefaultVehicleHal::subscribe(const std::shared_ptr<IVehicleCallback>&,
-                                           const std::vector<SubscribeOptions>&, int32_t) {
-    // TODO(b/200737967): implement this.
+Result<void> DefaultVehicleHal::checkSubscribeOptions(
+        const std::vector<SubscribeOptions>& options) {
+    for (const auto& option : options) {
+        int32_t propId = option.propId;
+        if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
+            return Error(toInt(StatusCode::INVALID_ARG))
+                   << StringPrintf("no config for property, ID: %" PRId32, propId);
+        }
+        const VehiclePropConfig& config = mConfigsByPropId[propId];
+
+        if (config.changeMode != VehiclePropertyChangeMode::ON_CHANGE &&
+            config.changeMode != VehiclePropertyChangeMode::CONTINUOUS) {
+            return Error(toInt(StatusCode::INVALID_ARG))
+                   << "only support subscribing to ON_CHANGE or CONTINUOUS property";
+        }
+
+        if (config.access != VehiclePropertyAccess::READ &&
+            config.access != VehiclePropertyAccess::READ_WRITE) {
+            return Error(toInt(StatusCode::ACCESS_DENIED))
+                   << StringPrintf("Property %" PRId32 " has no read access", propId);
+        }
+
+        if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+            float sampleRate = option.sampleRate;
+            float minSampleRate = config.minSampleRate;
+            float maxSampleRate = config.maxSampleRate;
+            if (sampleRate < minSampleRate || sampleRate > maxSampleRate) {
+                return Error(toInt(StatusCode::INVALID_ARG))
+                       << StringPrintf("sample rate: %f out of range, must be within %f and %f",
+                                       sampleRate, minSampleRate, maxSampleRate);
+            }
+            if (!SubscriptionManager::checkSampleRate(sampleRate)) {
+                return Error(toInt(StatusCode::INVALID_ARG))
+                       << "invalid sample rate: " << sampleRate;
+            }
+        }
+
+        if (isGlobalProp(propId)) {
+            continue;
+        }
+
+        // Non-global property.
+        for (int32_t areaId : option.areaIds) {
+            if (auto areaConfig = getAreaConfig(propId, areaId, config); areaConfig == nullptr) {
+                return Error(toInt(StatusCode::INVALID_ARG))
+                       << StringPrintf("invalid area ID: %" PRId32 " for prop ID: %" PRId32
+                                       ", not listed in config",
+                                       areaId, propId);
+            }
+        }
+    }
+    return {};
+}
+
+ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
+                                           const std::vector<SubscribeOptions>& options,
+                                           [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
+    monitorBinderLifeCycle(callback);
+
+    // TODO(b/205189110): Use shared memory file count.
+    if (auto result = checkSubscribeOptions(options); !result.ok()) {
+        ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
+        return toScopedAStatus(result);
+    }
+
+    std::vector<SubscribeOptions> onChangeSubscriptions;
+    std::vector<SubscribeOptions> continuousSubscriptions;
+    for (const auto& option : options) {
+        int32_t propId = option.propId;
+        // We have already validate config exists.
+        const VehiclePropConfig& config = mConfigsByPropId[propId];
+
+        SubscribeOptions optionCopy = option;
+        // If areaIds is empty, subscribe to all areas.
+        if (optionCopy.areaIds.empty() && !isGlobalProp(propId)) {
+            for (const auto& areaConfig : config.areaConfigs) {
+                optionCopy.areaIds.push_back(areaConfig.areaId);
+            }
+        }
+
+        if (isGlobalProp(propId)) {
+            optionCopy.areaIds = {0};
+        }
+
+        if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+            continuousSubscriptions.push_back(std::move(optionCopy));
+        } else {
+            onChangeSubscriptions.push_back(std::move(optionCopy));
+        }
+    }
+    // Since we have already check the sample rates, the following functions must succeed.
+    if (!onChangeSubscriptions.empty()) {
+        mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+                                        /*isContinuousProperty=*/false);
+    }
+    if (!continuousSubscriptions.empty()) {
+        mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+                                        /*isContinuousProperty=*/true);
+    }
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus DefaultVehicleHal::unsubscribe(const std::shared_ptr<IVehicleCallback>&,
-                                             const std::vector<int32_t>&) {
-    // TODO(b/200737967): implement this.
-    return ScopedAStatus::ok();
+ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType& callback,
+                                             const std::vector<int32_t>& propIds) {
+    return toScopedAStatus(mSubscriptionManager->unsubscribe(callback->asBinder().get(), propIds),
+                           StatusCode::INVALID_ARG);
 }
 
-ScopedAStatus DefaultVehicleHal::returnSharedMemory(const std::shared_ptr<IVehicleCallback>&,
-                                                    int64_t) {
+ScopedAStatus DefaultVehicleHal::returnSharedMemory(const CallbackType&, int64_t) {
     // TODO(b/200737967): implement this.
     return ScopedAStatus::ok();
 }
@@ -115,6 +656,103 @@
     return mVehicleHardware.get();
 }
 
+Result<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
+    int32_t propId = value.prop;
+    auto result = getConfig(propId);
+    if (!result.ok()) {
+        return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+    }
+    const VehiclePropConfig* config = result.value();
+
+    if (config->access != VehiclePropertyAccess::WRITE &&
+        config->access != VehiclePropertyAccess::READ_WRITE) {
+        return Error(toInt(StatusCode::ACCESS_DENIED))
+               << StringPrintf("Property %" PRId32 " has no write access", propId);
+    }
+    return {};
+}
+
+Result<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
+    int32_t propId = value.prop;
+    auto result = getConfig(propId);
+    if (!result.ok()) {
+        return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+    }
+    const VehiclePropConfig* config = result.value();
+
+    if (config->access != VehiclePropertyAccess::READ &&
+        config->access != VehiclePropertyAccess::READ_WRITE) {
+        return Error(toInt(StatusCode::ACCESS_DENIED))
+               << StringPrintf("Property %" PRId32 " has no read access", propId);
+    }
+    return {};
+}
+
+void DefaultVehicleHal::checkHealth(std::weak_ptr<IVehicleHardware> hardware,
+                                    std::weak_ptr<SubscriptionManager> subscriptionManager) {
+    auto hardwarePtr = hardware.lock();
+    if (hardwarePtr == nullptr) {
+        ALOGW("the VehicleHardware is destroyed, DefaultVehicleHal is ending");
+        return;
+    }
+
+    StatusCode status = hardwarePtr->checkHealth();
+    if (status != StatusCode::OK) {
+        ALOGE("VHAL check health returns non-okay status");
+        return;
+    }
+    std::vector<VehiclePropValue> values = {{
+            .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+            .areaId = 0,
+            .status = VehiclePropertyStatus::AVAILABLE,
+            .value.int64Values = {uptimeMillis()},
+    }};
+    onPropertyChangeEvent(subscriptionManager, values);
+    return;
+}
+
+binder_status_t DefaultVehicleHal::AIBinderLinkToDeathImpl::linkToDeath(
+        AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) {
+    return AIBinder_linkToDeath(binder, recipient, cookie);
+}
+
+void DefaultVehicleHal::setLinkToDeathImpl(std::unique_ptr<ILinkToDeath> impl) {
+    mLinkToDeathImpl = std::move(impl);
+}
+
+bool DefaultVehicleHal::checkDumpPermission() {
+    uid_t uid = AIBinder_getCallingUid();
+    return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
+}
+
+binder_status_t DefaultVehicleHal::dump(int fd, const char** args, uint32_t numArgs) {
+    if (!checkDumpPermission()) {
+        dprintf(fd, "Caller must be root, system or shell");
+        return STATUS_PERMISSION_DENIED;
+    }
+
+    std::vector<std::string> options;
+    for (uint32_t i = 0; i < numArgs; i++) {
+        options.push_back(args[i]);
+    }
+    DumpResult result = mVehicleHardware->dump(options);
+    dprintf(fd, "%s", (result.buffer + "\n").c_str());
+    if (!result.callerShouldDumpState) {
+        dprintf(fd, "Skip dumping Vehicle HAL State.\n");
+        return STATUS_OK;
+    }
+    dprintf(fd, "Vehicle HAL State: \n");
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
+        dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
+        dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
+        dprintf(fd, "Currently have %zu subscription clients\n",
+                mSubscriptionClients->countClients());
+    }
+    return STATUS_OK;
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp b/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp
new file mode 100644
index 0000000..23a5403
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PendingRequestPool.h"
+
+#include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+namespace {
+
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::android::base::Error;
+using ::android::base::Result;
+
+// At least check every 1s.
+constexpr int64_t CHECK_TIME_IN_NANO = 1000000000;
+
+}  // namespace
+
+PendingRequestPool::PendingRequestPool(int64_t timeoutInNano)
+    : mTimeoutInNano(timeoutInNano), mThread([this] {
+          // [this] must be alive within this thread because destructor would wait for this thread
+          // to exit.
+          int64_t sleepTime = std::min(mTimeoutInNano, static_cast<int64_t>(CHECK_TIME_IN_NANO));
+          std::unique_lock<std::mutex> lk(mCvLock);
+          while (!mCv.wait_for(lk, std::chrono::nanoseconds(sleepTime),
+                               [this] { return mThreadStop.load(); })) {
+              checkTimeout();
+          }
+      }) {}
+
+PendingRequestPool::~PendingRequestPool() {
+    mThreadStop = true;
+    mCv.notify_all();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+
+    // If this pool is being destructed, send out all pending requests as timeout.
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+
+        for (auto& [_, pendingRequests] : mPendingRequestsByClient) {
+            for (const auto& request : pendingRequests) {
+                (*request.callback)(request.requestIds);
+            }
+        }
+        mPendingRequestsByClient.clear();
+    }
+}
+
+Result<void> PendingRequestPool::addRequests(const void* clientId,
+                                             const std::unordered_set<int64_t>& requestIds,
+                                             std::shared_ptr<const TimeoutCallbackFunc> callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::list<PendingRequest>* pendingRequests;
+    size_t pendingRequestCount = 0;
+    if (mPendingRequestsByClient.find(clientId) != mPendingRequestsByClient.end()) {
+        pendingRequests = &mPendingRequestsByClient[clientId];
+        for (const auto& pendingRequest : *pendingRequests) {
+            const auto& pendingRequestIds = pendingRequest.requestIds;
+            for (int64_t requestId : requestIds) {
+                if (pendingRequestIds.find(requestId) != pendingRequestIds.end()) {
+                    return Error(toInt(StatusCode::INVALID_ARG))
+                           << "duplicate request ID: " << requestId;
+                }
+            }
+            pendingRequestCount += pendingRequestIds.size();
+        }
+    } else {
+        // Create a new empty list for this client.
+        pendingRequests = &mPendingRequestsByClient[clientId];
+    }
+
+    if (requestIds.size() > MAX_PENDING_REQUEST_PER_CLIENT - pendingRequestCount) {
+        return Error(toInt(StatusCode::TRY_AGAIN)) << "too many pending requests";
+    }
+
+    int64_t currentTime = elapsedRealtimeNano();
+    int64_t timeoutTimestamp = currentTime + mTimeoutInNano;
+
+    pendingRequests->push_back({
+            .requestIds = std::unordered_set<int64_t>(requestIds.begin(), requestIds.end()),
+            .timeoutTimestamp = timeoutTimestamp,
+            .callback = callback,
+    });
+
+    return {};
+}
+
+bool PendingRequestPool::isRequestPending(const void* clientId, int64_t requestId) const {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    return isRequestPendingLocked(clientId, requestId);
+}
+
+size_t PendingRequestPool::countPendingRequests() const {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    size_t count = 0;
+    for (const auto& [clientId, requests] : mPendingRequestsByClient) {
+        for (const auto& request : requests) {
+            count += request.requestIds.size();
+        }
+    }
+    return count;
+}
+
+size_t PendingRequestPool::countPendingRequests(const void* clientId) const {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    auto it = mPendingRequestsByClient.find(clientId);
+    if (it == mPendingRequestsByClient.end()) {
+        return 0;
+    }
+
+    size_t count = 0;
+    for (const auto& pendingRequest : it->second) {
+        count += pendingRequest.requestIds.size();
+    }
+
+    return count;
+}
+
+bool PendingRequestPool::isRequestPendingLocked(const void* clientId, int64_t requestId) const {
+    auto it = mPendingRequestsByClient.find(clientId);
+    if (it == mPendingRequestsByClient.end()) {
+        return false;
+    }
+    for (const auto& pendingRequest : it->second) {
+        const auto& requestIds = pendingRequest.requestIds;
+        if (requestIds.find(requestId) != requestIds.end()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void PendingRequestPool::checkTimeout() {
+    std::vector<PendingRequest> timeoutRequests;
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+
+        int64_t currentTime = elapsedRealtimeNano();
+
+        std::vector<const void*> clientsWithEmptyRequests;
+
+        for (auto& [clientId, pendingRequests] : mPendingRequestsByClient) {
+            auto it = pendingRequests.begin();
+            while (it != pendingRequests.end()) {
+                if (it->timeoutTimestamp >= currentTime) {
+                    break;
+                }
+                timeoutRequests.push_back(std::move(*it));
+                it = pendingRequests.erase(it);
+            }
+
+            if (pendingRequests.empty()) {
+                clientsWithEmptyRequests.push_back(clientId);
+            }
+        }
+
+        for (const void* clientId : clientsWithEmptyRequests) {
+            mPendingRequestsByClient.erase(clientId);
+        }
+    }
+
+    // Call the callback outside the lock.
+    for (const auto& request : timeoutRequests) {
+        (*request.callback)(request.requestIds);
+    }
+}
+
+std::unordered_set<int64_t> PendingRequestPool::tryFinishRequests(
+        const void* clientId, const std::unordered_set<int64_t>& requestIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    std::unordered_set<int64_t> foundIds;
+
+    if (mPendingRequestsByClient.find(clientId) == mPendingRequestsByClient.end()) {
+        return foundIds;
+    }
+
+    auto& pendingRequests = mPendingRequestsByClient[clientId];
+    auto it = pendingRequests.begin();
+    while (it != pendingRequests.end()) {
+        auto& pendingRequestIds = it->requestIds;
+        for (int64_t requestId : requestIds) {
+            auto idIt = pendingRequestIds.find(requestId);
+            if (idIt == pendingRequestIds.end()) {
+                continue;
+            }
+            pendingRequestIds.erase(idIt);
+            foundIds.insert(requestId);
+        }
+        if (pendingRequestIds.empty()) {
+            it = pendingRequests.erase(it);
+            continue;
+        }
+        it++;
+    }
+
+    return foundIds;
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp
new file mode 100644
index 0000000..8521c4d
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RecurrentTimer.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <inttypes.h>
+#include <math.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::android::base::ScopedLockAssertion;
+
+RecurrentTimer::RecurrentTimer() : mThread(&RecurrentTimer::loop, this) {}
+
+RecurrentTimer::~RecurrentTimer() {
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mStopRequested = true;
+    }
+    mCond.notify_one();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void RecurrentTimer::registerTimerCallback(int64_t intervalInNano,
+                                           std::shared_ptr<RecurrentTimer::Callback> callback) {
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+
+        // Aligns the nextTime to multiply of interval.
+        int64_t nextTime = ceil(elapsedRealtimeNano() / intervalInNano) * intervalInNano;
+
+        std::unique_ptr<CallbackInfo> info = std::make_unique<CallbackInfo>();
+        info->callback = callback;
+        info->interval = intervalInNano;
+        info->nextTime = nextTime;
+
+        auto it = mCallbacks.find(callback);
+        if (it != mCallbacks.end()) {
+            ALOGI("Replacing an existing timer callback with a new interval, current: %" PRId64
+                  " ns, new: %" PRId64 " ns",
+                  it->second->interval, intervalInNano);
+            markOutdatedLocked(it->second);
+        }
+        mCallbacks[callback] = info.get();
+        mCallbackQueue.push_back(std::move(info));
+        // Insert the last element into the heap.
+        std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+    }
+    mCond.notify_one();
+}
+
+void RecurrentTimer::unregisterTimerCallback(std::shared_ptr<RecurrentTimer::Callback> callback) {
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+
+        auto it = mCallbacks.find(callback);
+        if (it == mCallbacks.end()) {
+            ALOGE("No event found to unregister");
+            return;
+        }
+
+        markOutdatedLocked(it->second);
+        mCallbacks.erase(it);
+    }
+
+    mCond.notify_one();
+}
+
+void RecurrentTimer::markOutdatedLocked(RecurrentTimer::CallbackInfo* info) {
+    info->outdated = true;
+    info->callback = nullptr;
+    // Make sure the first element is always valid.
+    removeInvalidCallbackLocked();
+}
+
+void RecurrentTimer::removeInvalidCallbackLocked() {
+    while (mCallbackQueue.size() != 0 && mCallbackQueue[0]->outdated) {
+        std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+        mCallbackQueue.pop_back();
+    }
+}
+
+std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() {
+    std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+    std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]);
+    mCallbackQueue.pop_back();
+    // Make sure the first element is always valid.
+    removeInvalidCallbackLocked();
+    return info;
+}
+
+void RecurrentTimer::loop() {
+    std::unique_lock<std::mutex> uniqueLock(mLock);
+
+    while (true) {
+        // Wait until the timer exits or we have at least one recurrent callback.
+        mCond.wait(uniqueLock, [this] {
+            ScopedLockAssertion lockAssertion(mLock);
+            return mStopRequested || mCallbackQueue.size() != 0;
+        });
+
+        int64_t interval;
+        {
+            ScopedLockAssertion lockAssertion(mLock);
+            if (mStopRequested) {
+                return;
+            }
+            // The first element is the nearest next event.
+            int64_t nextTime = mCallbackQueue[0]->nextTime;
+            int64_t now = elapsedRealtimeNano();
+            if (nextTime > now) {
+                interval = nextTime - now;
+            } else {
+                interval = 0;
+            }
+        }
+
+        // Wait for the next event or the timer exits.
+        if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
+                ScopedLockAssertion lockAssertion(mLock);
+                return mStopRequested;
+            })) {
+            return;
+        }
+
+        {
+            ScopedLockAssertion lockAssertion(mLock);
+            int64_t now = elapsedRealtimeNano();
+            while (mCallbackQueue.size() > 0) {
+                int64_t nextTime = mCallbackQueue[0]->nextTime;
+                if (nextTime > now) {
+                    break;
+                }
+
+                std::unique_ptr<CallbackInfo> info = popNextCallbackLocked();
+                info->nextTime += info->interval;
+
+                auto callback = info->callback;
+                mCallbackQueue.push_back(std::move(info));
+                std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+
+                (*callback)();
+            }
+        }
+    }
+}
+
+bool RecurrentTimer::CallbackInfo::cmp(const std::unique_ptr<RecurrentTimer::CallbackInfo>& lhs,
+                                       const std::unique_ptr<RecurrentTimer::CallbackInfo>& rhs) {
+    return lhs->nextTime > rhs->nextTime;
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
new file mode 100644
index 0000000..21bfba6
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SubscriptionManager.h"
+
+#include <math/HashCombine.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+namespace {
+
+constexpr float ONE_SECOND_IN_NANO = 1'000'000'000.;
+
+}  // namespace
+
+using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
+using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+
+bool SubscriptionManager::PropIdAreaId::operator==(const PropIdAreaId& other) const {
+    return areaId == other.areaId && propId == other.propId;
+}
+
+size_t SubscriptionManager::PropIdAreaIdHash::operator()(PropIdAreaId const& propIdAreaId) const {
+    size_t res = 0;
+    hashCombine(res, propIdAreaId.propId);
+    hashCombine(res, propIdAreaId.areaId);
+    return res;
+}
+
+SubscriptionManager::SubscriptionManager(GetValueFunc&& action)
+    : mTimer(std::make_shared<RecurrentTimer>()), mGetValue(std::move(action)) {}
+
+SubscriptionManager::~SubscriptionManager() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    mClientsByPropIdArea.clear();
+    // RecurrentSubscription has reference to mGetValue, so it must be destroyed before mGetValue is
+    // destroyed.
+    mSubscriptionsByClient.clear();
+}
+
+bool SubscriptionManager::checkSampleRate(float sampleRate) {
+    return getInterval(sampleRate).ok();
+}
+
+Result<int64_t> SubscriptionManager::getInterval(float sampleRate) {
+    int64_t interval = 0;
+    if (sampleRate <= 0) {
+        return Error() << "invalid sample rate, must be a positive number";
+    }
+    if (sampleRate <= (ONE_SECOND_IN_NANO / static_cast<float>(INT64_MAX))) {
+        return Error() << "invalid sample rate: " << sampleRate << ", too small";
+    }
+    interval = static_cast<int64_t>(ONE_SECOND_IN_NANO / sampleRate);
+    return interval;
+}
+
+Result<void> SubscriptionManager::subscribe(const std::shared_ptr<IVehicleCallback>& callback,
+                                            const std::vector<SubscribeOptions>& options,
+                                            bool isContinuousProperty) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    std::vector<int64_t> intervals;
+    for (const auto& option : options) {
+        float sampleRate = option.sampleRate;
+
+        if (isContinuousProperty) {
+            auto intervalResult = getInterval(sampleRate);
+            if (!intervalResult.ok()) {
+                return intervalResult.error();
+            }
+            intervals.push_back(intervalResult.value());
+        }
+
+        if (option.areaIds.empty()) {
+            ALOGE("area IDs to subscribe must not be empty");
+            return Error() << "area IDs to subscribe must not be empty";
+        }
+    }
+
+    size_t intervalIndex = 0;
+    ClientIdType clientId = callback->asBinder().get();
+    for (const auto& option : options) {
+        int32_t propId = option.propId;
+        const std::vector<int32_t>& areaIds = option.areaIds;
+        int64_t interval = 0;
+        if (isContinuousProperty) {
+            interval = intervals[intervalIndex];
+            intervalIndex++;
+        }
+        for (int32_t areaId : areaIds) {
+            PropIdAreaId propIdAreaId = {
+                    .propId = propId,
+                    .areaId = areaId,
+            };
+            if (isContinuousProperty) {
+                VehiclePropValue propValueRequest{
+                        .prop = propId,
+                        .areaId = areaId,
+                };
+                mSubscriptionsByClient[clientId][propIdAreaId] =
+                        std::make_unique<RecurrentSubscription>(
+                                mTimer,
+                                [this, callback, propValueRequest] {
+                                    mGetValue(callback, propValueRequest);
+                                },
+                                interval);
+            } else {
+                mSubscriptionsByClient[clientId][propIdAreaId] =
+                        std::make_unique<OnChangeSubscription>();
+            }
+            mClientsByPropIdArea[propIdAreaId][clientId] = callback;
+        }
+    }
+    return {};
+}
+
+Result<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId,
+                                              const std::vector<int32_t>& propIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    if (mSubscriptionsByClient.find(clientId) == mSubscriptionsByClient.end()) {
+        return Error() << "No property was subscribed for the callback";
+    }
+    std::unordered_set<int32_t> subscribedPropIds;
+    for (auto const& [propIdAreaId, _] : mSubscriptionsByClient[clientId]) {
+        subscribedPropIds.insert(propIdAreaId.propId);
+    }
+
+    for (int32_t propId : propIds) {
+        if (subscribedPropIds.find(propId) == subscribedPropIds.end()) {
+            return Error() << "property ID: " << propId << " is not subscribed";
+        }
+    }
+
+    auto& subscriptions = mSubscriptionsByClient[clientId];
+    auto it = subscriptions.begin();
+    while (it != subscriptions.end()) {
+        int32_t propId = it->first.propId;
+        if (std::find(propIds.begin(), propIds.end(), propId) != propIds.end()) {
+            auto& clients = mClientsByPropIdArea[it->first];
+            clients.erase(clientId);
+            if (clients.empty()) {
+                mClientsByPropIdArea.erase(it->first);
+            }
+            it = subscriptions.erase(it);
+        } else {
+            it++;
+        }
+    }
+    if (subscriptions.empty()) {
+        mSubscriptionsByClient.erase(clientId);
+    }
+    return {};
+}
+
+Result<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    if (mSubscriptionsByClient.find(clientId) == mSubscriptionsByClient.end()) {
+        return Error() << "No property was subscribed for this client";
+    }
+
+    auto& subscriptions = mSubscriptionsByClient[clientId];
+    for (auto const& [propIdAreaId, _] : subscriptions) {
+        auto& clients = mClientsByPropIdArea[propIdAreaId];
+        clients.erase(clientId);
+        if (clients.empty()) {
+            mClientsByPropIdArea.erase(propIdAreaId);
+        }
+    }
+    mSubscriptionsByClient.erase(clientId);
+    return {};
+}
+
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
+SubscriptionManager::getSubscribedClients(const std::vector<VehiclePropValue>& updatedValues) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
+            clients;
+
+    for (const auto& value : updatedValues) {
+        PropIdAreaId propIdAreaId{
+                .propId = value.prop,
+                .areaId = value.areaId,
+        };
+        if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+            continue;
+        }
+        for (const auto& [clientId, client] : mClientsByPropIdArea[propIdAreaId]) {
+            if (!mSubscriptionsByClient[clientId][propIdAreaId]->isOnChange()) {
+                continue;
+            }
+            clients[client].push_back(&value);
+        }
+    }
+    return clients;
+}
+
+bool SubscriptionManager::isEmpty() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSubscriptionsByClient.empty() && mClientsByPropIdArea.empty();
+}
+
+SubscriptionManager::RecurrentSubscription::RecurrentSubscription(
+        std::shared_ptr<RecurrentTimer> timer, std::function<void()>&& action, int64_t interval)
+    : mAction(std::make_shared<std::function<void()>>(action)), mTimer(timer) {
+    mTimer->registerTimerCallback(interval, mAction);
+}
+
+SubscriptionManager::RecurrentSubscription::~RecurrentSubscription() {
+    mTimer->unregisterTimerCallback(mAction);
+}
+
+bool SubscriptionManager::RecurrentSubscription::isOnChange() {
+    return false;
+}
+
+bool SubscriptionManager::OnChangeSubscription::isOnChange() {
+    return true;
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
index 14224a5..c8b5c65 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
@@ -32,8 +32,8 @@
             ::ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
 
     ALOGI("Registering as service...");
-    binder_exception_t err = AServiceManager_addService(vhal->asBinder().get(),
-                                                        "android.hardware.automotive.vehicle");
+    binder_exception_t err = AServiceManager_addService(
+            vhal->asBinder().get(), "android.hardware.automotive.vehicle.IVehicle/default");
     if (err != EX_NONE) {
         ALOGE("failed to register android.hardware.automotive.vehicle service, exception: %d", err);
         return 1;
diff --git a/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp
index ddd0c65..bdb0d31 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp
@@ -39,12 +39,17 @@
     void SetUp() override {
         mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
         mCallbackClient = IVehicleCallback::fromBinder(mCallback->asBinder());
+        // timeout: 1s.
+        int64_t timeout = 1000000000;
+        mPool = std::make_shared<PendingRequestPool>(timeout);
     }
 
     std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
 
     MockVehicleCallback* getCallback() { return mCallback.get(); }
 
+    std::shared_ptr<PendingRequestPool> getPool() { return mPool; }
+
   protected:
     using GetValuesClient = GetSetValuesClient<GetValueResult, GetValueResults>;
     using SetValuesClient = GetSetValuesClient<SetValueResult, SetValueResults>;
@@ -52,6 +57,7 @@
   private:
     std::shared_ptr<MockVehicleCallback> mCallback;
     std::shared_ptr<IVehicleCallback> mCallbackClient;
+    std::shared_ptr<PendingRequestPool> mPool;
 };
 
 TEST_F(ConnectedClientTest, testSendGetValueResults) {
@@ -72,9 +78,10 @@
                                                            },
                                            }};
 
-    GetValuesClient client(getCallbackClient());
+    GetValuesClient client(getPool(), getCallbackClient());
 
-    client.sendResults(results);
+    auto resultsCopy = results;
+    client.sendResults(std::move(resultsCopy));
 
     auto maybeGetValueResults = getCallback()->nextGetValueResults();
     ASSERT_TRUE(maybeGetValueResults.has_value());
@@ -99,7 +106,7 @@
                                                            },
                                            }};
 
-    GetValuesClient client(getCallbackClient());
+    GetValuesClient client(getPool(), getCallbackClient());
 
     client.sendResultsSeparately(results);
 
@@ -131,7 +138,9 @@
                                                            },
                                            }};
 
-    GetValuesClient client(getCallbackClient());
+    GetValuesClient client(getPool(), getCallbackClient());
+
+    client.addRequests({0, 1});
 
     (*(client.getResultCallback()))(results);
 
@@ -150,9 +159,10 @@
                                                    .status = StatusCode::OK,
                                            }};
 
-    SetValuesClient client(getCallbackClient());
+    SetValuesClient client(getPool(), getCallbackClient());
 
-    client.sendResults(results);
+    auto resultsCopy = results;
+    client.sendResults(std::move(resultsCopy));
 
     auto maybeSetValueResults = getCallback()->nextSetValueResults();
     ASSERT_TRUE(maybeSetValueResults.has_value());
@@ -169,7 +179,7 @@
                                                    .status = StatusCode::OK,
                                            }};
 
-    SetValuesClient client(getCallbackClient());
+    SetValuesClient client(getPool(), getCallbackClient());
 
     client.sendResultsSeparately(results);
 
@@ -193,7 +203,9 @@
                                                    .status = StatusCode::OK,
                                            }};
 
-    SetValuesClient client(getCallbackClient());
+    SetValuesClient client(getPool(), getCallbackClient());
+
+    client.addRequests({0, 1});
 
     (*(client.getResultCallback()))(results);
 
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 62a7098..7443d5b 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -14,17 +14,30 @@
  * limitations under the License.
  */
 
+#include "ConnectedClient.h"
 #include "DefaultVehicleHal.h"
+#include "MockVehicleCallback.h"
+#include "MockVehicleHardware.h"
 
 #include <IVehicleHardware.h>
 #include <LargeParcelableBase.h>
 #include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
+#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
 
+#include <android-base/thread_annotations.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
 
+#include <chrono>
+#include <list>
 #include <memory>
+#include <mutex>
 #include <optional>
+#include <thread>
+#include <unordered_map>
 #include <vector>
 
 namespace android {
@@ -35,67 +48,60 @@
 namespace {
 
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::IVehicle;
+using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
 
 using ::android::automotive::car_binder_lib::LargeParcelableBase;
 using ::android::base::Result;
 
+using ::ndk::ScopedAStatus;
+using ::ndk::ScopedFileDescriptor;
+using ::ndk::SpAIBinder;
+
+using ::testing::ContainsRegex;
 using ::testing::Eq;
+using ::testing::UnorderedElementsAre;
+using ::testing::UnorderedElementsAreArray;
 using ::testing::WhenSortedBy;
 
-class MockVehicleHardware final : public IVehicleHardware {
-  public:
-    std::vector<VehiclePropConfig> getAllPropertyConfigs() const override {
-        return mPropertyConfigs;
-    }
+constexpr int32_t INVALID_PROP_ID = 0;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t READ_ONLY_PROP = 10006 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x10000000 + 0x01000000 + 0x00400000;
 
-    StatusCode setValues(std::function<void(const std::vector<SetValueResult>&)>&&,
-                         const std::vector<SetValueRequest>&) override {
-        // TODO(b/200737967): mock this.
-        return StatusCode::OK;
-    }
-
-    StatusCode getValues(std::function<void(const std::vector<GetValueResult>&)>&&,
-                         const std::vector<GetValueRequest>&) const override {
-        // TODO(b/200737967): mock this.
-        return StatusCode::OK;
-    }
-
-    DumpResult dump(const std::vector<std::string>&) override {
-        // TODO(b/200737967): mock this.
-        return DumpResult{};
-    }
-
-    StatusCode checkHealth() override {
-        // TODO(b/200737967): mock this.
-        return StatusCode::OK;
-    }
-
-    void registerOnPropertyChangeEvent(
-            std::function<void(const std::vector<VehiclePropValue>&)>&&) override {
-        // TODO(b/200737967): mock this.
-    }
-
-    void registerOnPropertySetErrorEvent(
-            std::function<void(const std::vector<SetValueErrorEvent>&)>&&) override {
-        // TODO(b/200737967): mock this.
-    }
-
-    // Test functions.
-    void setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
-        mPropertyConfigs = configs;
-    }
-
-  private:
-    std::vector<VehiclePropConfig> mPropertyConfigs;
-};
+int32_t testInt32VecProp(size_t i) {
+    // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
+    return static_cast<int32_t>(i) + 0x10000000 + 0x01000000 + 0x00410000;
+}
 
 struct PropConfigCmp {
     bool operator()(const VehiclePropConfig& a, const VehiclePropConfig& b) const {
@@ -103,9 +109,365 @@
     }
 } propConfigCmp;
 
+struct SetValuesInvalidRequestTestCase {
+    std::string name;
+    VehiclePropValue request;
+    StatusCode expectedStatus;
+};
+
+std::vector<SetValuesInvalidRequestTestCase> getSetValuesInvalidRequestTestCases() {
+    return {{
+                    .name = "config_not_found",
+                    .request =
+                            {
+                                    // No config for INVALID_PROP_ID.
+                                    .prop = INVALID_PROP_ID,
+                            },
+                    .expectedStatus = StatusCode::INVALID_ARG,
+            },
+            {
+                    .name = "invalid_prop_value",
+                    .request =
+                            {
+                                    .prop = testInt32VecProp(0),
+                                    // No int32Values for INT32_VEC property.
+                                    .value.int32Values = {},
+                            },
+                    .expectedStatus = StatusCode::INVALID_ARG,
+            },
+            {
+                    .name = "value_out_of_range",
+                    .request =
+                            {
+                                    .prop = testInt32VecProp(0),
+                                    // We configured the range to be 0-100.
+                                    .value.int32Values = {0, -1},
+                            },
+                    .expectedStatus = StatusCode::INVALID_ARG,
+            },
+            {
+                    .name = "invalid_area",
+                    .request =
+                            {
+                                    .prop = INT32_WINDOW_PROP,
+                                    .value.int32Values = {0},
+                                    // Only ROW_1_LEFT is allowed.
+                                    .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+                            },
+                    .expectedStatus = StatusCode::INVALID_ARG,
+            },
+            {
+                    .name = "no_write_permission",
+                    .request =
+                            {
+                                    .prop = READ_ONLY_PROP,
+                                    .value.int32Values = {0},
+                            },
+                    .expectedStatus = StatusCode::ACCESS_DENIED,
+            }};
+}
+
+struct SubscribeInvalidOptionsTestCase {
+    std::string name;
+    SubscribeOptions option;
+};
+
+std::vector<SubscribeInvalidOptionsTestCase> getSubscribeInvalidOptionsTestCases() {
+    return {{
+                    .name = "invalid_prop",
+                    .option =
+                            {
+                                    .propId = INVALID_PROP_ID,
+                            },
+            },
+            {
+                    .name = "invalid_area_ID",
+                    .option =
+                            {
+                                    .propId = AREA_ON_CHANGE_PROP,
+                                    .areaIds = {0},
+                            },
+            },
+            {
+                    .name = "invalid_sample_rate",
+                    .option =
+                            {
+                                    .propId = GLOBAL_CONTINUOUS_PROP,
+                                    .sampleRate = 0.0,
+                            },
+            },
+            {
+                    .name = "sample_rate_out_of_range",
+                    .option =
+                            {
+                                    .propId = GLOBAL_CONTINUOUS_PROP,
+                                    .sampleRate = 1000.0,
+                            },
+            },
+            {
+                    .name = "static_property",
+                    .option =
+                            {
+                                    // Default change mode is static.
+                                    .propId = testInt32VecProp(0),
+                            },
+            }};
+}
+
 }  // namespace
 
-TEST(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
+class DefaultVehicleHalTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        auto hardware = std::make_unique<MockVehicleHardware>();
+        std::vector<VehiclePropConfig> testConfigs;
+        for (size_t i = 0; i < 10000; i++) {
+            testConfigs.push_back(VehiclePropConfig{
+                    .prop = testInt32VecProp(i),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .areaConfigs =
+                            {
+                                    {
+                                            .areaId = 0,
+                                            .minInt32Value = 0,
+                                            .maxInt32Value = 100,
+                                    },
+                            },
+            });
+        }
+        // A property with area config.
+        testConfigs.push_back(
+                VehiclePropConfig{.prop = INT32_WINDOW_PROP,
+                                  .access = VehiclePropertyAccess::READ_WRITE,
+                                  .areaConfigs = {{
+                                          .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                          .minInt32Value = 0,
+                                          .maxInt32Value = 100,
+                                  }}});
+        // A global on-change property.
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = GLOBAL_ON_CHANGE_PROP,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        });
+        // A global continuous property.
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = GLOBAL_CONTINUOUS_PROP,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                .minSampleRate = 0.0,
+                .maxSampleRate = 100.0,
+        });
+        // A per-area on-change property.
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = AREA_ON_CHANGE_PROP,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs =
+                        {
+                                {
+
+                                        .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                        .minInt32Value = 0,
+                                        .maxInt32Value = 100,
+                                },
+                                {
+                                        .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+                                        .minInt32Value = 0,
+                                        .maxInt32Value = 100,
+                                },
+                        },
+        });
+        // A per-area continuous property.
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = AREA_CONTINUOUS_PROP,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                .minSampleRate = 0.0,
+                .maxSampleRate = 1000.0,
+                .areaConfigs =
+                        {
+                                {
+
+                                        .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                        .minInt32Value = 0,
+                                        .maxInt32Value = 100,
+                                },
+                                {
+                                        .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+                                        .minInt32Value = 0,
+                                        .maxInt32Value = 100,
+                                },
+                        },
+        });
+        // A read-only property.
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = READ_ONLY_PROP,
+                .access = VehiclePropertyAccess::READ,
+                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                .minSampleRate = 0.0,
+                .maxSampleRate = 1000.0,
+        });
+        // A write-only property.
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = WRITE_ONLY_PROP,
+                .access = VehiclePropertyAccess::WRITE,
+                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                .minSampleRate = 0.0,
+                .maxSampleRate = 1000.0,
+        });
+        // Register the heartbeat event property.
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+                .access = VehiclePropertyAccess::READ,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        });
+        hardware->setPropertyConfigs(testConfigs);
+        mHardwarePtr = hardware.get();
+        mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+        mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
+        mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
+        // Keep the local binder alive.
+        mBinder = mCallback->asBinder();
+        mCallbackClient = IVehicleCallback::fromBinder(mBinder);
+
+        // Set the linkToDeath to a fake implementation that always returns OK.
+        setTestLinkToDeathImpl();
+    }
+
+    void TearDown() override {
+        ASSERT_EQ(countPendingRequests(), static_cast<size_t>(0))
+                << "must have no pending requests when test finishes";
+    }
+
+    MockVehicleHardware* getHardware() { return mHardwarePtr; }
+
+    std::shared_ptr<IVehicle> getClient() { return mVhal; }
+
+    std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
+
+    MockVehicleCallback* getCallback() { return mCallback.get(); }
+
+    void setTimeout(int64_t timeoutInNano) { mVhal->setTimeout(timeoutInNano); }
+
+    void setTestLinkToDeathImpl() {
+        mVhal->setLinkToDeathImpl(std::make_unique<TestLinkToDeathImpl>());
+    }
+
+    size_t countPendingRequests() { return mVhal->mPendingRequestPool->countPendingRequests(); }
+
+    size_t countClients() {
+        std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+        return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size() +
+               mVhal->mSubscriptionClients->countClients();
+    }
+
+    std::shared_ptr<PendingRequestPool> getPool() { return mVhal->mPendingRequestPool; }
+
+    void onBinderDied(void* cookie) { return mVhal->onBinderDied(cookie); }
+
+    void onBinderUnlinked(void* cookie) { return mVhal->onBinderUnlinked(cookie); }
+
+    void* getOnBinderDiedContexts(AIBinder* clientId) {
+        std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+        return mVhal->mOnBinderDiedContexts[clientId].get();
+    }
+
+    size_t countOnBinderDiedContexts() {
+        std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+        return mVhal->mOnBinderDiedContexts.size();
+    }
+
+    bool hasNoSubscriptions() { return mVhal->mSubscriptionManager->isEmpty(); }
+
+    static Result<void> getValuesTestCases(size_t size, GetValueRequests& requests,
+                                           std::vector<GetValueResult>& expectedResults,
+                                           std::vector<GetValueRequest>& expectedHardwareRequests) {
+        expectedHardwareRequests.clear();
+        for (size_t i = 0; i < size; i++) {
+            int64_t requestId = static_cast<int64_t>(i);
+            int32_t propId = testInt32VecProp(i);
+            expectedHardwareRequests.push_back(GetValueRequest{
+                    .prop =
+                            VehiclePropValue{
+                                    .prop = propId,
+                            },
+                    .requestId = requestId,
+            });
+            expectedResults.push_back(GetValueResult{
+                    .requestId = requestId,
+                    .status = StatusCode::OK,
+                    .prop =
+                            VehiclePropValue{
+                                    .prop = propId,
+                                    .value.int32Values = {1, 2, 3, 4},
+                            },
+            });
+        }
+
+        requests.payloads = expectedHardwareRequests;
+        auto result = LargeParcelableBase::parcelableToStableLargeParcelable(requests);
+        if (!result.ok()) {
+            return result.error();
+        }
+        if (result.value() != nullptr) {
+            requests.sharedMemoryFd = std::move(*result.value());
+            requests.payloads.clear();
+        }
+        return {};
+    }
+
+    static Result<void> setValuesTestCases(size_t size, SetValueRequests& requests,
+                                           std::vector<SetValueResult>& expectedResults,
+                                           std::vector<SetValueRequest>& expectedHardwareRequests) {
+        expectedHardwareRequests.clear();
+        for (size_t i = 0; i < size; i++) {
+            int64_t requestId = static_cast<int64_t>(i);
+            int32_t propId = testInt32VecProp(i);
+            expectedHardwareRequests.push_back(SetValueRequest{
+                    .value =
+                            VehiclePropValue{
+                                    .prop = propId,
+                                    .value.int32Values = {1, 2, 3, 4},
+                            },
+                    .requestId = requestId,
+            });
+            expectedResults.push_back(SetValueResult{
+                    .requestId = requestId,
+                    .status = StatusCode::OK,
+            });
+        }
+
+        requests.payloads = expectedHardwareRequests;
+        auto result = LargeParcelableBase::parcelableToStableLargeParcelable(requests);
+        if (!result.ok()) {
+            return result.error();
+        }
+        if (result.value() != nullptr) {
+            requests.payloads.clear();
+            requests.sharedMemoryFd = std::move(*result.value());
+            requests.payloads.clear();
+        }
+        return {};
+    }
+
+  private:
+    std::shared_ptr<DefaultVehicleHal> mVhal;
+    std::shared_ptr<IVehicle> mVhalClient;
+    MockVehicleHardware* mHardwarePtr;
+    std::shared_ptr<MockVehicleCallback> mCallback;
+    std::shared_ptr<IVehicleCallback> mCallbackClient;
+    SpAIBinder mBinder;
+
+    class TestLinkToDeathImpl final : public DefaultVehicleHal::ILinkToDeath {
+      public:
+        binder_status_t linkToDeath(AIBinder*, AIBinder_DeathRecipient*, void*) override {
+            return STATUS_OK;
+        }
+    };
+};
+
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
     auto testConfigs = std::vector<VehiclePropConfig>({
             VehiclePropConfig{
                     .prop = 1,
@@ -123,14 +485,14 @@
     VehiclePropConfigs output;
     auto status = client->getAllPropConfigs(&output);
 
-    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
     ASSERT_THAT(output.payloads, WhenSortedBy(propConfigCmp, Eq(testConfigs)));
 }
 
-TEST(DefaultVehicleHalTest, testGetAllPropConfigsLarge) {
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsLarge) {
     std::vector<VehiclePropConfig> testConfigs;
-    // 10000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
-    for (size_t i = 0; i < 10000; i++) {
+    // 5000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
+    for (size_t i = 0; i < 5000; i++) {
         testConfigs.push_back(VehiclePropConfig{
                 .prop = static_cast<int32_t>(i),
         });
@@ -144,14 +506,1084 @@
     VehiclePropConfigs output;
     auto status = client->getAllPropConfigs(&output);
 
-    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
     ASSERT_TRUE(output.payloads.empty());
-    Result<std::optional<std::vector<VehiclePropConfig>>> result =
-            LargeParcelableBase::stableLargeParcelableToParcelableVector<VehiclePropConfig>(
-                    output.sharedMemoryFd);
-    ASSERT_TRUE(result.ok());
-    ASSERT_TRUE(result.value().has_value());
-    ASSERT_EQ(result.value().value(), testConfigs);
+    auto result = LargeParcelableBase::stableLargeParcelableToParcelable(output);
+    ASSERT_TRUE(result.ok()) << "failed to parse result shared memory file: "
+                             << result.error().message();
+    ASSERT_EQ(result.value().getObject()->payloads, testConfigs);
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesSmall) {
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addGetValueResponses(expectedResults);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests)
+            << "requests to hardware mismatch";
+
+    auto maybeGetValueResults = getCallback()->nextGetValueResults();
+    ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+    EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesLarge) {
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok())
+            << "requests to hardware mismatch";
+    ;
+
+    getHardware()->addGetValueResponses(expectedResults);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests);
+
+    auto maybeGetValueResults = getCallback()->nextGetValueResults();
+    ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+    const GetValueResults& getValueResults = maybeGetValueResults.value();
+    ASSERT_TRUE(getValueResults.payloads.empty())
+            << "payload should be empty, shared memory file should be used";
+
+    auto result = LargeParcelableBase::stableLargeParcelableToParcelable(getValueResults);
+    ASSERT_TRUE(result.ok()) << "failed to parse shared memory file";
+    ASSERT_EQ(result.value().getObject()->payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesErrorFromHardware) {
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->setStatus("getValues", StatusCode::INTERNAL_ERROR);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "expect getValues to fail when hardware returns error";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INTERNAL_ERROR));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesInvalidLargeParcelableInput) {
+    GetValueRequests requests;
+    requests.sharedMemoryFd = ScopedFileDescriptor(0);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "expect getValues to fail when input parcelable is not valid";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesNoReadPermission) {
+    GetValueRequests requests = {
+            .sharedMemoryFd = {},
+            .payloads =
+                    {
+                            {
+                                    .requestId = 0,
+                                    .prop =
+                                            {
+                                                    .prop = WRITE_ONLY_PROP,
+                                            },
+                            },
+                    },
+    };
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValue with no read permission should return okay with error "
+                                  "returned from callback"
+                               << ", error: " << status.getMessage();
+    EXPECT_TRUE(getHardware()->nextGetValueRequests().empty()) << "expect no request to hardware";
+
+    auto maybeResult = getCallback()->nextGetValueResults();
+    ASSERT_TRUE(maybeResult.has_value()) << "no results in callback";
+    EXPECT_EQ(maybeResult.value().payloads, std::vector<GetValueResult>({
+                                                    {
+                                                            .requestId = 0,
+                                                            .status = StatusCode::ACCESS_DENIED,
+                                                    },
+                                            }))
+            << "expect to get ACCESS_DENIED status if no read permission";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesFinishBeforeTimeout) {
+    // timeout: 0.1s
+    int64_t timeout = 100000000;
+    setTimeout(timeout);
+
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    // The response would be returned after 0.05s.
+    getHardware()->setSleepTime(timeout / 2);
+    getHardware()->addGetValueResponses(expectedResults);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    // Wait for the response.
+    std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
+
+    auto maybeGetValueResults = getCallback()->nextGetValueResults();
+    ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+    EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
+    ASSERT_FALSE(getCallback()->nextGetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesFinishAfterTimeout) {
+    // timeout: 0.1s
+    int64_t timeout = 100000000;
+    setTimeout(timeout);
+
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    // The response would be returned after 0.2s.
+    getHardware()->setSleepTime(timeout * 2);
+    getHardware()->addGetValueResponses(expectedResults);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    // Wait for the response.
+    std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+
+    for (size_t i = 0; i < expectedResults.size(); i++) {
+        expectedResults[i] = {
+                .requestId = expectedResults[i].requestId,
+                .status = StatusCode::TRY_AGAIN,
+                .prop = std::nullopt,
+        };
+    }
+
+    auto maybeGetValueResults = getCallback()->nextGetValueResults();
+    ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+    ASSERT_THAT(maybeGetValueResults.value().payloads, UnorderedElementsAreArray(expectedResults))
+            << "results mismatch, expect TRY_AGAIN error.";
+    ASSERT_FALSE(getCallback()->nextGetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestIdsInTwoRequests) {
+    // timeout: 0.1s
+    int64_t timeout = 100000000;
+    setTimeout(timeout);
+
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->setSleepTime(timeout * 2);
+    getHardware()->addGetValueResponses(expectedResults);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    // Use the same request ID again.
+    status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk())
+            << "Use the same request ID before the previous request finishes must fail";
+
+    // Wait for the request to finish.
+    std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestIdsInOneRequest) {
+    GetValueRequests requests = {.payloads = {
+                                         {
+                                                 .requestId = 0,
+                                                 .prop =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(0),
+                                                         },
+                                         },
+                                         {
+                                                 .requestId = 0,
+                                                 .prop =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(1),
+                                                         },
+                                         },
+                                 }};
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "duplicate Ids in one request must fail";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestProps) {
+    GetValueRequests requests = {.payloads = {
+                                         {
+                                                 .requestId = 0,
+                                                 .prop =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(0),
+                                                         },
+                                         },
+                                         {
+                                                 .requestId = 1,
+                                                 .prop =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(0),
+                                                         },
+                                         },
+                                 }};
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesSmall) {
+    SetValueRequests requests;
+    std::vector<SetValueResult> expectedResults;
+    std::vector<SetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addSetValueResponses(expectedResults);
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
+            << "requests to hardware mismatch";
+
+    auto maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+    ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesLarge) {
+    SetValueRequests requests;
+    std::vector<SetValueResult> expectedResults;
+    std::vector<SetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(setValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addSetValueResponses(expectedResults);
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
+            << "requests to hardware mismatch";
+
+    auto maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+    const SetValueResults& setValueResults = maybeSetValueResults.value();
+    ASSERT_TRUE(setValueResults.payloads.empty())
+            << "payload should be empty, shared memory file should be used";
+
+    auto result = LargeParcelableBase::stableLargeParcelableToParcelable(setValueResults);
+    ASSERT_TRUE(result.ok()) << "failed to parse shared memory file";
+    ASSERT_EQ(result.value().getObject()->payloads, expectedResults) << "results mismatch";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+class SetValuesInvalidRequestTest
+    : public DefaultVehicleHalTest,
+      public testing::WithParamInterface<SetValuesInvalidRequestTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+        SetValuesInvalidRequestTests, SetValuesInvalidRequestTest,
+        ::testing::ValuesIn(getSetValuesInvalidRequestTestCases()),
+        [](const testing::TestParamInfo<SetValuesInvalidRequestTest::ParamType>& info) {
+            return info.param.name;
+        });
+
+TEST_P(SetValuesInvalidRequestTest, testSetValuesInvalidRequest) {
+    SetValuesInvalidRequestTestCase tc = GetParam();
+    std::vector<SetValueResult> expectedHardwareResults{
+            SetValueResult{
+                    .requestId = 1,
+                    .status = StatusCode::OK,
+            },
+    };
+    getHardware()->addSetValueResponses(expectedHardwareResults);
+
+    SetValueRequests requests;
+    SetValueRequest invalidRequest{
+            .requestId = 0,
+            .value = tc.request,
+    };
+    SetValueRequest normalRequest{.requestId = 1,
+                                  .value = {
+                                          .prop = testInt32VecProp(0),
+                                          .value.int32Values = {0},
+                                  }};
+    requests.payloads = {invalidRequest, normalRequest};
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    EXPECT_EQ(getHardware()->nextSetValueRequests(), std::vector<SetValueRequest>({normalRequest}))
+            << "requests to hardware mismatch";
+
+    auto maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+    EXPECT_EQ(maybeSetValueResults.value().payloads, std::vector<SetValueResult>({
+                                                             {
+                                                                     .requestId = 0,
+                                                                     .status = tc.expectedStatus,
+                                                             },
+                                                     }))
+            << "invalid argument result mismatch";
+
+    maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results from hardware in callback";
+    EXPECT_EQ(maybeSetValueResults.value().payloads, expectedHardwareResults)
+            << "results from hardware mismatch";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesFinishBeforeTimeout) {
+    // timeout: 0.1s
+    int64_t timeout = 100000000;
+    setTimeout(timeout);
+
+    SetValueRequests requests;
+    std::vector<SetValueResult> expectedResults;
+    std::vector<SetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    // The response would be returned after 0.05s.
+    getHardware()->setSleepTime(timeout / 2);
+    getHardware()->addSetValueResponses(expectedResults);
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    // Wait for the response.
+    std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
+
+    auto maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+    EXPECT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
+    ASSERT_FALSE(getCallback()->nextSetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesFinishAfterTimeout) {
+    // timeout: 0.1s
+    int64_t timeout = 100000000;
+    setTimeout(timeout);
+
+    SetValueRequests requests;
+    std::vector<SetValueResult> expectedResults;
+    std::vector<SetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    // The response would be returned after 0.2s.
+    getHardware()->setSleepTime(timeout * 2);
+    getHardware()->addSetValueResponses(expectedResults);
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    // Wait for the response.
+    std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+
+    for (size_t i = 0; i < expectedResults.size(); i++) {
+        expectedResults[i] = {
+                .requestId = expectedResults[i].requestId,
+                .status = StatusCode::TRY_AGAIN,
+        };
+    }
+
+    auto maybeSetValueResults = getCallback()->nextSetValueResults();
+    ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+    ASSERT_THAT(maybeSetValueResults.value().payloads, UnorderedElementsAreArray(expectedResults))
+            << "results mismatch, expect TRY_AGAIN error.";
+    ASSERT_FALSE(getCallback()->nextSetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestIdsInTwoRequests) {
+    // timeout: 0.1s
+    int64_t timeout = 100000000;
+    setTimeout(timeout);
+
+    SetValueRequests requests;
+    std::vector<SetValueResult> expectedResults;
+    std::vector<SetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(setValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->setSleepTime(timeout * 2);
+    getHardware()->addSetValueResponses(expectedResults);
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    // Use the same request ID again.
+    status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk())
+            << "Use the same request ID before the previous request finishes must fail";
+
+    // Wait for the request to finish.
+    std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestIdsInOneRequest) {
+    SetValueRequests requests = {.payloads = {
+                                         {
+                                                 .requestId = 0,
+                                                 .value =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(0),
+                                                                 .value.int32Values = {0},
+                                                         },
+                                         },
+                                         {
+                                                 .requestId = 0,
+                                                 .value =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(1),
+                                                                 .value.int32Values = {0},
+                                                         },
+                                         },
+                                 }};
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "duplicate Ids in one request must fail";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestProps) {
+    SetValueRequests requests = {.payloads = {
+                                         {
+                                                 .requestId = 0,
+                                                 .value =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(0),
+                                                                 .value.int32Values = {0},
+                                                         },
+                                         },
+                                         {
+                                                 .requestId = 1,
+                                                 .value =
+                                                         VehiclePropValue{
+                                                                 .prop = testInt32VecProp(0),
+                                                                 .value.int32Values = {0},
+                                                         },
+                                         },
+                                 }};
+
+    auto status = getClient()->setValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeUnsubscribe) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    status = getClient()->unsubscribe(getCallbackClient(),
+                                      std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+    ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnChangeNormal) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    VehiclePropValue testValue{
+            .prop = GLOBAL_ON_CHANGE_PROP,
+            .value.int32Values = {0},
+    };
+    SetValueRequests setValueRequests = {
+            .payloads =
+                    {
+                            SetValueRequest{
+                                    .requestId = 0,
+                                    .value = testValue,
+                            },
+                    },
+    };
+    std::vector<SetValueResult> setValueResults = {{
+            .requestId = 0,
+            .status = StatusCode::OK,
+    }};
+
+    // Set the value to trigger a property change event.
+    getHardware()->addSetValueResponses(setValueResults);
+    status = getClient()->setValues(getCallbackClient(), setValueRequests);
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    auto maybeResults = getCallback()->nextOnPropertyEventResults();
+    ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+    ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+            << "results mismatch, expect on change event for the updated value";
+    ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+            << "more results than expected";
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnchangeUnrelatedEventIgnored) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    VehiclePropValue testValue{
+            .prop = GLOBAL_CONTINUOUS_PROP,
+            .value.int32Values = {0},
+    };
+
+    // Set the value to trigger a property change event. This event should be ignored because we
+    // have not subscribed to it.
+    getHardware()->addSetValueResponses({{
+            .requestId = 0,
+            .status = StatusCode::OK,
+    }});
+    status = getClient()->setValues(getCallbackClient(),
+                                    {
+                                            .payloads =
+                                                    {
+                                                            SetValueRequest{
+                                                                    .requestId = 0,
+                                                                    .value = testValue,
+                                                            },
+                                                    },
+                                    });
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+            << "must receive no property update event if the property is not subscribed";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChange) {
+    int testAreaId = toInt(VehicleAreaWindow::ROW_1_LEFT);
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = AREA_ON_CHANGE_PROP,
+                    .areaIds = {testAreaId},
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    VehiclePropValue testValue{
+            .prop = AREA_ON_CHANGE_PROP,
+            .areaId = testAreaId,
+            .value.int32Values = {0},
+    };
+
+    // Set the value to trigger a property change event.
+    getHardware()->addSetValueResponses({{
+            .requestId = 0,
+            .status = StatusCode::OK,
+    }});
+    status = getClient()->setValues(getCallbackClient(),
+                                    {
+                                            .payloads =
+                                                    {
+                                                            SetValueRequest{
+                                                                    .requestId = 0,
+                                                                    .value = testValue,
+                                                            },
+                                                    },
+                                    });
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    auto maybeResults = getCallback()->nextOnPropertyEventResults();
+    ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+    ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+            << "results mismatch, expect on change event for the updated value";
+    ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+            << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChangeAllAreas) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = AREA_ON_CHANGE_PROP,
+                    // No areaIds means subscribing to all area IDs.
+                    .areaIds = {},
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    VehiclePropValue testValue1{
+            .prop = AREA_ON_CHANGE_PROP,
+            .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+            .value.int32Values = {0},
+    };
+    VehiclePropValue testValue2{
+            .prop = AREA_ON_CHANGE_PROP,
+            .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+            .value.int32Values = {0},
+    };
+
+    // Set the values to trigger property change events for two areas.
+    getHardware()->addSetValueResponses({{
+                                                 .requestId = 0,
+                                                 .status = StatusCode::OK,
+                                         },
+                                         {
+                                                 .requestId = 1,
+                                                 .status = StatusCode::OK,
+                                         }});
+    status = getClient()->setValues(getCallbackClient(),
+                                    {
+                                            .payloads =
+                                                    {
+                                                            SetValueRequest{
+                                                                    .requestId = 0,
+                                                                    .value = testValue1,
+                                                            },
+                                                            SetValueRequest{
+                                                                    .requestId = 1,
+                                                                    .value = testValue2,
+                                                            },
+                                                    },
+                                    });
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    auto maybeResults = getCallback()->nextOnPropertyEventResults();
+    ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+    ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue1, testValue2))
+            << "results mismatch, expect two on-change events for all updated areas";
+    ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+            << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuous) {
+    VehiclePropValue testValue{
+            .prop = GLOBAL_CONTINUOUS_PROP,
+            .value.int32Values = {0},
+    };
+    // Set responses for all the hardware getValues requests.
+    getHardware()->setGetValueResponder(
+            [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+               const std::vector<GetValueRequest>& requests) {
+                std::vector<GetValueResult> results;
+                for (auto& request : requests) {
+                    VehiclePropValue prop = request.prop;
+                    prop.value.int32Values = {0};
+                    results.push_back({
+                            .requestId = request.requestId,
+                            .status = StatusCode::OK,
+                            .prop = prop,
+                    });
+                }
+                (*callback)(results);
+                return StatusCode::OK;
+            });
+
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .sampleRate = 20.0,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    // Sleep for 1s, which should generate ~20 events.
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    // Should trigger about 20 times, check for at least 15 events to be safe.
+    for (size_t i = 0; i < 15; i++) {
+        auto maybeResults = getCallback()->nextOnPropertyEventResults();
+        ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+        ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+                << "results mismatch, expect to get the updated value";
+    }
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaContinuous) {
+    // Set responses for all the hardware getValues requests.
+    getHardware()->setGetValueResponder(
+            [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+               const std::vector<GetValueRequest>& requests) {
+                std::vector<GetValueResult> results;
+                for (auto& request : requests) {
+                    VehiclePropValue prop = request.prop;
+                    prop.value.int32Values = {0};
+                    results.push_back({
+                            .requestId = request.requestId,
+                            .status = StatusCode::OK,
+                            .prop = prop,
+                    });
+                }
+                (*callback)(results);
+                return StatusCode::OK;
+            });
+
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = AREA_CONTINUOUS_PROP,
+                    .sampleRate = 20.0,
+                    .areaIds = {toInt(VehicleAreaWindow::ROW_1_LEFT)},
+            },
+            {
+                    .propId = AREA_CONTINUOUS_PROP,
+                    .sampleRate = 10.0,
+                    .areaIds = {toInt(VehicleAreaWindow::ROW_1_RIGHT)},
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    // Sleep for 1s, which should generate ~20 events.
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    std::vector<VehiclePropValue> events;
+    while (true) {
+        auto maybeResults = getCallback()->nextOnPropertyEventResults();
+        if (!maybeResults.has_value()) {
+            break;
+        }
+        for (const auto& value : maybeResults.value().payloads) {
+            events.push_back(value);
+        }
+    }
+
+    size_t leftCount = 0;
+    size_t rightCount = 0;
+
+    for (const auto& event : events) {
+        ASSERT_EQ(event.prop, AREA_CONTINUOUS_PROP);
+        if (event.areaId == toInt(VehicleAreaWindow::ROW_1_LEFT)) {
+            leftCount++;
+            continue;
+        }
+        rightCount++;
+    }
+
+    // Should trigger about 20 times, check for at least 15 events to be safe.
+    ASSERT_GE(leftCount, static_cast<size_t>(15));
+    // Should trigger about 10 times, check for at least 5 events to be safe.
+    ASSERT_GE(rightCount, static_cast<size_t>(5));
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeOnChange) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    status = getClient()->unsubscribe(getCallbackClient(),
+                                      std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+    ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+
+    VehiclePropValue testValue{
+            .prop = GLOBAL_ON_CHANGE_PROP,
+            .value.int32Values = {0},
+    };
+
+    // Set the value to trigger a property change event.
+    getHardware()->addSetValueResponses({{
+            .requestId = 0,
+            .status = StatusCode::OK,
+    }});
+    status = getClient()->setValues(getCallbackClient(),
+                                    {
+                                            .payloads =
+                                                    {
+                                                            SetValueRequest{
+                                                                    .requestId = 0,
+                                                                    .value = testValue,
+                                                            },
+                                                    },
+                                    });
+
+    ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+    ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+            << "No property event should be generated after unsubscription";
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeContinuous) {
+    VehiclePropValue testValue{
+            .prop = GLOBAL_CONTINUOUS_PROP,
+            .value.int32Values = {0},
+    };
+    // Set responses for all the hardware getValues requests.
+    getHardware()->setGetValueResponder(
+            [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+               const std::vector<GetValueRequest>& requests) {
+                std::vector<GetValueResult> results;
+                for (auto& request : requests) {
+                    VehiclePropValue prop = request.prop;
+                    prop.value.int32Values = {0};
+                    results.push_back({
+                            .requestId = request.requestId,
+                            .status = StatusCode::OK,
+                            .prop = prop,
+                    });
+                }
+                (*callback)(results);
+                return StatusCode::OK;
+            });
+
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .sampleRate = 20.0,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    status = getClient()->unsubscribe(getCallbackClient(),
+                                      std::vector<int32_t>({GLOBAL_CONTINUOUS_PROP}));
+
+    ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+
+    // Clear existing events.
+    while (getCallback()->nextOnPropertyEventResults().has_value()) {
+        // Do nothing.
+    }
+
+    // Wait for a while, make sure no new events are generated.
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+    ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+            << "No property event should be generated after unsubscription";
+}
+
+class SubscribeInvalidOptionsTest
+    : public DefaultVehicleHalTest,
+      public testing::WithParamInterface<SubscribeInvalidOptionsTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+        SubscribeInvalidOptionsTests, SubscribeInvalidOptionsTest,
+        ::testing::ValuesIn(getSubscribeInvalidOptionsTestCases()),
+        [](const testing::TestParamInfo<SubscribeInvalidOptionsTest::ParamType>& info) {
+            return info.param.name;
+        });
+
+TEST_P(SubscribeInvalidOptionsTest, testSubscribeInvalidOptions) {
+    std::vector<SubscribeOptions> options = {GetParam().option};
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_FALSE(status.isOk()) << "invalid subscribe options must fail";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeNoReadPermission) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = WRITE_ONLY_PROP,
+    }};
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_FALSE(status.isOk()) << "subscribe to a write-only property must fail";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeFailure) {
+    auto status = getClient()->unsubscribe(getCallbackClient(),
+                                           std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+    ASSERT_FALSE(status.isOk()) << "unsubscribe to a not-subscribed property must fail";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testHeartbeatEvent) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = toInt(VehicleProperty::VHAL_HEARTBEAT),
+    }};
+    int64_t currentTime = uptimeMillis();
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "unable to subscribe to heartbeat event: " << status.getMessage();
+
+    // We send out a heartbeat event every 3s, so sleep for 3s.
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+
+    auto maybeResults = getCallback()->nextOnPropertyEventResults();
+    ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+    ASSERT_EQ(maybeResults.value().payloads.size(), static_cast<size_t>(1));
+    VehiclePropValue gotValue = maybeResults.value().payloads[0];
+    ASSERT_EQ(gotValue.prop, toInt(VehicleProperty::VHAL_HEARTBEAT));
+    ASSERT_EQ(gotValue.value.int64Values.size(), static_cast<size_t>(1));
+    ASSERT_GE(gotValue.value.int64Values[0], currentTime)
+            << "expect to get the latest timestamp with the heartbeat event";
+}
+
+TEST_F(DefaultVehicleHalTest, testOnBinderDiedUnlinked) {
+    // First subscribe to a continuous property so that we register a death recipient for our
+    // client.
+    VehiclePropValue testValue{
+            .prop = GLOBAL_CONTINUOUS_PROP,
+            .value.int32Values = {0},
+    };
+    // Set responses for all the hardware getValues requests.
+    getHardware()->setGetValueResponder(
+            [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+               const std::vector<GetValueRequest>& requests) {
+                std::vector<GetValueResult> results;
+                for (auto& request : requests) {
+                    VehiclePropValue prop = request.prop;
+                    prop.value.int32Values = {0};
+                    results.push_back({
+                            .requestId = request.requestId,
+                            .status = StatusCode::OK,
+                            .prop = prop,
+                    });
+                }
+                (*callback)(results);
+                return StatusCode::OK;
+            });
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .sampleRate = 20.0,
+            },
+    };
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+    // Sleep for 100ms so that the subscriptionClient gets created because we would at least try to
+    // get value once.
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+    // Issue another getValue request on the same client.
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+    ASSERT_TRUE(getValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
+    getHardware()->addGetValueResponses(expectedResults);
+    status = getClient()->getValues(getCallbackClient(), requests);
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+    ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(1))
+            << "expect one OnBinderDied context when one client is registered";
+
+    // Get the death recipient cookie for our callback that would be used in onBinderDied and
+    // onBinderUnlinked.
+    AIBinder* clientId = getCallbackClient()->asBinder().get();
+    void* context = getOnBinderDiedContexts(clientId);
+
+    onBinderDied(context);
+
+    ASSERT_EQ(countClients(), static_cast<size_t>(0))
+            << "expect all clients to be removed when binder died";
+    ASSERT_TRUE(hasNoSubscriptions()) << "expect no subscriptions when binder died";
+
+    onBinderUnlinked(context);
+
+    ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(0))
+            << "expect OnBinderDied context to be deleted when binder is unlinked";
+}
+
+TEST_F(DefaultVehicleHalTest, testDumpCallerShouldDump) {
+    std::string buffer = "Dump from hardware";
+    getHardware()->setDumpResult({
+            .callerShouldDumpState = true,
+            .buffer = buffer,
+    });
+    int fd = memfd_create("memfile", 0);
+    getClient()->dump(fd, nullptr, 0);
+
+    lseek(fd, 0, SEEK_SET);
+    char buf[10240] = {};
+    read(fd, buf, sizeof(buf));
+    close(fd);
+
+    std::string msg(buf);
+
+    ASSERT_THAT(msg, ContainsRegex(buffer + "\nVehicle HAL State: \n"));
+}
+
+TEST_F(DefaultVehicleHalTest, testDumpCallerShouldNotDump) {
+    std::string buffer = "Dump from hardware";
+    getHardware()->setDumpResult({
+            .callerShouldDumpState = false,
+            .buffer = buffer,
+    });
+    int fd = memfd_create("memfile", 0);
+    getClient()->dump(fd, nullptr, 0);
+
+    lseek(fd, 0, SEEK_SET);
+    char buf[10240] = {};
+    read(fd, buf, sizeof(buf));
+    close(fd);
+
+    std::string msg(buf);
+
+    ASSERT_THAT(msg, ContainsRegex(buffer));
+    ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
 }
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index ca366cd..5e3e03c 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -31,16 +31,6 @@
 using ::ndk::ScopedFileDescriptor;
 
 template <class T>
-std::optional<T> pop(std::list<T>& items) {
-    if (items.size() > 0) {
-        auto item = std::move(items.front());
-        items.pop_front();
-        return item;
-    }
-    return std::nullopt;
-}
-
-template <class T>
 static ScopedAStatus storeResults(const T& results, std::list<T>* storedResults) {
     T resultsCopy{
             .payloads = results.payloads,
@@ -65,8 +55,12 @@
     return storeResults(results, &mSetValueResults);
 }
 
-ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues&, int32_t) {
-    return ScopedAStatus::ok();
+ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues& results,
+                                                   int32_t sharedMemoryFileCount) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+
+    mSharedMemoryFileCount = sharedMemoryFileCount;
+    return storeResults(results, &mOnPropertyEventResults);
 }
 
 ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
@@ -83,6 +77,11 @@
     return pop(mSetValueResults);
 }
 
+std::optional<VehiclePropValues> MockVehicleCallback::nextOnPropertyEventResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return pop(mOnPropertyEventResults);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index 916575a..c83164f 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -31,6 +31,16 @@
 namespace automotive {
 namespace vehicle {
 
+template <class T>
+std::optional<T> pop(std::list<T>& items) {
+    if (items.size() > 0) {
+        auto item = std::move(items.front());
+        items.pop_front();
+        return item;
+    }
+    return std::nullopt;
+}
+
 // MockVehicleCallback is a mock VehicleCallback implementation that simply stores the results.
 class MockVehicleCallback final
     : public ::aidl::android::hardware::automotive::vehicle::BnVehicleCallback {
@@ -52,6 +62,8 @@
     nextGetValueResults();
     std::optional<::aidl::android::hardware::automotive::vehicle::SetValueResults>
     nextSetValueResults();
+    std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValues>
+    nextOnPropertyEventResults();
 
   private:
     std::mutex mLock;
@@ -59,6 +71,9 @@
             GUARDED_BY(mLock);
     std::list<::aidl::android::hardware::automotive::vehicle::SetValueResults> mSetValueResults
             GUARDED_BY(mLock);
+    std::list<::aidl::android::hardware::automotive::vehicle::VehiclePropValues>
+            mOnPropertyEventResults GUARDED_BY(mLock);
+    int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
new file mode 100644
index 0000000..66aef7c
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockVehicleHardware.h"
+#include "MockVehicleCallback.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+MockVehicleHardware::~MockVehicleHardware() {
+    std::unique_lock<std::mutex> lk(mLock);
+    mCv.wait(lk, [this] { return mThreadCount == 0; });
+}
+
+std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mPropertyConfigs;
+}
+
+StatusCode MockVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
+                                          const std::vector<SetValueRequest>& requests) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    if (StatusCode status = handleRequestsLocked(__func__, callback, requests, &mSetValueRequests,
+                                                 &mSetValueResponses);
+        status != StatusCode::OK) {
+        return status;
+    }
+    if (mPropertyChangeCallback == nullptr) {
+        return StatusCode::OK;
+    }
+    std::vector<VehiclePropValue> values;
+    for (auto& request : requests) {
+        values.push_back(request.value);
+    }
+    (*mPropertyChangeCallback)(values);
+    return StatusCode::OK;
+}
+
+StatusCode MockVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
+                                          const std::vector<GetValueRequest>& requests) const {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    if (mGetValueResponder != nullptr) {
+        return mGetValueResponder(callback, requests);
+    }
+    return handleRequestsLocked(__func__, callback, requests, &mGetValueRequests,
+                                &mGetValueResponses);
+}
+
+void MockVehicleHardware::setDumpResult(DumpResult result) {
+    mDumpResult = result;
+}
+
+DumpResult MockVehicleHardware::dump(const std::vector<std::string>&) {
+    return mDumpResult;
+}
+
+StatusCode MockVehicleHardware::checkHealth() {
+    return StatusCode::OK;
+}
+
+void MockVehicleHardware::registerOnPropertyChangeEvent(
+        std::unique_ptr<const PropertyChangeCallback> callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mPropertyChangeCallback = std::move(callback);
+}
+
+void MockVehicleHardware::registerOnPropertySetErrorEvent(
+        std::unique_ptr<const PropertySetErrorCallback>) {
+    // TODO(b/200737967): mock this.
+}
+
+void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mPropertyConfigs = configs;
+}
+
+void MockVehicleHardware::addGetValueResponses(const std::vector<GetValueResult>& responses) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mGetValueResponses.push_back(responses);
+}
+
+void MockVehicleHardware::addSetValueResponses(const std::vector<SetValueResult>& responses) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mSetValueResponses.push_back(responses);
+}
+
+void MockVehicleHardware::setGetValueResponder(
+        std::function<StatusCode(std::shared_ptr<const GetValuesCallback>,
+                                 const std::vector<GetValueRequest>&)>&& responder) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mGetValueResponder = responder;
+}
+
+std::vector<GetValueRequest> MockVehicleHardware::nextGetValueRequests() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
+    if (!request.has_value()) {
+        return std::vector<GetValueRequest>();
+    }
+    return std::move(request.value());
+}
+
+std::vector<SetValueRequest> MockVehicleHardware::nextSetValueRequests() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
+    if (!request.has_value()) {
+        return std::vector<SetValueRequest>();
+    }
+    return std::move(request.value());
+}
+
+void MockVehicleHardware::setStatus(const char* functionName, StatusCode status) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mStatusByFunctions[functionName] = status;
+}
+
+void MockVehicleHardware::setSleepTime(int64_t timeInNano) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mSleepTime = timeInNano;
+}
+
+template <class ResultType>
+StatusCode MockVehicleHardware::returnResponse(
+        std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+        std::list<std::vector<ResultType>>* storedResponses) const {
+    if (storedResponses->size() > 0) {
+        (*callback)(std::move(storedResponses->front()));
+        storedResponses->pop_front();
+        return StatusCode::OK;
+    } else {
+        ALOGE("no more response");
+        return StatusCode::INTERNAL_ERROR;
+    }
+}
+
+template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
+        std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+        std::list<std::vector<GetValueResult>>* storedResponses) const;
+
+template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
+        std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+        std::list<std::vector<SetValueResult>>* storedResponses) const;
+
+template <class RequestType, class ResultType>
+StatusCode MockVehicleHardware::handleRequestsLocked(
+        const char* functionName,
+        std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+        const std::vector<RequestType>& requests,
+        std::list<std::vector<RequestType>>* storedRequests,
+        std::list<std::vector<ResultType>>* storedResponses) const {
+    storedRequests->push_back(requests);
+    if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
+        if (StatusCode status = it->second; status != StatusCode::OK) {
+            return status;
+        }
+    }
+
+    if (mSleepTime != 0) {
+        int64_t sleepTime = mSleepTime;
+        mThreadCount++;
+        std::thread t([this, callback, sleepTime, storedResponses]() {
+            std::this_thread::sleep_for(std::chrono::nanoseconds(sleepTime));
+            returnResponse(callback, storedResponses);
+            mThreadCount--;
+            mCv.notify_one();
+        });
+        // Detach the thread here so we do not have to maintain the thread object. mThreadCount
+        // and mCv make sure we wait for all threads to end before we exit.
+        t.detach();
+        return StatusCode::OK;
+
+    } else {
+        return returnResponse(callback, storedResponses);
+    }
+}
+
+template StatusCode MockVehicleHardware::handleRequestsLocked<GetValueRequest, GetValueResult>(
+        const char* functionName,
+        std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+        const std::vector<GetValueRequest>& requests,
+        std::list<std::vector<GetValueRequest>>* storedRequests,
+        std::list<std::vector<GetValueResult>>* storedResponses) const;
+
+template StatusCode MockVehicleHardware::handleRequestsLocked<SetValueRequest, SetValueResult>(
+        const char* functionName,
+        std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+        const std::vector<SetValueRequest>& requests,
+        std::list<std::vector<SetValueRequest>>* storedRequests,
+        std::list<std::vector<SetValueResult>>* storedResponses) const;
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
new file mode 100644
index 0000000..74d4fae
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleHardware_H_
+#define android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleHardware_H_
+
+#include <IVehicleHardware.h>
+#include <VehicleHalTypes.h>
+
+#include <android-base/thread_annotations.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+class MockVehicleHardware final : public IVehicleHardware {
+  public:
+    ~MockVehicleHardware();
+
+    std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+    getAllPropertyConfigs() const override;
+    ::aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+            std::shared_ptr<const SetValuesCallback> callback,
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+                    requests) override;
+    ::aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+            std::shared_ptr<const GetValuesCallback> callback,
+            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+                    requests) const override;
+    DumpResult dump(const std::vector<std::string>&) override;
+    ::aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override;
+    void registerOnPropertyChangeEvent(
+            std::unique_ptr<const PropertyChangeCallback> callback) override;
+    void registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback>) override;
+
+    // Test functions.
+    void setPropertyConfigs(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>&
+                    configs);
+    void addGetValueResponses(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>&
+                    responses);
+    void addSetValueResponses(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>&
+                    responses);
+    void setGetValueResponder(
+            std::function<::aidl::android::hardware::automotive::vehicle::StatusCode(
+                    std::shared_ptr<const GetValuesCallback>,
+                    const std::vector<
+                            ::aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>&&
+                    responder);
+    std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>
+    nextGetValueRequests();
+    std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>
+    nextSetValueRequests();
+    void setStatus(const char* functionName,
+                   ::aidl::android::hardware::automotive::vehicle::StatusCode status);
+    void setSleepTime(int64_t timeInNano);
+    void setDumpResult(DumpResult result);
+
+  private:
+    mutable std::mutex mLock;
+    mutable std::condition_variable mCv;
+    mutable std::atomic<int> mThreadCount;
+    std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig> mPropertyConfigs
+            GUARDED_BY(mLock);
+    mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>>
+            mGetValueRequests GUARDED_BY(mLock);
+    mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>>
+            mGetValueResponses GUARDED_BY(mLock);
+    mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>>
+            mSetValueRequests GUARDED_BY(mLock);
+    mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>>
+            mSetValueResponses GUARDED_BY(mLock);
+    std::unordered_map<const char*, ::aidl::android::hardware::automotive::vehicle::StatusCode>
+            mStatusByFunctions GUARDED_BY(mLock);
+    int64_t mSleepTime GUARDED_BY(mLock) = 0;
+    std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
+    std::function<::aidl::android::hardware::automotive::vehicle::StatusCode(
+            std::shared_ptr<const GetValuesCallback>,
+            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
+            mGetValueResponder GUARDED_BY(mLock);
+
+    template <class ResultType>
+    ::aidl::android::hardware::automotive::vehicle::StatusCode returnResponse(
+            std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+            std::list<std::vector<ResultType>>* storedResponses) const;
+    template <class RequestType, class ResultType>
+    ::aidl::android::hardware::automotive::vehicle::StatusCode handleRequestsLocked(
+            const char* functionName,
+            std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+            const std::vector<RequestType>& requests,
+            std::list<std::vector<RequestType>>* storedRequests,
+            std::list<std::vector<ResultType>>* storedResponses) const REQUIRES(mLock);
+
+    DumpResult mDumpResult;
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleHardware_H_
diff --git a/automotive/vehicle/aidl/impl/vhal/test/PendingRequestPoolTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/PendingRequestPoolTest.cpp
new file mode 100644
index 0000000..9c9e4b9
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/PendingRequestPoolTest.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PendingRequestPool.h"
+
+#include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+
+using ::testing::ElementsAre;
+using ::testing::UnorderedElementsAre;
+using ::testing::WhenSorted;
+
+class PendingRequestPoolTest : public ::testing::Test {
+  public:
+    void SetUp() override { mPool = std::make_unique<PendingRequestPool>(TEST_TIMEOUT); }
+
+    void TearDown() override {
+        if (mPool != nullptr) {
+            ASSERT_EQ(mPool->countPendingRequests(getTestClientId()), static_cast<size_t>(0))
+                    << "at least one pending request still exists in the pool when finish";
+        }
+    }
+
+    PendingRequestPool* getPool() { return mPool.get(); }
+
+    void destroyPool() { mPool.reset(); }
+
+    int64_t getTimeout() { return TEST_TIMEOUT; }
+
+    const void* getTestClientId() { return reinterpret_cast<const void*>(0); }
+
+  private:
+    // Test timeout is 0.1s.
+    static const int64_t TEST_TIMEOUT = 100000000;
+
+    std::unique_ptr<PendingRequestPool> mPool;
+};
+
+TEST_F(PendingRequestPoolTest, testFinishAllRequests) {
+    std::mutex lock;
+    std::vector<int64_t> timeoutRequestIds;
+
+    std::unordered_set<int64_t> requestIds;
+    for (int64_t i = 0; i < 10; i++) {
+        requestIds.insert(i);
+    }
+
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [&lock, &timeoutRequestIds](const std::unordered_set<int64_t>& requests) {
+                std::scoped_lock<std::mutex> lockGuard(lock);
+                for (int64_t request : requests) {
+                    timeoutRequestIds.push_back(request);
+                }
+            });
+
+    ASSERT_RESULT_OK(getPool()->addRequests(getTestClientId(), requestIds, callback));
+
+    for (int64_t i = 0; i < 10; i++) {
+        ASSERT_TRUE(getPool()->isRequestPending(getTestClientId(), i));
+    }
+
+    for (int64_t i = 0; i < 10; i++) {
+        ASSERT_THAT(getPool()->tryFinishRequests(getTestClientId(), {i}), UnorderedElementsAre(i));
+    }
+
+    for (int64_t i = 0; i < 10; i++) {
+        ASSERT_FALSE(getPool()->isRequestPending(getTestClientId(), i));
+    }
+}
+
+TEST_F(PendingRequestPoolTest, testFinishHalfOfRequest) {
+    int64_t timeout = getTimeout();
+    std::mutex lock;
+    std::vector<int64_t> timeoutRequestIds;
+
+    std::unordered_set<int64_t> requestIds;
+    for (int64_t i = 0; i < 10; i++) {
+        requestIds.insert(i);
+    }
+
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [&lock, &timeoutRequestIds](const std::unordered_set<int64_t>& requests) {
+                std::scoped_lock<std::mutex> lockGuard(lock);
+                for (int64_t request : requests) {
+                    timeoutRequestIds.push_back(request);
+                }
+            });
+
+    ASSERT_RESULT_OK(getPool()->addRequests(getTestClientId(), requestIds, callback));
+
+    for (int64_t i = 0; i < 10; i++) {
+        ASSERT_TRUE(getPool()->isRequestPending(getTestClientId(), i));
+    }
+
+    // Finish half of the requests.
+    requestIds.clear();
+    for (int64_t i = 0; i < 5; i++) {
+        requestIds.insert(i);
+    }
+
+    ASSERT_EQ(getPool()->tryFinishRequests(getTestClientId(), requestIds), requestIds);
+
+    for (int64_t i = 0; i < 5; i++) {
+        ASSERT_FALSE(getPool()->isRequestPending(getTestClientId(), i));
+    }
+    for (int64_t i = 5; i < 10; i++) {
+        ASSERT_TRUE(getPool()->isRequestPending(getTestClientId(), i));
+    }
+
+    // Wait until the unfinished requests timeout. The check interval is timeout, so at max we
+    // would wait an additional interval, which is 2 * timeout until the callback is called.
+    std::this_thread::sleep_for(2 * std::chrono::nanoseconds(timeout));
+
+    ASSERT_THAT(timeoutRequestIds, WhenSorted(ElementsAre(5, 6, 7, 8, 9)));
+}
+
+TEST_F(PendingRequestPoolTest, testFinishRequestTwice) {
+    std::mutex lock;
+    std::vector<int64_t> timeoutRequestIds;
+
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [&lock, &timeoutRequestIds](const std::unordered_set<int64_t>& requests) {
+                std::scoped_lock<std::mutex> lockGuard(lock);
+                for (int64_t request : requests) {
+                    timeoutRequestIds.push_back(request);
+                }
+            });
+
+    ASSERT_RESULT_OK(getPool()->addRequests(getTestClientId(), {0}, callback));
+
+    ASSERT_THAT(getPool()->tryFinishRequests(getTestClientId(), {0}), UnorderedElementsAre(0))
+            << "failed to finish an added request";
+    ASSERT_TRUE(getPool()->tryFinishRequests(getTestClientId(), {0}).empty())
+            << "finish a request second time must return empty result";
+}
+
+TEST_F(PendingRequestPoolTest, testFinishRequestNonExistingId) {
+    std::mutex lock;
+    std::vector<int64_t> timeoutRequestIds;
+
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [&lock, &timeoutRequestIds](const std::unordered_set<int64_t>& requests) {
+                std::scoped_lock<std::mutex> lockGuard(lock);
+                for (int64_t request : requests) {
+                    timeoutRequestIds.push_back(request);
+                }
+            });
+
+    ASSERT_RESULT_OK(getPool()->addRequests(getTestClientId(), {0, 1, 2}, callback));
+
+    ASSERT_THAT(getPool()->tryFinishRequests(getTestClientId(), {0, 1, 2, 3}),
+                UnorderedElementsAre(0, 1, 2))
+            << "finished request IDs must not contain non-existing request ID";
+    // Even though one of the request to finish does not exist, the rest of the requests should be
+    // finished.
+    ASSERT_EQ(getPool()->countPendingRequests(getTestClientId()), static_cast<size_t>(0))
+            << "requests not being finished correctly";
+}
+
+TEST_F(PendingRequestPoolTest, testFinishAfterTimeout) {
+    std::mutex lock;
+    std::vector<int64_t> timeoutRequestIds;
+
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [&lock, &timeoutRequestIds](const std::unordered_set<int64_t>& requests) {
+                std::scoped_lock<std::mutex> lockGuard(lock);
+                for (int64_t request : requests) {
+                    timeoutRequestIds.push_back(request);
+                }
+            });
+
+    ASSERT_RESULT_OK(getPool()->addRequests(getTestClientId(), {0}, callback));
+
+    std::this_thread::sleep_for(2 * std::chrono::nanoseconds(getTimeout()));
+
+    ASSERT_TRUE(getPool()->tryFinishRequests(getTestClientId(), {0}).empty())
+            << "finish a request after timeout must do nothing";
+}
+
+TEST_F(PendingRequestPoolTest, testDestroyWithPendingRequests) {
+    std::mutex lock;
+    std::vector<int64_t> timeoutRequestIds;
+
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [&lock, &timeoutRequestIds](const std::unordered_set<int64_t>& requests) {
+                std::scoped_lock<std::mutex> lockGuard(lock);
+                for (int64_t request : requests) {
+                    timeoutRequestIds.push_back(request);
+                }
+            });
+
+    ASSERT_RESULT_OK(getPool()->addRequests(getTestClientId(), {0}, callback));
+
+    destroyPool();
+
+    // Before the pool is destroyed, the pending requests should be notified as timeout.
+    ASSERT_THAT(timeoutRequestIds, UnorderedElementsAre(0))
+            << "timeout not triggered when the pool is destroyed";
+}
+
+TEST_F(PendingRequestPoolTest, testDuplicateRequestId) {
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [](std::unordered_set<int64_t>) {});
+
+    ASSERT_RESULT_OK(getPool()->addRequests(getTestClientId(), {0}, callback));
+    ASSERT_FALSE(getPool()->addRequests(getTestClientId(), {1, 2, 0}, callback).ok())
+            << "adding duplicate request IDs must fail";
+
+    ASSERT_THAT(getPool()->tryFinishRequests(getTestClientId(), {0}), UnorderedElementsAre(0));
+}
+
+TEST_F(PendingRequestPoolTest, testSameRequestIdForDifferentClient) {
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [](std::unordered_set<int64_t>) {});
+
+    ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<const void*>(0), {0}, callback));
+    ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<const void*>(1), {1, 2, 0}, callback));
+
+    ASSERT_THAT(getPool()->tryFinishRequests(reinterpret_cast<const void*>(0), {0}),
+                UnorderedElementsAre(0));
+    ASSERT_THAT(getPool()->tryFinishRequests(reinterpret_cast<const void*>(1), {1, 2, 0}),
+                UnorderedElementsAre(0, 1, 2));
+}
+
+TEST_F(PendingRequestPoolTest, testPendingRequestCountLimit) {
+    auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
+            [](std::unordered_set<int64_t>) {});
+
+    std::unordered_set<int64_t> requests;
+
+    // MAX_PENDING_REQUEST_PER_CLIENT = 10000
+    for (size_t i = 0; i < 10000; i++) {
+        requests.insert(static_cast<int64_t>(i));
+    }
+    ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<const void*>(0), requests, callback));
+
+    auto result = getPool()->addRequests(reinterpret_cast<const void*>(0),
+                                         {static_cast<int64_t>(10000)}, callback);
+    ASSERT_FALSE(result.ok()) << "adding more pending requests than limit must fail";
+    ASSERT_EQ(result.error().code(), toInt(StatusCode::TRY_AGAIN));
+
+    getPool()->tryFinishRequests(reinterpret_cast<const void*>(0), requests);
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp
new file mode 100644
index 0000000..d343cea
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RecurrentTimer.h"
+
+#include <android-base/thread_annotations.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+class RecurrentTimerTest : public ::testing::Test {
+  public:
+    std::shared_ptr<RecurrentTimer::Callback> getCallback(size_t token) {
+        return std::make_shared<RecurrentTimer::Callback>([this, token] {
+            std::scoped_lock<std::mutex> lockGuard(mLock);
+
+            mCallbacks.push_back(token);
+        });
+    }
+
+    std::vector<size_t> getCalledCallbacks() {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        return mCallbacks;
+    }
+
+    void clearCalledCallbacks() {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mCallbacks.clear();
+    }
+
+    size_t countTimerCallbackQueue(RecurrentTimer* timer) {
+        std::scoped_lock<std::mutex> lockGuard(timer->mLock);
+        return timer->mCallbackQueue.size();
+    }
+
+  private:
+    std::mutex mLock;
+    std::vector<size_t> mCallbacks GUARDED_BY(mLock);
+};
+
+TEST_F(RecurrentTimerTest, testRegisterCallback) {
+    RecurrentTimer timer;
+    // 0.1s
+    int64_t interval = 100000000;
+
+    auto action = getCallback(0);
+    timer.registerTimerCallback(interval, action);
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    timer.unregisterTimerCallback(action);
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+}
+
+TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
+    RecurrentTimer timer;
+    // 0.1s
+    int64_t interval = 100000000;
+
+    auto action = getCallback(0);
+    timer.registerTimerCallback(interval, action);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+    timer.unregisterTimerCallback(action);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+    clearCalledCallbacks();
+
+    timer.registerTimerCallback(interval, action);
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+}
+
+TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
+    std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
+    // 0.1s
+    int64_t interval = 100000000;
+
+    auto action = getCallback(0);
+    timer->registerTimerCallback(interval, action);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+    timer.reset();
+
+    clearCalledCallbacks();
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+    ASSERT_TRUE(getCalledCallbacks().empty());
+}
+
+TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
+    RecurrentTimer timer;
+    // 0.1s
+    int64_t interval1 = 100000000;
+    auto action1 = getCallback(1);
+    timer.registerTimerCallback(interval1, action1);
+    // 0.05s
+    int64_t interval2 = 50000000;
+    auto action2 = getCallback(2);
+    timer.registerTimerCallback(interval2, action2);
+    // 0.03s
+    int64_t interval3 = 30000000;
+    auto action3 = getCallback(3);
+    timer.registerTimerCallback(interval3, action3);
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    timer.unregisterTimerCallback(action1);
+    timer.unregisterTimerCallback(action2);
+    timer.unregisterTimerCallback(action3);
+
+    size_t action1Count = 0;
+    size_t action2Count = 0;
+    size_t action3Count = 0;
+    for (size_t token : getCalledCallbacks()) {
+        if (token == 1) {
+            action1Count++;
+        }
+        if (token == 2) {
+            action2Count++;
+        }
+        if (token == 3) {
+            action3Count++;
+        }
+    }
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    ASSERT_GE(action1Count, static_cast<size_t>(9));
+    // Theoretically trigger 20 times, but check for at least 15 times to be stable.
+    ASSERT_GE(action2Count, static_cast<size_t>(15));
+    // Theoretically trigger 33 times, but check for at least 25 times to be stable.
+    ASSERT_GE(action3Count, static_cast<size_t>(25));
+}
+
+TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
+    RecurrentTimer timer;
+    // 0.02s
+    int64_t interval1 = 20000000;
+    // 0.01s
+    int64_t interval2 = 10000000;
+
+    auto action = getCallback(0);
+    for (int i = 0; i < 10; i++) {
+        timer.registerTimerCallback(interval1, action);
+        timer.registerTimerCallback(interval2, action);
+    }
+
+    clearCalledCallbacks();
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+
+    timer.unregisterTimerCallback(action);
+
+    // Make sure there is no item in the callback queue.
+    ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
new file mode 100644
index 0000000..f81b1a2
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SubscriptionManager.h"
+
+#include <VehicleHalTypes.h>
+
+#include <aidl/android/hardware/automotive/vehicle/BnVehicleCallback.h>
+#include <android-base/thread_annotations.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <float.h>
+#include <chrono>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::BnVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
+using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
+using ::ndk::ScopedAStatus;
+using ::ndk::SpAIBinder;
+using ::testing::ElementsAre;
+using ::testing::WhenSorted;
+
+class PropertyCallback final : public BnVehicleCallback {
+  public:
+    ScopedAStatus onGetValues(const GetValueResults&) override { return ScopedAStatus::ok(); }
+
+    ScopedAStatus onSetValues(const SetValueResults&) override { return ScopedAStatus::ok(); }
+
+    ScopedAStatus onPropertyEvent(const VehiclePropValues& values, int32_t) override {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        for (const auto& value : values.payloads) {
+            mEvents.push_back(value);
+        }
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus onPropertySetError(const VehiclePropErrors&) override {
+        return ScopedAStatus::ok();
+    }
+
+    // Test functions.
+    std::list<VehiclePropValue> getEvents() {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        return mEvents;
+    }
+
+    void clearEvents() {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mEvents.clear();
+    }
+
+  private:
+    std::mutex mLock;
+    std::list<VehiclePropValue> mEvents GUARDED_BY(mLock);
+};
+
+class SubscriptionManagerTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        mManager = std::make_unique<SubscriptionManager>(
+                [](const std::shared_ptr<IVehicleCallback>& callback,
+                   const VehiclePropValue& value) {
+                    callback->onPropertyEvent(
+                            VehiclePropValues{
+                                    .payloads = {value},
+                            },
+                            0);
+                });
+        mCallback = ::ndk::SharedRefBase::make<PropertyCallback>();
+        // Keep the local binder alive.
+        mBinder = mCallback->asBinder();
+        mCallbackClient = IVehicleCallback::fromBinder(mBinder);
+    }
+
+    SubscriptionManager* getManager() { return mManager.get(); }
+
+    std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
+
+    PropertyCallback* getCallback() { return mCallback.get(); }
+
+    std::list<VehiclePropValue> getEvents() { return getCallback()->getEvents(); }
+
+    void clearEvents() { return getCallback()->clearEvents(); }
+
+  private:
+    std::unique_ptr<SubscriptionManager> mManager;
+    std::shared_ptr<PropertyCallback> mCallback;
+    std::shared_ptr<IVehicleCallback> mCallbackClient;
+    SpAIBinder mBinder;
+};
+
+TEST_F(SubscriptionManagerTest, testSubscribeGlobalContinuous) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+    }};
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    ASSERT_GE(getEvents().size(), static_cast<size_t>(9));
+    EXPECT_EQ(getEvents().back().prop, 0);
+    EXPECT_EQ(getEvents().back().areaId, 0);
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeMultiplePropsGlobalContinuous) {
+    std::vector<SubscribeOptions> options = {{
+                                                     .propId = 0,
+                                                     .areaIds = {0},
+                                                     .sampleRate = 10.0,
+                                             },
+                                             {
+                                                     .propId = 1,
+                                                     .areaIds = {0},
+                                                     .sampleRate = 20.0,
+                                             }};
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    size_t event0Count = 0;
+    size_t event1Count = 0;
+
+    for (const auto& event : getEvents()) {
+        if (event.prop == 0) {
+            event0Count++;
+        } else {
+            event1Count++;
+        }
+    }
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    EXPECT_GE(event0Count, static_cast<size_t>(9));
+    // Theoretically trigger 20 times, but check for at least 15 times to be stable.
+    EXPECT_GE(event1Count, static_cast<size_t>(15));
+}
+
+TEST_F(SubscriptionManagerTest, testOverrideSubscriptionContinuous) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 20.0,
+    }};
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    // Override sample rate to be 10.0.
+    options[0].sampleRate = 10.0;
+    result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    EXPECT_GE(getEvents().size(), static_cast<size_t>(9));
+    EXPECT_LE(getEvents().size(), static_cast<size_t>(15));
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeMultipleAreasContinuous) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = 0,
+                    .areaIds = {0, 1},
+                    .sampleRate = 10.0,
+            },
+    };
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    size_t area0Count = 0;
+    size_t area1Count = 0;
+
+    for (const auto& event : getEvents()) {
+        if (event.areaId == 0) {
+            area0Count++;
+        } else {
+            area1Count++;
+        }
+    }
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    EXPECT_GE(area0Count, static_cast<size_t>(9));
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    EXPECT_GE(area1Count, static_cast<size_t>(9));
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeGlobalContinuous) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+    }};
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get());
+    ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+    clearEvents();
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    ASSERT_TRUE(getEvents().empty());
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeMultipleAreas) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = 0,
+                    .areaIds = {0, 1, 2, 3, 4},
+                    .sampleRate = 10.0,
+            },
+            {
+                    .propId = 1,
+                    .areaIds = {0},
+                    .sampleRate = 10.0,
+            },
+    };
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+                                       std::vector<int32_t>({0}));
+    ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+    clearEvents();
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+    EXPECT_GE(getEvents().size(), static_cast<size_t>(9));
+
+    for (const auto& event : getEvents()) {
+        EXPECT_EQ(event.prop, 1);
+    }
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeByCallback) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = 0,
+                    .areaIds = {0, 1, 2, 3, 4},
+                    .sampleRate = 10.0,
+            },
+            {
+                    .propId = 1,
+                    .areaIds = {0},
+                    .sampleRate = 10.0,
+            },
+    };
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get());
+    ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+    clearEvents();
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    EXPECT_TRUE(getEvents().empty());
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeFailure) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = 0,
+                    .areaIds = {0, 1, 2, 3, 4},
+            },
+            {
+                    .propId = 1,
+                    .areaIds = {0},
+            },
+    };
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, false);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    // Property ID: 2 was not subscribed.
+    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+                                       std::vector<int32_t>({0, 1, 2}));
+    ASSERT_FALSE(result.ok()) << "unsubscribe an unsubscribed property must fail";
+
+    // Since property 0 and property 1 was not unsubscribed successfully, we should be able to
+    // unsubscribe them again.
+    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+                                       std::vector<int32_t>({0, 1}));
+    ASSERT_TRUE(result.ok()) << "a failed unsubscription must not unsubscribe any properties"
+                             << result.error().message();
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeOnchange) {
+    std::vector<SubscribeOptions> options1 = {
+            {
+                    .propId = 0,
+                    .areaIds = {0, 1},
+            },
+            {
+                    .propId = 1,
+                    .areaIds = {0},
+            },
+    };
+    std::vector<SubscribeOptions> options2 = {
+            {
+                    .propId = 0,
+                    .areaIds = {0},
+            },
+    };
+
+    SpAIBinder binder1 = ::ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+    SpAIBinder binder2 = ::ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+    auto result = getManager()->subscribe(client1, options1, false);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+    result = getManager()->subscribe(client2, options2, false);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    std::vector<VehiclePropValue> updatedValues = {
+            {
+                    .prop = 0,
+                    .areaId = 0,
+            },
+            {
+                    .prop = 0,
+                    .areaId = 1,
+            },
+            {
+                    .prop = 1,
+                    .areaId = 0,
+            },
+            {
+                    .prop = 1,
+                    .areaId = 1,
+            },
+    };
+    auto clients = getManager()->getSubscribedClients(updatedValues);
+
+    ASSERT_THAT(clients[client1],
+                WhenSorted(ElementsAre(&updatedValues[0], &updatedValues[1], &updatedValues[2])));
+    ASSERT_THAT(clients[client2], ElementsAre(&updatedValues[0]));
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeInvalidOption) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = 0,
+                    .areaIds = {0, 1, 2, 3, 4},
+                    // invalid sample rate.
+                    .sampleRate = 0.0,
+            },
+            {
+                    .propId = 1,
+                    .areaIds = {0},
+                    .sampleRate = 10.0,
+            },
+    };
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_FALSE(result.ok()) << "subscribe with invalid sample rate must fail";
+    ASSERT_TRUE(getManager()
+                        ->getSubscribedClients({{
+                                                        .prop = 0,
+                                                        .areaId = 0,
+                                                },
+                                                {
+                                                        .prop = 1,
+                                                        .areaId = 0,
+                                                }})
+                        .empty())
+            << "no property should be subscribed if error is returned";
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeNoAreaIds) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = 0,
+                    .areaIds = {},
+                    .sampleRate = 1.0,
+            },
+            {
+                    .propId = 1,
+                    .areaIds = {0},
+                    .sampleRate = 10.0,
+            },
+    };
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_FALSE(result.ok()) << "subscribe with invalid sample rate must fail";
+    ASSERT_TRUE(getManager()
+                        ->getSubscribedClients({{
+                                .prop = 1,
+                                .areaId = 0,
+                        }})
+                        .empty())
+            << "no property should be subscribed if error is returned";
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeOnchange) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = 0,
+                    .areaIds = {0, 1},
+            },
+            {
+                    .propId = 1,
+                    .areaIds = {0},
+            },
+    };
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, false);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+                                       std::vector<int32_t>({0}));
+    ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+    std::vector<VehiclePropValue> updatedValues = {
+            {
+                    .prop = 0,
+                    .areaId = 0,
+            },
+            {
+                    .prop = 1,
+                    .areaId = 0,
+            },
+    };
+    auto clients = getManager()->getSubscribedClients(updatedValues);
+
+    ASSERT_THAT(clients[getCallbackClient()], ElementsAre(&updatedValues[1]));
+}
+
+TEST_F(SubscriptionManagerTest, testCheckSampleRateValid) {
+    ASSERT_TRUE(SubscriptionManager::checkSampleRate(1.0));
+}
+
+TEST_F(SubscriptionManagerTest, testCheckSampleRateInvalidTooSmall) {
+    ASSERT_FALSE(SubscriptionManager::checkSampleRate(FLT_MIN));
+}
+
+TEST_F(SubscriptionManagerTest, testCheckSampleRateInvalidZero) {
+    ASSERT_FALSE(SubscriptionManager::checkSampleRate(0));
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
index 4c8865a..19267cd 100644
--- a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
+++ b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
@@ -1,4 +1,4 @@
-service vendor.vehicle-hal-default /vendor/bin/hw/android.hardware.automotive.vehicle-aidl-default-service
+service vendor.vehicle-hal-default /vendor/bin/hw/android.hardware.automotive.vehicle@V1-default-service
     class early_hal
     user vehicle_network
     group system inet
diff --git a/automotive/vehicle/proto/Android.bp b/automotive/vehicle/proto/Android.bp
new file mode 100644
index 0000000..683f128
--- /dev/null
+++ b/automotive/vehicle/proto/Android.bp
@@ -0,0 +1,87 @@
+// Copyright (C) 2017 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.
+
+// Vehicle HAL Protobuf library
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "android.hardware.automotive.vehicle@2.0-libproto-native",
+    visibility: [
+        "//hardware/interfaces/automotive/vehicle:__subpackages__",
+        "//device/generic/car/emulator:__subpackages__",
+    ],
+    vendor: true,
+    host_supported: true,
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+    strip: {
+        keep_symbols: true,
+    },
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    srcs: ["VehicleHalProto.proto"],
+}
+
+filegroup {
+    name: "vhal-proto-src",
+    visibility: [
+        "//device/google/trout/hal/vehicle/2.0:__subpackages__",
+    ],
+    srcs: [
+        "VehicleHalProto.proto",
+    ],
+}
+
+genrule {
+    name: "DefaultVehicleHalProtoStub_h",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "VehicleHalProto.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.h",
+        "VehicleHalProto.grpc.pb.h",
+    ],
+}
+
+genrule {
+    name: "DefaultVehicleHalProtoStub_cc",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "VehicleHalProto.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.cc",
+        "VehicleHalProto.grpc.pb.cc",
+    ],
+}
diff --git a/automotive/vehicle/proto/VehicleHalProto.proto b/automotive/vehicle/proto/VehicleHalProto.proto
new file mode 100644
index 0000000..0dafe8c
--- /dev/null
+++ b/automotive/vehicle/proto/VehicleHalProto.proto
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package vhal_proto;
+
+// CMD messages are from workstation --> VHAL
+// RESP messages are from VHAL --> workstation
+enum MsgType {
+    GET_CONFIG_CMD = 0;
+    GET_CONFIG_RESP = 1;
+    GET_CONFIG_ALL_CMD = 2;
+    GET_CONFIG_ALL_RESP = 3;
+    GET_PROPERTY_CMD = 4;
+    GET_PROPERTY_RESP = 5;
+    GET_PROPERTY_ALL_CMD = 6;
+    GET_PROPERTY_ALL_RESP = 7;
+    SET_PROPERTY_CMD = 8;
+    SET_PROPERTY_RESP = 9;
+    SET_PROPERTY_ASYNC = 10;
+    DEBUG_CMD = 11;
+    DEBUG_RESP = 12;
+}
+enum Status {
+    RESULT_OK = 0;
+    ERROR_UNKNOWN = 1;
+    ERROR_UNIMPLEMENTED_CMD = 2;
+    ERROR_INVALID_PROPERTY = 3;
+    ERROR_INVALID_AREA_ID = 4;
+    ERROR_PROPERTY_UNINITIALIZED = 5;
+    ERROR_WRITE_ONLY_PROPERTY = 6;
+    ERROR_MEMORY_ALLOC_FAILED = 7;
+    ERROR_INVALID_OPERATION = 8;
+}
+
+enum VehiclePropStatus {
+    AVAILABLE = 0;
+    UNAVAILABLE = 1;
+    ERROR = 2;
+}
+
+message VehicleAreaConfig {
+    required int32 area_id = 1;
+    optional sint32 min_int32_value = 2;
+    optional sint32 max_int32_value = 3;
+    optional sint64 min_int64_value = 4;
+    optional sint64 max_int64_value = 5;
+    optional float min_float_value = 6;
+    optional float max_float_value = 7;
+}
+
+message VehiclePropConfig {
+    required int32 prop = 1;
+    optional int32 access = 2;
+    optional int32 change_mode = 3;
+    optional int32 value_type = 4;
+    optional int32 supported_areas = 5;  // Deprecated - DO NOT USE
+    repeated VehicleAreaConfig area_configs = 6;
+    optional int32 config_flags = 7;
+    repeated int32 config_array = 8;
+    optional string config_string = 9;
+    optional float min_sample_rate = 10;
+    optional float max_sample_rate = 11;
+};
+
+message VehiclePropValue {
+    // common data
+    required int32 prop = 1;
+    optional int32 value_type = 2;
+    optional int64 timestamp = 3;            // required for valid data from HAL, skipped for set
+    optional VehiclePropStatus status = 10;  // required for valid data from HAL, skipped for set
+
+    // values
+    optional int32 area_id = 4;
+    repeated sint32 int32_values = 5;  // this also covers boolean value.
+    repeated sint64 int64_values = 6;
+    repeated float float_values = 7;
+    optional string string_value = 8;
+    optional bytes bytes_value = 9;
+};
+
+// This structure is used to notify what values to get from the Vehicle HAL
+message VehiclePropGet {
+    required int32 prop = 1;
+    optional int32 area_id = 2;
+};
+
+message EmulatorMessage {
+    required MsgType msg_type = 1;
+    optional Status status = 2;        // Only for RESP messages
+    repeated VehiclePropGet prop = 3;  // Provided for getConfig, getProperty commands
+    repeated VehiclePropConfig config = 4;
+    repeated VehiclePropValue value = 5;
+    repeated string debug_commands = 6;  // Required for debug command
+    optional string debug_result = 7;    // Required for debug RESP messages
+};
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
new file mode 100644
index 0000000..3a6461e
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.common;
+@VintfStability
+parcelable OperationContext {
+  int id = 0;
+  android.hardware.biometrics.common.OperationReason reason = android.hardware.biometrics.common.OperationReason.UNKNOWN;
+  boolean isAoD = false;
+  boolean isCrypto = false;
+}
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
new file mode 100644
index 0000000..3da3a6a
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.common;
+@Backing(type="byte") @VintfStability
+enum OperationReason {
+  UNKNOWN = 0,
+  BIOMETRIC_PROMPT = 1,
+  KEYGUARD = 2,
+}
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
new file mode 100644
index 0000000..390e698
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.common;
+
+import android.hardware.biometrics.common.OperationReason;
+
+/**
+ * Additional context associated with an operation.
+ */
+@VintfStability
+parcelable OperationContext {
+    /**
+     * An identifier for the logical action that the user is engaged in. These identifiers are
+     * not guaranteed to be unique. However, the framework will not reuse identifiers within
+     * short periods of time so they can be made unique, if needed, by appending a timestamp.
+     *
+     * Zero if the reason is OperationReason.UNKNOWN.
+     */
+    int id = 0;
+
+    /**
+     * A logical reason for this operation.
+     *
+     * This should be interpreted as a hint to enable optimizations or tracing. The
+     * framework may choose to use OperationReason.UNKNOWN at any time based on the device's
+     * policy.
+     */
+    OperationReason reason = OperationReason.UNKNOWN;
+
+    /* Flag indicating that the display is in AoD mode. */
+    boolean isAoD = false;
+
+    /** Flag indicating that crypto was requested. */
+    boolean isCrypto = false;
+}
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
new file mode 100644
index 0000000..abc25ed
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.common;
+
+@VintfStability
+@Backing(type="byte")
+enum OperationReason {
+    /**
+     * A normal operation without an explicit reason.
+     */
+    UNKNOWN,
+
+    /**
+     * An operation associated with biometric prompt. This may be due to either application or
+     * system use, but it is not related to KEYGUARD device entry.
+     */
+    BIOMETRIC_PROMPT,
+
+    /**
+     * An operation associated with device entry.
+     */
+    KEYGUARD,
+}
diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
index 3f53fc8..fff2c1d 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -16,7 +16,7 @@
     imports: [
         "android.hardware.biometrics.common",
         "android.hardware.common-V2",
-        "android.hardware.keymaster",
+        "android.hardware.keymaster-V3",
     ],
     stability: "vintf",
     backend: {
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
index 7817864..4b51bb1 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
@@ -48,4 +48,7 @@
   void invalidateAuthenticatorId();
   void resetLockout(in android.hardware.keymaster.HardwareAuthToken hat);
   void close();
+  android.hardware.biometrics.common.ICancellationSignal authenticateWithContext(in long operationId, in android.hardware.biometrics.common.OperationContext context);
+  android.hardware.biometrics.common.ICancellationSignal enrollWithContext(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in @nullable android.hardware.common.NativeHandle previewSurface, in android.hardware.biometrics.common.OperationContext context);
+  android.hardware.biometrics.common.ICancellationSignal detectInteractionWithContext(in android.hardware.biometrics.common.OperationContext context);
 }
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index 5f06b40..bbe3632 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -17,6 +17,7 @@
 package android.hardware.biometrics.face;
 
 import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.common.OperationContext;
 import android.hardware.biometrics.face.EnrollmentStageConfig;
 import android.hardware.biometrics.face.EnrollmentType;
 import android.hardware.biometrics.face.Feature;
@@ -441,4 +442,23 @@
      *   - ISessionCallback#onSessionClosed
      */
     void close();
+
+    /**
+     * These are alternative methods for some operations to allow the HAL to make optional
+     * optimizations during execution.
+     *
+     * HALs may ignore the additional context and treat all *WithContext methods the same as
+     * the original methods.
+     */
+
+    /* See ISession#authenticateWithContext(long) */
+    ICancellationSignal authenticateWithContext(in long operationId, in OperationContext context);
+
+    /* See ISession#enroll(HardwareAuthToken, EnrollmentType, Feature[], NativeHandle) */
+    ICancellationSignal enrollWithContext(in HardwareAuthToken hat, in EnrollmentType type,
+            in Feature[] features, in @nullable NativeHandle previewSurface,
+            in OperationContext context);
+
+    /* See ISession#detectInteraction() */
+    ICancellationSignal detectInteractionWithContext(in OperationContext context);
 }
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 5092318..7f66eca 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -16,8 +16,8 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.face-V1-ndk",
-        "android.hardware.biometrics.common-V1-ndk",
+        "android.hardware.biometrics.face-V2-ndk",
+        "android.hardware.biometrics.common-V2-ndk",
     ],
     srcs: [
         "main.cpp",
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index 01cb620..9e753e5 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -151,4 +151,25 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Session::authenticateWithContext(
+        int64_t operationId, const common::OperationContext& /*context*/,
+        std::shared_ptr<common::ICancellationSignal>* out) {
+    return authenticate(operationId, out);
+}
+
+ndk::ScopedAStatus Session::enrollWithContext(const keymaster::HardwareAuthToken& hat,
+                                              EnrollmentType enrollmentType,
+                                              const std::vector<Feature>& features,
+                                              const std::optional<NativeHandle>& previewSurface,
+                                              const common::OperationContext& /*context*/,
+                                              std::shared_ptr<common::ICancellationSignal>* out) {
+    return enroll(hat, enrollmentType, features, previewSurface, out);
+}
+
+ndk::ScopedAStatus Session::detectInteractionWithContext(
+        const common::OperationContext& /*context*/,
+        std::shared_ptr<common::ICancellationSignal>* out) {
+    return detectInteraction(out);
+}
+
 }  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
index 4152909..0ce9e20 100644
--- a/biometrics/face/aidl/default/Session.h
+++ b/biometrics/face/aidl/default/Session.h
@@ -68,6 +68,20 @@
 
     ndk::ScopedAStatus close() override;
 
+    ndk::ScopedAStatus authenticateWithContext(
+            int64_t operationId, const common::OperationContext& context,
+            std::shared_ptr<common::ICancellationSignal>* out) override;
+
+    ndk::ScopedAStatus enrollWithContext(
+            const keymaster::HardwareAuthToken& hat, EnrollmentType enrollmentType,
+            const std::vector<Feature>& features, const std::optional<NativeHandle>& previewSurface,
+            const common::OperationContext& context,
+            std::shared_ptr<common::ICancellationSignal>* out) override;
+
+    ndk::ScopedAStatus detectInteractionWithContext(
+            const common::OperationContext& context,
+            std::shared_ptr<common::ICancellationSignal>* out) override;
+
   private:
     std::shared_ptr<ISessionCallback> cb_;
     std::mt19937 mRandom;
diff --git a/biometrics/face/aidl/default/face-default.xml b/biometrics/face/aidl/default/face-default.xml
index 6915ad0..e6ef842 100644
--- a/biometrics/face/aidl/default/face-default.xml
+++ b/biometrics/face/aidl/default/face-default.xml
@@ -1,6 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.biometrics.face</name>
+        <version>2</version>
         <fqname>IFace/default</fqname>
     </hal>
 </manifest>
diff --git a/biometrics/face/aidl/default/main.cpp b/biometrics/face/aidl/default/main.cpp
index 80b153e..b7274e3 100644
--- a/biometrics/face/aidl/default/main.cpp
+++ b/biometrics/face/aidl/default/main.cpp
@@ -29,7 +29,7 @@
 
     const std::string instance = std::string(Face::descriptor) + "/default";
     binder_status_t status = AServiceManager_addService(hal->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/biometrics/face/aidl/vts/Android.bp b/biometrics/face/aidl/vts/Android.bp
index 09ec4d0..4171ac3 100644
--- a/biometrics/face/aidl/vts/Android.bp
+++ b/biometrics/face/aidl/vts/Android.bp
@@ -15,8 +15,8 @@
     ],
     srcs: ["VtsHalBiometricsFaceTargetTest.cpp"],
     static_libs: [
-        "android.hardware.biometrics.common-V1-ndk",
-        "android.hardware.biometrics.face-V1-ndk",
+        "android.hardware.biometrics.common-V2-ndk",
+        "android.hardware.biometrics.face-V2-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.keymaster-V3-ndk",
     ],
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index c46150e..c3a056c 100644
--- a/biometrics/fingerprint/aidl/Android.bp
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -15,7 +15,7 @@
     ],
     imports: [
         "android.hardware.biometrics.common",
-        "android.hardware.keymaster",
+        "android.hardware.keymaster-V3",
     ],
     stability: "vintf",
     backend: {
@@ -26,8 +26,5 @@
             enabled: false,
         },
     },
-    versions: [
-        "1",
-        "2",
-    ],
+    versions: ["1"],
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/.hash b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/.hash
deleted file mode 100644
index 411cb75..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/.hash
+++ /dev/null
@@ -1 +0,0 @@
-762eb38ce93ea3c7d39a680949cbdbd2371b3f06
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
deleted file mode 100644
index c51aa03..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-@Backing(type="byte") @VintfStability
-enum AcquiredInfo {
-  UNKNOWN = 0,
-  GOOD = 1,
-  PARTIAL = 2,
-  INSUFFICIENT = 3,
-  SENSOR_DIRTY = 4,
-  TOO_SLOW = 5,
-  TOO_FAST = 6,
-  VENDOR = 7,
-  START = 8,
-  TOO_DARK = 9,
-  TOO_BRIGHT = 10,
-  IMMOBILE = 11,
-  RETRYING_CAPTURE = 12,
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/Error.aidl
deleted file mode 100644
index af7bc3c..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/Error.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-@Backing(type="byte") @VintfStability
-enum Error {
-  UNKNOWN = 0,
-  HW_UNAVAILABLE = 1,
-  UNABLE_TO_PROCESS = 2,
-  TIMEOUT = 3,
-  NO_SPACE = 4,
-  CANCELED = 5,
-  UNABLE_TO_REMOVE = 6,
-  VENDOR = 7,
-  BAD_CALIBRATION = 8,
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
deleted file mode 100644
index 9c208c4..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-@Backing(type="byte") @VintfStability
-enum FingerprintSensorType {
-  UNKNOWN = 0,
-  REAR = 1,
-  UNDER_DISPLAY_ULTRASONIC = 2,
-  UNDER_DISPLAY_OPTICAL = 3,
-  POWER_BUTTON = 4,
-  HOME_BUTTON = 5,
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/IFingerprint.aidl
deleted file mode 100644
index 5d3df6f..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-@VintfStability
-interface IFingerprint {
-  android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps();
-  android.hardware.biometrics.fingerprint.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.ISessionCallback cb);
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/ISession.aidl
deleted file mode 100644
index 9934a76..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/ISession.aidl
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-@VintfStability
-interface ISession {
-  void generateChallenge();
-  void revokeChallenge(in long challenge);
-  android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat);
-  android.hardware.biometrics.common.ICancellationSignal authenticate(in long operationId);
-  android.hardware.biometrics.common.ICancellationSignal detectInteraction();
-  void enumerateEnrollments();
-  void removeEnrollments(in int[] enrollmentIds);
-  void getAuthenticatorId();
-  void invalidateAuthenticatorId();
-  void resetLockout(in android.hardware.keymaster.HardwareAuthToken hat);
-  void close();
-  void onPointerDown(in int pointerId, in int x, in int y, in float minor, in float major);
-  void onPointerUp(in int pointerId);
-  void onUiReady();
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
deleted file mode 100644
index 3c40ad6..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-@VintfStability
-interface ISessionCallback {
-  void onChallengeGenerated(in long challenge);
-  void onChallengeRevoked(in long challenge);
-  void onAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfo info, in int vendorCode);
-  void onError(in android.hardware.biometrics.fingerprint.Error error, in int vendorCode);
-  void onEnrollmentProgress(in int enrollmentId, int remaining);
-  void onAuthenticationSucceeded(in int enrollmentId, in android.hardware.keymaster.HardwareAuthToken hat);
-  void onAuthenticationFailed();
-  void onLockoutTimed(in long durationMillis);
-  void onLockoutPermanent();
-  void onLockoutCleared();
-  void onInteractionDetected();
-  void onEnrollmentsEnumerated(in int[] enrollmentIds);
-  void onEnrollmentsRemoved(in int[] enrollmentIds);
-  void onAuthenticatorIdRetrieved(in long authenticatorId);
-  void onAuthenticatorIdInvalidated(in long newAuthenticatorId);
-  void onSessionClosed();
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/SensorLocation.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/SensorLocation.aidl
deleted file mode 100644
index 295fde9..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/SensorLocation.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.biometrics.fingerprint;
-@VintfStability
-parcelable SensorLocation {
-  int displayId;
-  int sensorLocationX;
-  int sensorLocationY;
-  int sensorRadius;
-  String display = "";
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/SensorProps.aidl
deleted file mode 100644
index 782d289..0000000
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/2/android/hardware/biometrics/fingerprint/SensorProps.aidl
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.biometrics.fingerprint;
-@VintfStability
-parcelable SensorProps {
-  android.hardware.biometrics.common.CommonProps commonProps;
-  android.hardware.biometrics.fingerprint.FingerprintSensorType sensorType = android.hardware.biometrics.fingerprint.FingerprintSensorType.UNKNOWN;
-  android.hardware.biometrics.fingerprint.SensorLocation[] sensorLocations;
-  boolean supportsNavigationGestures;
-  boolean supportsDetectInteraction;
-  boolean halHandlesDisplayTouches;
-  boolean halControlsIllumination;
-}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
index 9934a76..4e7b3b4 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -48,4 +48,9 @@
   void onPointerDown(in int pointerId, in int x, in int y, in float minor, in float major);
   void onPointerUp(in int pointerId);
   void onUiReady();
+  android.hardware.biometrics.common.ICancellationSignal authenticateWithContext(in long operationId, in android.hardware.biometrics.common.OperationContext context);
+  android.hardware.biometrics.common.ICancellationSignal enrollWithContext(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.common.OperationContext context);
+  android.hardware.biometrics.common.ICancellationSignal detectInteractionWithContext(in android.hardware.biometrics.common.OperationContext context);
+  void onPointerDownWithContext(in android.hardware.biometrics.fingerprint.PointerContext context);
+  void onPointerUpWithContext(in android.hardware.biometrics.fingerprint.PointerContext context);
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
new file mode 100644
index 0000000..e383330
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+parcelable PointerContext {
+  int pointerId = 0;
+  int x = 0;
+  int y = 0;
+  float minor = 0.000000f;
+  float major = 0.000000f;
+  boolean isAoD = false;
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index f1d96d3..ea8c6aa 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -17,6 +17,8 @@
 package android.hardware.biometrics.fingerprint;
 
 import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.fingerprint.PointerContext;
 import android.hardware.keymaster.HardwareAuthToken;
 
 /**
@@ -140,7 +142,7 @@
      *
      * @param hat See above documentation.
      * @return ICancellationSignal An object that can be used by the framework to cancel this
-     * operation.
+     *                             operation.
      */
     ICancellationSignal enroll(in HardwareAuthToken hat);
 
@@ -234,7 +236,7 @@
      *   - ISessionCallback#onAcquired
      *
      * @return ICancellationSignal An object that can be used by the framework to cancel this
-     * operation.
+     *                             operation.
      */
     ICancellationSignal detectInteraction();
 
@@ -448,4 +450,27 @@
      * HAL, the framework will invoke this operation to notify when the illumination is showing.
      */
     void onUiReady();
+
+    /**
+     * These are alternative methods for some operations to allow the HAL to make optional
+     * optimizations during execution.
+     *
+     * HALs may ignore the additional context and treat all *WithContext methods the same as
+     * the original methods.
+     */
+
+    /** See ISession#authenticate(long) */
+    ICancellationSignal authenticateWithContext(in long operationId, in OperationContext context);
+
+    /** See ISession#enroll(HardwareAuthToken) */
+    ICancellationSignal enrollWithContext(in HardwareAuthToken hat, in OperationContext context);
+
+    /** See ISession#detectInteraction() */
+    ICancellationSignal detectInteractionWithContext(in OperationContext context);
+
+    /** See ISession#onPointerDown(int, int, int, float, float) */
+    void onPointerDownWithContext(in PointerContext context);
+
+    /** See ISession#onPointerUp(int) */
+    void onPointerUpWithContext(in PointerContext context);
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
new file mode 100644
index 0000000..4975175
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+/**
+ * Additional context associated with a pointer event.
+ */
+@VintfStability
+parcelable PointerContext {
+    /* See android.view.MotionEvent#getPointerId. */
+    int pointerId = 0;
+
+    /* The distance in pixels from the left edge of the display. */
+    int x = 0;
+
+    /* The distance in pixels from the top edge of the display. */
+    int y = 0;
+
+    /* See android.view.MotionEvent#getTouchMinor. */
+    float minor = 0f;
+
+    /* See android.view.MotionEvent#getTouchMajor. */
+    float major = 0f;
+
+    /* Flag indicating that the display is in AoD mode. */
+    boolean isAoD = false;
+}
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index d4194a3..430bf3c 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -25,7 +25,7 @@
         "libbase",
         "libbinder_ndk",
         "android.hardware.biometrics.fingerprint-V2-ndk",
-        "android.hardware.biometrics.common-V1-ndk",
+        "android.hardware.biometrics.common-V2-ndk",
     ],
 }
 
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index ca481e7..8cbcfc7 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -244,4 +244,30 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Session::authenticateWithContext(
+        int64_t operationId, const common::OperationContext& /*context*/,
+        std::shared_ptr<common::ICancellationSignal>* out) {
+    return authenticate(operationId, out);
+}
+
+ndk::ScopedAStatus Session::enrollWithContext(const keymaster::HardwareAuthToken& hat,
+                                              const common::OperationContext& /*context*/,
+                                              std::shared_ptr<common::ICancellationSignal>* out) {
+    return enroll(hat, out);
+}
+
+ndk::ScopedAStatus Session::detectInteractionWithContext(
+        const common::OperationContext& /*context*/,
+        std::shared_ptr<common::ICancellationSignal>* out) {
+    return detectInteraction(out);
+}
+
+ndk::ScopedAStatus Session::onPointerDownWithContext(const PointerContext& context) {
+    return onPointerDown(context.pointerId, context.x, context.y, context.minor, context.major);
+}
+
+ndk::ScopedAStatus Session::onPointerUpWithContext(const PointerContext& context) {
+    return onPointerUp(context.pointerId);
+}
+
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h
index 9e46422..584cb27 100644
--- a/biometrics/fingerprint/aidl/default/include/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -79,6 +79,22 @@
 
     ndk::ScopedAStatus onUiReady() override;
 
+    ndk::ScopedAStatus authenticateWithContext(
+            int64_t operationId, const common::OperationContext& context,
+            std::shared_ptr<common::ICancellationSignal>* out) override;
+
+    ndk::ScopedAStatus enrollWithContext(
+            const keymaster::HardwareAuthToken& hat, const common::OperationContext& context,
+            std::shared_ptr<common::ICancellationSignal>* out) override;
+
+    ndk::ScopedAStatus detectInteractionWithContext(
+            const common::OperationContext& context,
+            std::shared_ptr<common::ICancellationSignal>* out) override;
+
+    ndk::ScopedAStatus onPointerDownWithContext(const PointerContext& context) override;
+
+    ndk::ScopedAStatus onPointerUpWithContext(const PointerContext& context) override;
+
     bool isClosed();
 
   private:
diff --git a/biometrics/fingerprint/aidl/default/main.cpp b/biometrics/fingerprint/aidl/default/main.cpp
index 4690d73..c985201 100644
--- a/biometrics/fingerprint/aidl/default/main.cpp
+++ b/biometrics/fingerprint/aidl/default/main.cpp
@@ -29,7 +29,7 @@
 
     const std::string instance = std::string(Fingerprint::descriptor) + "/default";
     binder_status_t status = AServiceManager_addService(hal->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/bluetooth/audio/2.1/Android.bp b/bluetooth/audio/2.1/Android.bp
index 822f5b3..1175fb3 100644
--- a/bluetooth/audio/2.1/Android.bp
+++ b/bluetooth/audio/2.1/Android.bp
@@ -25,7 +25,7 @@
     ],
     apex_available: [
         "//apex_available:platform",
-        "com.android.bluetooth.updatable",
+        "com.android.bluetooth",
     ],
     gen_java: false,
 }
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
index b0d171a..6e8c1d7 100644
--- a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
@@ -41,12 +41,8 @@
     BluetoothAudioProvidersFactory::hearing_aid_provider_instance_;
 LeAudioOutputAudioProvider
     BluetoothAudioProvidersFactory::leaudio_output_provider_instance_;
-LeAudioOffloadOutputAudioProvider
-    BluetoothAudioProvidersFactory::leaudio_offload_output_provider_instance_;
 LeAudioInputAudioProvider
     BluetoothAudioProvidersFactory::leaudio_input_provider_instance_;
-LeAudioOffloadInputAudioProvider
-    BluetoothAudioProvidersFactory::leaudio_offload_input_provider_instance_;
 
 Return<void> BluetoothAudioProvidersFactory::openProvider(
     const V2_0::SessionType sessionType, openProvider_cb _hidl_cb) {
@@ -94,15 +90,9 @@
     case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
       provider = &leaudio_output_provider_instance_;
       break;
-    case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
-      provider = &leaudio_offload_output_provider_instance_;
-      break;
     case SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
       provider = &leaudio_input_provider_instance_;
       break;
-    case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
-      provider = &leaudio_offload_input_provider_instance_;
-      break;
     default:
       status = BluetoothAudioStatus::FAILURE;
   }
@@ -157,7 +147,11 @@
         audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
       }
     }
-  } else if (sessionType != SessionType::UNKNOWN) {
+  } else if (sessionType !=
+                 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+             sessionType !=
+                 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH &&
+             sessionType != SessionType::UNKNOWN) {
     std::vector<PcmParameters> db_pcm_capabilities =
         android::bluetooth::audio::GetSoftwarePcmCapabilities_2_1();
     if (db_pcm_capabilities.size() == 1) {
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
index f8f557e..714d738 100644
--- a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
@@ -56,8 +56,6 @@
   static HearingAidAudioProvider hearing_aid_provider_instance_;
   static LeAudioOutputAudioProvider leaudio_output_provider_instance_;
   static LeAudioInputAudioProvider leaudio_input_provider_instance_;
-  static LeAudioOffloadOutputAudioProvider leaudio_offload_output_provider_instance_;
-  static LeAudioOffloadInputAudioProvider leaudio_offload_input_provider_instance_;
 };
 
 extern "C" IBluetoothAudioProvidersFactory*
diff --git a/bluetooth/audio/2.2/Android.bp b/bluetooth/audio/2.2/Android.bp
index 6449c08..d66e84e 100644
--- a/bluetooth/audio/2.2/Android.bp
+++ b/bluetooth/audio/2.2/Android.bp
@@ -14,6 +14,7 @@
     root: "android.hardware",
     srcs: [
         "types.hal",
+        "IBluetoothAudioPort.hal",
         "IBluetoothAudioProvider.hal",
         "IBluetoothAudioProvidersFactory.hal",
     ],
@@ -26,7 +27,7 @@
     ],
     apex_available: [
         "//apex_available:platform",
-        "com.android.bluetooth.updatable",
+        "com.android.bluetooth",
     ],
     gen_java: false,
 }
diff --git a/bluetooth/audio/2.2/IBluetoothAudioPort.hal b/bluetooth/audio/2.2/IBluetoothAudioPort.hal
new file mode 100644
index 0000000..344899c
--- /dev/null
+++ b/bluetooth/audio/2.2/IBluetoothAudioPort.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio@2.2;
+
+import @2.0::IBluetoothAudioPort;
+import android.hardware.audio.common@5.0::SinkMetadata;
+
+interface IBluetoothAudioPort extends @2.0::IBluetoothAudioPort  {
+    /**
+     * Called when the metadata of the stream's sink has been changed.
+     *
+     * @param sinkMetadata Description of the audio that is recorded by the
+     *    clients.
+     */
+    updateSinkMetadata(SinkMetadata sinkMetadata);
+};
diff --git a/bluetooth/audio/2.2/IBluetoothAudioProvider.hal b/bluetooth/audio/2.2/IBluetoothAudioProvider.hal
index ad8c839..f577537 100644
--- a/bluetooth/audio/2.2/IBluetoothAudioProvider.hal
+++ b/bluetooth/audio/2.2/IBluetoothAudioProvider.hal
@@ -17,7 +17,7 @@
 package android.hardware.bluetooth.audio@2.2;
 
 import @2.1::IBluetoothAudioProvider;
-import @2.0::IBluetoothAudioPort;
+import @2.2::IBluetoothAudioPort;
 import @2.0::Status;
 
 /**
@@ -59,4 +59,14 @@
      */
     startSession_2_2(IBluetoothAudioPort hostIf, AudioConfiguration audioConfig)
                 generates (Status status, fmq_sync<uint8_t> dataMQ);
+
+    /**
+     * Called when the audio configuration of the stream has been changed.
+     *
+     * @param audioConfig The audio configuration negotiated with the remote
+     *    device. The PCM parameters are set if software based encoding,
+     *    otherwise the correct codec configuration is used for hardware
+     *    encoding.
+     */
+    updateAudioConfiguration(AudioConfiguration audioConfig);
 };
diff --git a/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal b/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal
index 7fb5b6c..ae9c598 100644
--- a/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal
+++ b/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal
@@ -48,4 +48,26 @@
      */
     openProvider_2_2(SessionType sessionType)
         generates (Status status, IBluetoothAudioProvider provider);
+
+    /**
+     * Gets a list of audio capabilities for a session type.
+     *
+     * For software encoding, the PCM capabilities are returned.
+     * For hardware encoding, the supported codecs and their capabilities are
+     * returned.
+     *
+     * @param sessionType The session type (e.g.
+     *    A2DP_SOFTWARE_ENCODING_DATAPATH).
+     * @return audioCapabilities A list containing all the capabilities
+     *    supported by the sesson type. The capabilities is a list of
+     *    available options when configuring the codec for the session.
+     *    For software encoding it is the PCM data rate.
+     *    For hardware encoding it is the list of supported codecs and their
+     *    capabilities.
+     *    If a provider isn't supported, an empty list should be returned.
+     *    Note: Only one entry should exist per codec when using hardware
+     *    encoding.
+     */
+     getProviderCapabilities_2_2(SessionType sessionType)
+         generates (vec<AudioCapabilities> audioCapabilities);
 };
diff --git a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp
index 126bc9e..2a6d93a 100644
--- a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp
+++ b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp
@@ -54,7 +54,7 @@
 }
 
 Return<void> A2dpOffloadAudioProvider::startSession(
-    const sp<IBluetoothAudioPort>& hostIf,
+    const sp<V2_0::IBluetoothAudioPort>& hostIf,
     const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   /**
    * Initialize the audio platform if audioConfiguration is supported.
diff --git a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp
index 0d918e1..eb87178 100644
--- a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp
@@ -21,7 +21,7 @@
 #include <android-base/logging.h>
 
 #include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_2.h"
 
 namespace android {
 namespace hardware {
@@ -70,7 +70,7 @@
 }
 
 Return<void> A2dpSoftwareAudioProvider::startSession(
-    const sp<IBluetoothAudioPort>& hostIf,
+    const sp<V2_0::IBluetoothAudioPort>& hostIf,
     const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   /**
    * Initialize the audio platform if audioConfiguration is supported.
diff --git a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h
index 3d4f0cc..ac3aece 100644
--- a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h
+++ b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h
@@ -40,7 +40,7 @@
   bool isValid(const V2_1::SessionType& sessionType) override;
   bool isValid(const V2_0::SessionType& sessionType) override;
 
-  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
                             const V2_0::AudioConfiguration& audioConfig,
                             startSession_cb _hidl_cb) override;
 
diff --git a/bluetooth/audio/2.2/default/AudioPort_2_0_to_2_2_Wrapper.h b/bluetooth/audio/2.2/default/AudioPort_2_0_to_2_2_Wrapper.h
new file mode 100644
index 0000000..c5613fb
--- /dev/null
+++ b/bluetooth/audio/2.2/default/AudioPort_2_0_to_2_2_Wrapper.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.2/types.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V5_0::SinkMetadata;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
+using ::android::hardware::bluetooth::audio::V2_2::IBluetoothAudioPort;
+
+class AudioPort_2_0_to_2_2_Wrapper : public V2_2::IBluetoothAudioPort {
+ public:
+  AudioPort_2_0_to_2_2_Wrapper(const sp<V2_0::IBluetoothAudioPort>& port) {
+    this->port = port;
+  }
+
+  Return<void> startStream() override { return port->startStream(); }
+  Return<void> suspendStream() override { return port->suspendStream(); }
+  Return<void> stopStream() override { return port->stopStream(); }
+  Return<void> getPresentationPosition(
+      getPresentationPosition_cb _hidl_cb) override {
+    return port->getPresentationPosition(_hidl_cb);
+  }
+  Return<void> updateMetadata(const SourceMetadata& sourceMetadata) override {
+    return port->updateMetadata(sourceMetadata);
+  }
+  Return<void> updateSinkMetadata(const SinkMetadata&) override {
+    // DO NOTHING, 2.0 AudioPort doesn't support sink metadata updates
+    return Void();
+  }
+
+  sp<V2_0::IBluetoothAudioPort> port;
+};
+
+}  // namespace implementation
+}  // namespace V2_2
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp
index 3655bc0..202cfb9 100644
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp
@@ -20,8 +20,9 @@
 
 #include <android-base/logging.h>
 
+#include "AudioPort_2_0_to_2_2_Wrapper.h"
 #include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_2.h"
 
 namespace android {
 namespace hardware {
@@ -51,7 +52,7 @@
       audio_config_({}) {}
 
 Return<void> BluetoothAudioProvider::startSession(
-    const sp<IBluetoothAudioPort>& hostIf,
+    const sp<V2_0::IBluetoothAudioPort>& hostIf,
     const V2_0::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   AudioConfiguration audioConfig_2_2;
 
@@ -67,11 +68,13 @@
     audioConfig_2_2.codecConfig(audioConfig.codecConfig());
   }
 
-  return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
+      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
+  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
 }
 
 Return<void> BluetoothAudioProvider::startSession_2_1(
-    const sp<IBluetoothAudioPort>& hostIf,
+    const sp<V2_0::IBluetoothAudioPort>& hostIf,
     const V2_1::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   AudioConfiguration audioConfig_2_2;
   if (audioConfig.getDiscriminator() ==
@@ -92,11 +95,13 @@
     audioConfig_2_2.codecConfig(audioConfig.codecConfig());
   }
 
-  return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
+      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
+  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
 }
 
 Return<void> BluetoothAudioProvider::startSession_2_2(
-    const sp<IBluetoothAudioPort>& hostIf,
+    const sp<V2_2::IBluetoothAudioPort>& hostIf,
     const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   if (hostIf == nullptr) {
     _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
@@ -181,6 +186,29 @@
   return Void();
 }
 
+Return<void> BluetoothAudioProvider::updateAudioConfiguration(
+    const AudioConfiguration& audioConfig) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+  if (stack_iface_ == nullptr) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO session";
+    return Void();
+  }
+
+  if (audioConfig.getDiscriminator() != audio_config_.getDiscriminator()) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " audio config type is not match";
+    return Void();
+  }
+
+  audio_config_ = audioConfig;
+  BluetoothAudioSessionReport_2_2::ReportAudioConfigChanged(session_type_,
+                                                            audio_config_);
+
+  return Void();
+}
+
 }  // namespace implementation
 }  // namespace V2_2
 }  // namespace audio
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvider.h b/bluetooth/audio/2.2/default/BluetoothAudioProvider.h
index b7581ba..425ea3b 100644
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvider.h
@@ -26,7 +26,7 @@
 namespace implementation {
 
 using ::android::sp;
-using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+using ::android::hardware::bluetooth::audio::V2_2::IBluetoothAudioPort;
 
 using BluetoothAudioStatus =
     ::android::hardware::bluetooth::audio::V2_0::Status;
@@ -41,25 +41,27 @@
   virtual bool isValid(const V2_1::SessionType& sessionType) = 0;
   virtual bool isValid(const V2_0::SessionType& sessionType) = 0;
 
-  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
                             const V2_0::AudioConfiguration& audioConfig,
                             startSession_cb _hidl_cb) override;
-  Return<void> startSession_2_1(const sp<IBluetoothAudioPort>& hostIf,
+  Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
                                 const V2_1::AudioConfiguration& audioConfig,
                                 startSession_cb _hidl_cb) override;
-  Return<void> startSession_2_2(const sp<IBluetoothAudioPort>& hostIf,
+  Return<void> startSession_2_2(const sp<V2_2::IBluetoothAudioPort>& hostIf,
                                 const AudioConfiguration& audioConfig,
                                 startSession_cb _hidl_cb) override;
   Return<void> streamStarted(BluetoothAudioStatus status) override;
   Return<void> streamSuspended(BluetoothAudioStatus status) override;
   Return<void> endSession() override;
+  Return<void> updateAudioConfiguration(
+      const AudioConfiguration& audioConfig) override;
 
  protected:
   sp<BluetoothAudioDeathRecipient> death_recipient_;
 
   V2_1::SessionType session_type_;
   AudioConfiguration audio_config_;
-  sp<V2_0::IBluetoothAudioPort> stack_iface_;
+  sp<V2_2::IBluetoothAudioPort> stack_iface_;
 
   virtual Return<void> onSessionReady(startSession_cb _hidl_cb) = 0;
 };
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
index 510833d..490a436 100644
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
@@ -20,7 +20,7 @@
 
 #include <android-base/logging.h>
 
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_2.h"
 
 namespace android {
 namespace hardware {
@@ -98,15 +98,9 @@
     case V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
       provider = &leaudio_output_provider_instance_;
       break;
-    case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
-      provider = &leaudio_offload_output_provider_instance_;
-      break;
     case V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
       provider = &leaudio_input_provider_instance_;
       break;
-    case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
-      provider = &leaudio_offload_input_provider_instance_;
-      break;
     default:
       status = BluetoothAudioStatus::FAILURE;
   }
@@ -221,6 +215,47 @@
   return Void();
 }
 
+Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities_2_2(
+    const V2_1::SessionType sessionType,
+    getProviderCapabilities_2_2_cb _hidl_cb) {
+  hidl_vec<V2_2::AudioCapabilities> audio_capabilities =
+      hidl_vec<V2_2::AudioCapabilities>(0);
+  if (sessionType == V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    std::vector<CodecCapabilities> db_codec_capabilities =
+        android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
+    if (db_codec_capabilities.size()) {
+      audio_capabilities.resize(db_codec_capabilities.size());
+      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+        audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
+      }
+    }
+  } else if (sessionType == V2_1::SessionType::
+                                LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+             sessionType == V2_1::SessionType::
+                                LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    std::vector<LeAudioCodecCapabilitiesSetting> db_codec_capabilities =
+        android::bluetooth::audio::GetLeAudioOffloadCodecCapabilities(
+            sessionType);
+    if (db_codec_capabilities.size()) {
+      audio_capabilities.resize(db_codec_capabilities.size());
+      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+        audio_capabilities[i].leAudioCapabilities(db_codec_capabilities[i]);
+      }
+    }
+  } else if (sessionType != V2_1::SessionType::UNKNOWN) {
+    std::vector<V2_1::PcmParameters> db_pcm_capabilities =
+        android::bluetooth::audio::GetSoftwarePcmCapabilities_2_1();
+    if (db_pcm_capabilities.size() == 1) {
+      audio_capabilities.resize(1);
+      audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
+    }
+  }
+  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
+            << " supports " << audio_capabilities.size() << " codecs";
+  _hidl_cb(audio_capabilities);
+  return Void();
+}
+
 IBluetoothAudioProvidersFactory* HIDL_FETCH_IBluetoothAudioProvidersFactory(
     const char* /* name */) {
   return new BluetoothAudioProvidersFactory();
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h
index 658249b..4f549d9 100644
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h
@@ -53,6 +53,10 @@
       const V2_1::SessionType sessionType,
       getProviderCapabilities_2_1_cb _hidl_cb) override;
 
+  Return<void> getProviderCapabilities_2_2(
+      const V2_1::SessionType sessionType,
+      getProviderCapabilities_2_2_cb _hidl_cb) override;
+
  private:
   static A2dpSoftwareAudioProvider a2dp_software_provider_instance_;
   static A2dpOffloadAudioProvider a2dp_offload_provider_instance_;
diff --git a/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp b/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp
index c79b910..25e49a1 100644
--- a/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp
+++ b/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp
@@ -21,7 +21,7 @@
 #include <android-base/logging.h>
 
 #include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_2.h"
 
 namespace android {
 namespace hardware {
@@ -66,7 +66,7 @@
 }
 
 Return<void> HearingAidAudioProvider::startSession(
-    const sp<IBluetoothAudioPort>& hostIf,
+    const sp<V2_0::IBluetoothAudioPort>& hostIf,
     const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   /**
    * Initialize the audio platform if audioConfiguration is supported.
diff --git a/bluetooth/audio/2.2/default/HearingAidAudioProvider.h b/bluetooth/audio/2.2/default/HearingAidAudioProvider.h
index 426c443..63290b5 100644
--- a/bluetooth/audio/2.2/default/HearingAidAudioProvider.h
+++ b/bluetooth/audio/2.2/default/HearingAidAudioProvider.h
@@ -40,7 +40,7 @@
   bool isValid(const V2_1::SessionType& sessionType) override;
   bool isValid(const V2_0::SessionType& sessionType) override;
 
-  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
                             const V2_0::AudioConfiguration& audioConfig,
                             startSession_cb _hidl_cb) override;
 
diff --git a/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp b/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp
index af6ec99..a7a0023 100644
--- a/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp
+++ b/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp
@@ -20,8 +20,9 @@
 
 #include <android-base/logging.h>
 
+#include "AudioPort_2_0_to_2_2_Wrapper.h"
 #include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_2.h"
 
 namespace android {
 namespace hardware {
@@ -83,11 +84,13 @@
        .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
        .dataIntervalUs = 0});
 
-  return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
+      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
+  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
 }
 
 Return<void> LeAudioAudioProvider::startSession_2_2(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
+    const sp<V2_2::IBluetoothAudioPort>& hostIf,
     const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   /**
    * Initialize the audio platform if audioConfiguration is supported.
diff --git a/bluetooth/audio/2.2/default/LeAudioAudioProvider.h b/bluetooth/audio/2.2/default/LeAudioAudioProvider.h
index 40c26e0..3de1724 100644
--- a/bluetooth/audio/2.2/default/LeAudioAudioProvider.h
+++ b/bluetooth/audio/2.2/default/LeAudioAudioProvider.h
@@ -45,7 +45,7 @@
                                 const V2_1::AudioConfiguration& audioConfig,
                                 startSession_cb _hidl_cb) override;
 
-  Return<void> startSession_2_2(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+  Return<void> startSession_2_2(const sp<V2_2::IBluetoothAudioPort>& hostIf,
                                 const AudioConfiguration& audioConfig,
                                 startSession_cb _hidl_cb) override;
 
diff --git a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp
index 7b70654..2b0c02f 100644
--- a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp
@@ -20,8 +20,8 @@
 
 #include <android-base/logging.h>
 
+#include "AudioPort_2_0_to_2_2_Wrapper.h"
 #include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
 #include "BluetoothAudioSupportedCodecsDB_2_2.h"
 
 namespace android {
@@ -91,11 +91,13 @@
       .peerDelay = 0,
       .lc3Config = audioConfig.leAudioCodecConfig().lc3Config};
 
-  return startSession_2_2(hostIf, audioConfig_2_2, _hidl_cb);
+  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
+      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
+  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
 }
 
 Return<void> LeAudioOffloadAudioProvider::startSession_2_2(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
+    const sp<V2_2::IBluetoothAudioPort>& hostIf,
     const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
   /**
    * Initialize the audio platform if audioConfiguration is supported.
diff --git a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h
index 5620295..fe58de5 100644
--- a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h
@@ -38,7 +38,7 @@
                                 const V2_1::AudioConfiguration& audioConfig,
                                 startSession_cb _hidl_cb) override;
 
-  Return<void> startSession_2_2(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+  Return<void> startSession_2_2(const sp<V2_2::IBluetoothAudioPort>& hostIf,
                                 const AudioConfiguration& audioConfig,
                                 startSession_cb _hidl_cb) override;
 
diff --git a/bluetooth/audio/2.2/default/OWNERS b/bluetooth/audio/2.2/default/OWNERS
new file mode 100644
index 0000000..17ea464
--- /dev/null
+++ b/bluetooth/audio/2.2/default/OWNERS
@@ -0,0 +1,4 @@
+include platform/packages/modules/Bluetooth:/OWNERS
+
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/2.2/types.hal b/bluetooth/audio/2.2/types.hal
index d5f8a3f..6755899 100644
--- a/bluetooth/audio/2.2/types.hal
+++ b/bluetooth/audio/2.2/types.hal
@@ -19,6 +19,8 @@
 import @2.1::Lc3Parameters;
 import @2.1::PcmParameters;
 import @2.0::CodecConfiguration;
+import @2.0::CodecCapabilities;
+import @2.1::CodecType;
 
 enum LeAudioMode : uint8_t {
     UNKNOWN = 0x00,
@@ -26,6 +28,12 @@
     BROADCAST = 0x02,
 };
 
+enum AudioLocation : uint8_t {
+  UNKNOWN = 0,
+  FRONT_LEFT = 1,
+  FRONT_RIGHT = 2,
+};
+
 struct UnicastStreamMap {
     /* The connection handle used for a unicast or a broadcast group. */
     uint16_t streamHandle;
@@ -70,3 +78,50 @@
     CodecConfiguration codecConfig;
     LeAudioConfiguration leAudioConfig;
 };
+
+/** Used to specify the capabilities of the different session types */
+safe_union AudioCapabilities {
+    PcmParameters pcmCapabilities;
+    CodecCapabilities codecCapabilities;
+    LeAudioCodecCapabilitiesSetting leAudioCapabilities;
+};
+
+/**
+ * Used to specify the le audio capabilities for unicast and broadcast hardware offload.
+ */
+struct LeAudioCodecCapabilitiesSetting{
+    UnicastCapability unicastEncodeCapability;
+    UnicastCapability unicastDecodeCapability;
+    BroadcastCapability broadcastCapability;
+};
+
+/**
+ * Used to specify the le audio unicast codec capabilities for hardware offload.
+ */
+struct UnicastCapability {
+    CodecType codecType;
+    AudioLocation supportedChannel;
+
+    // The number of connected device
+    uint8_t deviceCount;
+
+    // Supported channel count for each device
+    uint8_t channelCountPerDevice;
+
+    // Should use safe union when there is more than one codec
+    Lc3Parameters capabilities;
+};
+
+/**
+ * Used to specify the le audio broadcast codec capabilities for hardware offload.
+ */
+struct BroadcastCapability {
+    CodecType codecType;
+    AudioLocation supportedChannel;
+
+    // Supported channel count for each stream
+    uint8_t channelCountPerStream;
+
+    // Should use safe union when there is more than one codec
+    vec<Lc3Parameters> capabilities;
+};
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
new file mode 100644
index 0000000..5107240
--- /dev/null
+++ b/bluetooth/audio/aidl/Android.bp
@@ -0,0 +1,52 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.bluetooth.audio",
+    vendor_available: true,
+    srcs: ["android/hardware/bluetooth/audio/*.aidl"],
+    stability: "vintf",
+    imports: [
+        "android.hardware.common-V2",
+        "android.hardware.common.fmq-V1",
+        "android.hardware.audio.common",
+    ],
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+            enabled: false,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.bluetooth",
+            ],
+        },
+    },
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacCapabilities.aidl
new file mode 100644
index 0000000..899b8ca
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacCapabilities.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AacCapabilities {
+  android.hardware.bluetooth.audio.AacObjectType[] objectType;
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  boolean variableBitRateSupported;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacConfiguration.aidl
new file mode 100644
index 0000000..6adef6d
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacConfiguration.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AacConfiguration {
+  android.hardware.bluetooth.audio.AacObjectType objectType;
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  boolean variableBitRateEnabled;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
new file mode 100644
index 0000000..2148244
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum AacObjectType {
+  MPEG2_LC = 0,
+  MPEG4_LC = 1,
+  MPEG4_LTP = 2,
+  MPEG4_SCALABLE = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxCapabilities.aidl
new file mode 100644
index 0000000..08a38e2
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AptxCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxConfiguration.aidl
new file mode 100644
index 0000000..91e88b3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxConfiguration.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AptxConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioCapabilities.aidl
new file mode 100644
index 0000000..8ae716f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union AudioCapabilities {
+  android.hardware.bluetooth.audio.PcmCapabilities pcmCapabilities;
+  android.hardware.bluetooth.audio.CodecCapabilities a2dpCapabilities;
+  android.hardware.bluetooth.audio.LeAudioCodecCapabilitiesSetting leAudioCapabilities;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
new file mode 100644
index 0000000..50b54c3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union AudioConfiguration {
+  android.hardware.bluetooth.audio.PcmConfiguration pcmConfig;
+  android.hardware.bluetooth.audio.CodecConfiguration a2dpConfig;
+  android.hardware.bluetooth.audio.LeAudioConfiguration leAudioConfig;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
new file mode 100644
index 0000000..319a5e2
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AudioLocation {
+  UNKNOWN = 1,
+  FRONT_LEFT = 2,
+  FRONT_RIGHT = 4,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
new file mode 100644
index 0000000..7c0d825
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum BluetoothAudioStatus {
+  UNKNOWN = 0,
+  SUCCESS = 1,
+  UNSUPPORTED_CODEC_CONFIGURATION = 2,
+  FAILURE = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
new file mode 100644
index 0000000..58710ef
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 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.bluetooth.audio;
+@VintfStability
+parcelable BroadcastCapability {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.AudioLocation supportedChannel;
+  int channelCountPerStream;
+  android.hardware.bluetooth.audio.BroadcastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union LeAudioCodecCapabilities {
+    @nullable android.hardware.bluetooth.audio.Lc3Capabilities[] lc3Capabilities;
+    @nullable android.hardware.bluetooth.audio.BroadcastCapability.VendorCapabilities[] vendorCapabillities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastConfiguration.aidl
new file mode 100644
index 0000000..5fa3926
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/BroadcastConfiguration.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable BroadcastConfiguration {
+  android.hardware.bluetooth.audio.BroadcastConfiguration.BroadcastStreamMap[] streamMap;
+  @VintfStability
+  parcelable BroadcastStreamMap {
+    char streamHandle;
+    int audioChannelAllocation;
+    android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
new file mode 100644
index 0000000..c3bc741
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum ChannelMode {
+  UNKNOWN = 0,
+  MONO = 1,
+  STEREO = 2,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
new file mode 100644
index 0000000..948c04a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable CodecCapabilities {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.CodecCapabilities.Capabilities capabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union Capabilities {
+    android.hardware.bluetooth.audio.SbcCapabilities sbcCapabilities;
+    android.hardware.bluetooth.audio.AacCapabilities aacCapabilities;
+    android.hardware.bluetooth.audio.LdacCapabilities ldacCapabilities;
+    android.hardware.bluetooth.audio.AptxCapabilities aptxCapabilities;
+    android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
+    android.hardware.bluetooth.audio.CodecCapabilities.VendorCapabilities vendorCapabilities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
new file mode 100644
index 0000000..32bccd8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable CodecConfiguration {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  int encodedAudioBitrate;
+  int peerMtu;
+  boolean isScmstEnabled;
+  android.hardware.bluetooth.audio.CodecConfiguration.CodecSpecific config;
+  @VintfStability
+  parcelable VendorConfiguration {
+    int vendorId;
+    char codecId;
+    ParcelableHolder codecConfig;
+  }
+  @VintfStability
+  union CodecSpecific {
+    android.hardware.bluetooth.audio.SbcConfiguration sbcConfig;
+    android.hardware.bluetooth.audio.AacConfiguration aacConfig;
+    android.hardware.bluetooth.audio.LdacConfiguration ldacConfig;
+    android.hardware.bluetooth.audio.AptxConfiguration aptxConfig;
+    android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
+    android.hardware.bluetooth.audio.CodecConfiguration.VendorConfiguration vendorConfig;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
new file mode 100644
index 0000000..3a5f951
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum CodecType {
+  UNKNOWN = 0,
+  SBC = 1,
+  AAC = 2,
+  APTX = 3,
+  APTX_HD = 4,
+  LDAC = 5,
+  LC3 = 6,
+  VENDOR = 7,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
new file mode 100644
index 0000000..9a1557a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioPort {
+  android.hardware.bluetooth.audio.PresentationPosition getPresentationPosition();
+  void startStream();
+  void stopStream();
+  void suspendStream();
+  void updateSourceMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
+  void updateSinkMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
new file mode 100644
index 0000000..0dcba2e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioProvider {
+  void endSession();
+  android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> startSession(in android.hardware.bluetooth.audio.IBluetoothAudioPort hostIf, in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
+  void streamStarted(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
+  void streamSuspended(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
+  void updateAudioConfiguration(in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
new file mode 100644
index 0000000..5e33deb
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioProviderFactory {
+  android.hardware.bluetooth.audio.AudioCapabilities[] getProviderCapabilities(in android.hardware.bluetooth.audio.SessionType sessionType);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider openProvider(in android.hardware.bluetooth.audio.SessionType sessionType);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Lc3Capabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
new file mode 100644
index 0000000..cc4449a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable Lc3Capabilities {
+  byte[] pcmBitDepth;
+  int[] samplingFrequencyHz;
+  int[] frameDurationUs;
+  int[] octetsPerFrame;
+  byte[] blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Lc3Configuration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Lc3Configuration.aidl
new file mode 100644
index 0000000..7e8dccf
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Lc3Configuration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable Lc3Configuration {
+  byte pcmBitDepth;
+  int samplingFrequencyHz;
+  int frameDurationUs;
+  int octetsPerFrame;
+  byte blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacCapabilities.aidl
new file mode 100644
index 0000000..aa4e4c8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LdacCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.LdacChannelMode[] channelMode;
+  android.hardware.bluetooth.audio.LdacQualityIndex[] qualityIndex;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
new file mode 100644
index 0000000..88d6faf
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum LdacChannelMode {
+  UNKNOWN = 0,
+  STEREO = 1,
+  DUAL = 2,
+  MONO = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacConfiguration.aidl
new file mode 100644
index 0000000..8a37638
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LdacConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.LdacChannelMode channelMode;
+  android.hardware.bluetooth.audio.LdacQualityIndex qualityIndex;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
new file mode 100644
index 0000000..35e4358
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum LdacQualityIndex {
+  HIGH = 0,
+  MID = 1,
+  LOW = 2,
+  ABR = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
new file mode 100644
index 0000000..9818d54
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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.bluetooth.audio;
+@VintfStability
+parcelable LeAudioCodecCapabilitiesSetting {
+  android.hardware.bluetooth.audio.UnicastCapability unicastEncodeCapability;
+  android.hardware.bluetooth.audio.UnicastCapability unicastDecodeCapability;
+  android.hardware.bluetooth.audio.BroadcastCapability broadcastCapability;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
new file mode 100644
index 0000000..bb3d7e4
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union LeAudioCodecConfiguration {
+  android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
+  android.hardware.bluetooth.audio.LeAudioCodecConfiguration.VendorConfiguration vendorConfig;
+  @VintfStability
+  parcelable VendorConfiguration {
+    ParcelableHolder extension;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
new file mode 100644
index 0000000..2bc1791
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LeAudioConfiguration {
+  android.hardware.bluetooth.audio.LeAudioMode mode;
+  android.hardware.bluetooth.audio.LeAudioConfiguration.LeAudioModeConfig modeConfig;
+  android.hardware.bluetooth.audio.CodecType codecType;
+  @VintfStability
+  union LeAudioModeConfig {
+    android.hardware.bluetooth.audio.UnicastConfiguration unicastConfig;
+    android.hardware.bluetooth.audio.BroadcastConfiguration broadcastConfig;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioMode.aidl
new file mode 100644
index 0000000..766f637
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum LeAudioMode {
+  UNKNOWN = 0,
+  UNICAST = 1,
+  BROADCAST = 2,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmCapabilities.aidl
new file mode 100644
index 0000000..0c2f87d
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable PcmCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  byte[] bitsPerSample;
+  int[] dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmConfiguration.aidl
new file mode 100644
index 0000000..93d7805
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable PcmConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  byte bitsPerSample;
+  int dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PresentationPosition.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PresentationPosition.aidl
new file mode 100644
index 0000000..7e997e8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PresentationPosition.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable PresentationPosition {
+  long remoteDeviceAudioDelayNanos;
+  long transmittedOctets;
+  android.hardware.bluetooth.audio.PresentationPosition.TimeSpec transmittedOctetsTimestamp;
+  @VintfStability
+  parcelable TimeSpec {
+    long tvSec;
+    long tvNSec;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
new file mode 100644
index 0000000..091f6d7
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SbcAllocMethod {
+  ALLOC_MD_S = 0,
+  ALLOC_MD_L = 1,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcCapabilities.aidl
new file mode 100644
index 0000000..c8d7e7e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcCapabilities.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable SbcCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.SbcChannelMode[] channelMode;
+  byte[] blockLength;
+  byte[] numSubbands;
+  android.hardware.bluetooth.audio.SbcAllocMethod[] allocMethod;
+  byte[] bitsPerSample;
+  int minBitpool;
+  int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
new file mode 100644
index 0000000..6441a99
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SbcChannelMode {
+  UNKNOWN = 0,
+  JOINT_STEREO = 1,
+  STEREO = 2,
+  DUAL = 3,
+  MONO = 4,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcConfiguration.aidl
new file mode 100644
index 0000000..8eab9c3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcConfiguration.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable SbcConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.SbcChannelMode channelMode;
+  byte blockLength;
+  byte numSubbands;
+  android.hardware.bluetooth.audio.SbcAllocMethod allocMethod;
+  byte bitsPerSample;
+  int minBitpool;
+  int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
new file mode 100644
index 0000000..72d7fb2
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SessionType {
+  UNKNOWN = 0,
+  A2DP_SOFTWARE_ENCODING_DATAPATH = 1,
+  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 2,
+  HEARING_AID_SOFTWARE_ENCODING_DATAPATH = 3,
+  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH = 4,
+  LE_AUDIO_SOFTWARE_DECODING_DATAPATH = 5,
+  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 6,
+  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH = 7,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
new file mode 100644
index 0000000..130fef9
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable UnicastCapability {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.AudioLocation supportedChannel;
+  int deviceCount;
+  int channelCountPerDevice;
+  android.hardware.bluetooth.audio.UnicastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union LeAudioCodecCapabilities {
+    android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
+    android.hardware.bluetooth.audio.UnicastCapability.VendorCapabilities vendorCapabillities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastConfiguration.aidl
new file mode 100644
index 0000000..b385763
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/UnicastConfiguration.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable UnicastConfiguration {
+  android.hardware.bluetooth.audio.UnicastConfiguration.UnicastStreamMap[] streamMap;
+  int peerDelay;
+  android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
+  @VintfStability
+  parcelable UnicastStreamMap {
+    char streamHandle;
+    int audioChannelAllocation;
+  }
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacCapabilities.aidl
new file mode 100644
index 0000000..c4153e9
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacCapabilities.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AacObjectType;
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding AAC codec capabilities
+ */
+@VintfStability
+parcelable AacCapabilities {
+    AacObjectType[] objectType;
+    int[] sampleRateHz;
+    ChannelMode[] channelMode;
+    boolean variableBitRateSupported;
+    byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacConfiguration.aidl
new file mode 100644
index 0000000..30338e7
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacConfiguration.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AacObjectType;
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding AAC codec configuration
+ */
+@VintfStability
+parcelable AacConfiguration {
+    AacObjectType objectType;
+    int sampleRateHz;
+    ChannelMode channelMode;
+    boolean variableBitRateEnabled;
+    byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacObjectType.aidl
new file mode 100644
index 0000000..4e9958c
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum AacObjectType {
+    /**
+     * MPEG-2 Low Complexity. Support is Mandatory.
+     */
+    MPEG2_LC,
+    /**
+     * MPEG-4 Low Complexity. Support is Optional.
+     */
+    MPEG4_LC,
+    /**
+     * MPEG-4 Long Term Prediction. Support is Optional.
+     */
+    MPEG4_LTP,
+    /**
+     * MPEG-4 Scalable. Support is Optional.
+     */
+    MPEG4_SCALABLE,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxCapabilities.aidl
new file mode 100644
index 0000000..f5605d3
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxCapabilities.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding AptX and AptX-HD codec capabilities
+ */
+@VintfStability
+parcelable AptxCapabilities {
+    int[] sampleRateHz;
+    ChannelMode[] channelMode;
+    byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxConfiguration.aidl
new file mode 100644
index 0000000..83b7b0c
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxConfiguration.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding AptX and AptX-HD codec configuration
+ */
+@VintfStability
+parcelable AptxConfiguration {
+    int sampleRateHz;
+    ChannelMode channelMode;
+    byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioCapabilities.aidl
new file mode 100644
index 0000000..a75c445
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioCapabilities.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecCapabilities;
+import android.hardware.bluetooth.audio.LeAudioCodecCapabilitiesSetting;
+import android.hardware.bluetooth.audio.PcmCapabilities;
+
+/**
+ * Used to specify the capabilities of the different session types
+ */
+@VintfStability
+union AudioCapabilities {
+    PcmCapabilities pcmCapabilities;
+    CodecCapabilities a2dpCapabilities;
+    LeAudioCodecCapabilitiesSetting leAudioCapabilities;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
new file mode 100644
index 0000000..81b41dc
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecConfiguration;
+import android.hardware.bluetooth.audio.LeAudioConfiguration;
+import android.hardware.bluetooth.audio.PcmConfiguration;
+
+/**
+ * Used to configure either a Hardware or Software Encoding session based on session type
+ */
+@VintfStability
+union AudioConfiguration {
+    PcmConfiguration pcmConfig;
+    CodecConfiguration a2dpConfig;
+    LeAudioConfiguration leAudioConfig;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioLocation.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioLocation.aidl
new file mode 100644
index 0000000..dedfbf9
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioLocation.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="int")
+enum AudioLocation {
+    UNKNOWN = 1,
+    FRONT_LEFT = 1 << 1,
+    FRONT_RIGHT = 1 << 2,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
new file mode 100644
index 0000000..ec78445
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="int")
+enum BluetoothAudioStatus {
+    UNKNOWN = 0,
+    SUCCESS = 1,
+    UNSUPPORTED_CODEC_CONFIGURATION = 2,
+    // General failure
+    FAILURE = 3
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
new file mode 100644
index 0000000..cb63f88
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioLocation;
+import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.Lc3Capabilities;
+import android.hardware.bluetooth.audio.LeAudioMode;
+
+/**
+ * Used to specify the le audio broadcast codec capabilities for hardware offload.
+ */
+@VintfStability
+parcelable BroadcastCapability {
+    @VintfStability
+    parcelable VendorCapabilities {
+        ParcelableHolder extension;
+    }
+    @VintfStability
+    union LeAudioCodecCapabilities {
+        @nullable Lc3Capabilities[] lc3Capabilities;
+        @nullable VendorCapabilities[] vendorCapabillities;
+    }
+    CodecType codecType;
+    AudioLocation supportedChannel;
+    // Supported channel count for each stream
+    int channelCountPerStream;
+    LeAudioCodecCapabilities leAudioCodecCapabilities;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastConfiguration.aidl
new file mode 100644
index 0000000..cfc9d3a
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/BroadcastConfiguration.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.LeAudioCodecConfiguration;
+
+@VintfStability
+parcelable BroadcastConfiguration {
+    @VintfStability
+    parcelable BroadcastStreamMap {
+        /*
+         * The connection handle used for a unicast or a broadcast group.
+         * Range: 0x0000 to 0xEFFF
+         */
+        char streamHandle;
+        /*
+         * Audio channel allocation is  a bit field, each enabled bit means that given audio
+         * direction, i.e. "left", or "right" is used. Ordering of audio channels comes from the
+         * least significant bit to the most significant bit.
+         */
+        int audioChannelAllocation;
+        LeAudioCodecConfiguration leAudioCodecConfig;
+    }
+    BroadcastStreamMap[] streamMap;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
new file mode 100644
index 0000000..6613872
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum ChannelMode {
+    UNKNOWN,
+    MONO,
+    STEREO,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
new file mode 100644
index 0000000..41e2431
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AacCapabilities;
+import android.hardware.bluetooth.audio.AptxCapabilities;
+import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.Lc3Capabilities;
+import android.hardware.bluetooth.audio.LdacCapabilities;
+import android.hardware.bluetooth.audio.SbcCapabilities;
+
+/**
+ * Used to specify the capabilities of the codecs supported by Hardware Encoding.
+ * AptX and AptX-HD both use the AptxCapabilities field.
+ */
+@VintfStability
+parcelable CodecCapabilities {
+    @VintfStability
+    parcelable VendorCapabilities {
+        ParcelableHolder extension;
+    }
+    @VintfStability
+    union Capabilities {
+        SbcCapabilities sbcCapabilities;
+        AacCapabilities aacCapabilities;
+        LdacCapabilities ldacCapabilities;
+        AptxCapabilities aptxCapabilities;
+        Lc3Capabilities lc3Capabilities;
+        VendorCapabilities vendorCapabilities;
+    }
+    CodecType codecType;
+    Capabilities capabilities;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
new file mode 100644
index 0000000..3679537
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AacConfiguration;
+import android.hardware.bluetooth.audio.AptxConfiguration;
+import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.Lc3Configuration;
+import android.hardware.bluetooth.audio.LdacConfiguration;
+import android.hardware.bluetooth.audio.SbcConfiguration;
+
+/**
+ * Used to configure a Hardware Encoding session.
+ * AptX and AptX-HD both use the AptxConfiguration field.
+ */
+@VintfStability
+parcelable CodecConfiguration {
+    @VintfStability
+    parcelable VendorConfiguration {
+        int vendorId;
+        char codecId;
+        ParcelableHolder codecConfig;
+    }
+    @VintfStability
+    union CodecSpecific {
+        SbcConfiguration sbcConfig;
+        AacConfiguration aacConfig;
+        LdacConfiguration ldacConfig;
+        AptxConfiguration aptxConfig;
+        Lc3Configuration lc3Config;
+        VendorConfiguration vendorConfig;
+    }
+    CodecType codecType;
+    /**
+     * The encoded audio bitrate in bits / second.
+     * 0x00000000 - The audio bitrate is not specified / unused
+     * 0x00000001 - 0x00FFFFFF - Encoded audio bitrate in bits/second
+     * 0x01000000 - 0xFFFFFFFF - Reserved
+     *
+     * The HAL needs to support all legal bitrates for the selected codec.
+     */
+    int encodedAudioBitrate;
+    /**
+     * Peer MTU (in two-octets)
+     */
+    int peerMtu;
+    /**
+     * Content protection by SCMS-T
+     */
+    boolean isScmstEnabled;
+    CodecSpecific config;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
new file mode 100644
index 0000000..9c33081
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="int")
+enum CodecType {
+    UNKNOWN,
+    SBC,
+    AAC,
+    APTX,
+    APTX_HD,
+    LDAC,
+    LC3,
+    VENDOR,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
new file mode 100644
index 0000000..827f57d
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.common.SourceMetadata;
+import android.hardware.bluetooth.audio.PresentationPosition;
+
+/**
+ * HAL interface from the Audio HAL to the Bluetooth stack
+ *
+ * The Audio HAL calls methods in this interface to start, suspend, and stop
+ * an audio stream. These calls return immediately and the results, if any,
+ * are sent over the IBluetoothAudioProvider interface.
+ *
+ * Moreover, the Audio HAL can also get the presentation position of the stream
+ * and provide stream metadata.
+ *
+ */
+@VintfStability
+interface IBluetoothAudioPort {
+    /**
+     * Get the audio presentation position.
+     *
+     * @return the audio presentation position
+     *
+     */
+    PresentationPosition getPresentationPosition();
+
+    /**
+     * This indicates that the caller of this method has opened the data path
+     * and wants to start an audio stream. The caller must wait for a
+     * IBluetoothAudioProvider.streamStarted(Status) call.
+     */
+    void startStream();
+
+    /**
+     * This indicates that the caller of this method wants to stop the audio
+     * stream. The data path will be closed after this call. There is no
+     * callback from the IBluetoothAudioProvider interface even though the
+     * teardown is asynchronous.
+     */
+    void stopStream();
+
+    /**
+     * This indicates that the caller of this method wants to suspend the audio
+     * stream. The caller must wait for the Bluetooth process to call
+     * IBluetoothAudioProvider.streamSuspended(Status). The caller still keeps
+     * the data path open.
+     */
+    void suspendStream();
+
+    /**
+     * Called when the metadata of the stream's source has been changed.
+     *
+     * @param sourceMetadata Description of the audio that is played by the
+     *    clients.
+     */
+    void updateSourceMetadata(in SourceMetadata sourceMetadata);
+
+    /**
+     * Called when the metadata of the stream's sink has been changed.
+     *
+     * @param sinkMetadata as passed from Audio Framework
+     */
+    void updateSinkMetadata(in SinkMetadata sinkMetadata);
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
new file mode 100644
index 0000000..6f88f30
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioConfiguration;
+import android.hardware.bluetooth.audio.BluetoothAudioStatus;
+import android.hardware.bluetooth.audio.IBluetoothAudioPort;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+
+/**
+ * HAL interface from the Bluetooth stack to the Audio HAL
+ *
+ * The Bluetooth stack calls methods in this interface to start and end audio
+ * sessions and sends callback events to the Audio HAL.
+ *
+ */
+@VintfStability
+interface IBluetoothAudioProvider {
+    /**
+     * Ends the current session and unregisters the IBluetoothAudioPort
+     * interface.
+     */
+    void endSession();
+
+    /**
+     * This method indicates that the Bluetooth stack is ready to stream audio.
+     * It registers an instance of IBluetoothAudioPort with and provides the
+     * current negotiated codec to the Audio HAL. After this method is called,
+     * the Audio HAL can invoke IBluetoothAudioPort.startStream().
+     *
+     * Note: endSession() must be called to unregister this IBluetoothAudioPort
+     *
+     * @param hostIf An instance of IBluetoothAudioPort for stream control
+     * @param audioConfig The audio configuration negotiated with the remote
+     *    device. The PCM parameters are set if software based encoding,
+     *    otherwise the correct codec configuration is used for hardware
+     *    encoding.
+     *
+     * @return The fast message queue for audio data from/to this
+     *    provider. Audio data will be in PCM format as specified by the
+     *    audioConfig.pcmConfig parameter. Invalid if streaming is offloaded
+     *    from/to hardware or on failure
+     */
+    MQDescriptor<byte, SynchronizedReadWrite> startSession(
+            in IBluetoothAudioPort hostIf, in AudioConfiguration audioConfig);
+
+    /**
+     * Callback for IBluetoothAudioPort.startStream()
+     *
+     * @param status true for SUCCESS or false for FAILURE
+     */
+    void streamStarted(in BluetoothAudioStatus status);
+
+    /**
+     * Callback for IBluetoothAudioPort.suspendStream()
+     *
+     * @param status true for SUCCESS or false for FAILURE
+     */
+    void streamSuspended(in BluetoothAudioStatus status);
+
+    /**
+     * Called when the audio configuration of the stream has been changed.
+     *
+     * @param audioConfig The audio configuration negotiated with the remote
+     *    device. The PCM parameters are set if software based encoding,
+     *    otherwise the correct codec configuration is used for hardware
+     *    encoding.
+     */
+    void updateAudioConfiguration(in AudioConfiguration audioConfig);
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
new file mode 100644
index 0000000..3cde22c
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioCapabilities;
+import android.hardware.bluetooth.audio.IBluetoothAudioProvider;
+import android.hardware.bluetooth.audio.SessionType;
+/**
+ * This factory allows a HAL implementation to be split into multiple
+ * independent providers.
+ *
+ * When the Bluetooth stack is ready to create an audio session, it must first
+ * obtain the IBluetoothAudioProvider for that session type by calling
+ * openProvider().
+ *
+ */
+
+@VintfStability
+interface IBluetoothAudioProviderFactory {
+    /**
+     * Gets a list of audio capabilities for a session type.
+     *
+     * For software encoding, the PCM capabilities are returned.
+     * For hardware encoding, the supported codecs and their capabilities are
+     * returned.
+     *
+     * @param sessionType The session type (e.g.
+     *    A2DP_SOFTWARE_ENCODING_DATAPATH).
+     * @return A list containing all the capabilities
+     *    supported by the sesson type. The capabilities is a list of
+     *    available options when configuring the codec for the session.
+     *    For software encoding it is the PCM data rate.
+     *    For hardware encoding it is the list of supported codecs and their
+     *    capabilities.
+     *    If a provider isn't supported, an empty list should be returned.
+     *    Note: Only one entry should exist per codec when using hardware
+     *    encoding.
+     */
+    AudioCapabilities[] getProviderCapabilities(in SessionType sessionType);
+
+    /**
+     * Opens an audio provider for a session type. To close the provider, it is
+     * necessary to release references to the returned provider object.
+     *
+     * @param sessionType The session type (e.g.
+     *    LE_AUDIO_SOFTWARE_ENCODING_DATAPATH).
+     *
+     * @return provider The provider of the specified session type
+     */
+    IBluetoothAudioProvider openProvider(in SessionType sessionType);
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Lc3Capabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
new file mode 100644
index 0000000..fc2f382
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding/Decoding LC3 codec capabilities.
+ */
+@VintfStability
+parcelable Lc3Capabilities {
+    /*
+     * PCM is Input for encoder, Output for decoder
+     */
+    byte[] pcmBitDepth;
+    /*
+     * codec-specific parameters
+     */
+    int[] samplingFrequencyHz;
+    /*
+     * FrameDuration based on microseconds.
+     */
+    int[] frameDurationUs;
+    /*
+     * length in octets of a codec frame
+     */
+    int[] octetsPerFrame;
+    /*
+     * Number of blocks of codec frames per single SDU (Service Data Unit)
+     */
+    byte[] blocksPerSdu;
+    /*
+     * Channel mode used in A2DP special audio, ignored in standard LE Audio mode
+     */
+    ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Lc3Configuration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Lc3Configuration.aidl
new file mode 100644
index 0000000..e8a93b2
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Lc3Configuration.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding/Decoding LC3 codec configuration.
+ */
+@VintfStability
+parcelable Lc3Configuration {
+    /*
+     * PCM is Input for encoder, Output for decoder
+     */
+    byte pcmBitDepth;
+    /*
+     * codec-specific parameters
+     */
+    int samplingFrequencyHz;
+    /*
+     * FrameDuration based on microseconds.
+     */
+    int frameDurationUs;
+    /*
+     * length in octets of a codec frame
+     */
+    int octetsPerFrame;
+    /*
+     * Number of blocks of codec frames per single SDU (Service Data Unit)
+     */
+    byte blocksPerSdu;
+    /*
+     * Channel mode used in A2DP special audio, ignored in standard LE Audio mode
+     */
+    ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacCapabilities.aidl
new file mode 100644
index 0000000..1dbec08
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacCapabilities.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.LdacChannelMode;
+import android.hardware.bluetooth.audio.LdacQualityIndex;
+
+/**
+ * Used for Hardware Encoding LDAC codec capabilities
+ * all qualities must be supported.
+ */
+@VintfStability
+parcelable LdacCapabilities {
+    int[] sampleRateHz;
+    LdacChannelMode[] channelMode;
+    LdacQualityIndex[] qualityIndex;
+    byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacChannelMode.aidl
new file mode 100644
index 0000000..3cc910f
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Channel Mode: 3 bits
+ */
+@VintfStability
+@Backing(type="byte")
+enum LdacChannelMode {
+    UNKNOWN,
+    STEREO,
+    DUAL,
+    MONO,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacConfiguration.aidl
new file mode 100644
index 0000000..cc03dd0
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacConfiguration.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.LdacChannelMode;
+import android.hardware.bluetooth.audio.LdacQualityIndex;
+
+/**
+ * Used for Hardware Encoding LDAC codec configuration
+ * Only used when configuring the codec.
+ */
+@VintfStability
+parcelable LdacConfiguration {
+    int sampleRateHz;
+    LdacChannelMode channelMode;
+    LdacQualityIndex qualityIndex;
+    byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
new file mode 100644
index 0000000..9993b8b
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum LdacQualityIndex {
+    /**
+     * 990kbps
+     */
+    HIGH,
+    /**
+     * 660kbps
+     */
+    MID,
+    /**
+     * 330kbps
+     */
+    LOW,
+    /**
+     * Adaptive Bit Rate mode
+     */
+    ABR,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
new file mode 100644
index 0000000..58dac06
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.BroadcastCapability;
+import android.hardware.bluetooth.audio.UnicastCapability;
+
+/**
+ * Used to specify the le audio capabilities for unicast and broadcast hardware offload.
+ */
+@VintfStability
+parcelable LeAudioCodecCapabilitiesSetting {
+    UnicastCapability unicastEncodeCapability;
+    UnicastCapability unicastDecodeCapability;
+    BroadcastCapability broadcastCapability;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
new file mode 100644
index 0000000..421eeb2
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.Lc3Configuration;
+
+@VintfStability
+union LeAudioCodecConfiguration {
+    @VintfStability
+    parcelable VendorConfiguration {
+        ParcelableHolder extension;
+    }
+    Lc3Configuration lc3Config;
+    VendorConfiguration vendorConfig;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
new file mode 100644
index 0000000..515794b
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.BroadcastConfiguration;
+import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.LeAudioMode;
+import android.hardware.bluetooth.audio.UnicastConfiguration;
+
+@VintfStability
+parcelable LeAudioConfiguration {
+    @VintfStability
+    union LeAudioModeConfig {
+        UnicastConfiguration unicastConfig;
+        BroadcastConfiguration broadcastConfig;
+    }
+    /*
+     * The mode of the LE audio
+     */
+    LeAudioMode mode;
+    LeAudioModeConfig modeConfig;
+    CodecType codecType;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioMode.aidl
new file mode 100644
index 0000000..2cf019e
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioMode.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum LeAudioMode {
+    UNKNOWN,
+    UNICAST,
+    BROADCAST,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmCapabilities.aidl
new file mode 100644
index 0000000..776b777
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmCapabilities.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Software Encoding audio feed capabilities
+ */
+@VintfStability
+parcelable PcmCapabilities {
+    int[] sampleRateHz;
+    ChannelMode[] channelMode;
+    byte[] bitsPerSample;
+    /**
+     * Data interval for data transfer
+     */
+    int[] dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmConfiguration.aidl
new file mode 100644
index 0000000..03aa27b
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmConfiguration.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Software Encoding audio feed configuration
+ */
+@VintfStability
+parcelable PcmConfiguration {
+    int sampleRateHz;
+    ChannelMode channelMode;
+    byte bitsPerSample;
+    /**
+     * Data interval for data transfer
+     */
+    int dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PresentationPosition.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PresentationPosition.aidl
new file mode 100644
index 0000000..f3b8aed
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PresentationPosition.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+parcelable PresentationPosition {
+    @VintfStability
+    parcelable TimeSpec {
+        /**
+         * seconds
+         */
+        long tvSec;
+        /**
+         *  nanoseconds
+         */
+        long tvNSec;
+    }
+    /*
+     * remoteDeviceAudioDelayNanos the audio delay from when the remote
+     * device (e.g. headset) receives audio data to when the device plays the
+     * sound. If the delay is unknown, the value is set to zero.
+     */
+    long remoteDeviceAudioDelayNanos;
+    /*
+     * transmittedOctets the number of audio data octets that were sent
+     * to a remote device. This excludes octets that have been written to the
+     * data path but have not been sent to the remote device. The count is
+     * not reset until stopStream() is called. If the software data path is
+     * unused (e.g. Hardware Offload), the value is set to 0.
+     */
+    long transmittedOctets;
+    /*
+     * transmittedOctetsTimestamp the value of CLOCK_MONOTONIC
+     * corresponding to transmittedOctets. If the software data path is
+     * unused (e.g., for Hardware Offload), the value is set to zero.
+     */
+    TimeSpec transmittedOctetsTimestamp;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
new file mode 100644
index 0000000..1159f30
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum SbcAllocMethod {
+    /**
+     * SNR
+     */
+    ALLOC_MD_S,
+    /**
+     * Loudness
+     */
+    ALLOC_MD_L,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcCapabilities.aidl
new file mode 100644
index 0000000..743a1f7
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.SbcAllocMethod;
+import android.hardware.bluetooth.audio.SbcChannelMode;
+
+/**
+ * Used for Hardware Encoding SBC codec capabilities.
+ */
+@VintfStability
+parcelable SbcCapabilities {
+    int[] sampleRateHz;
+    SbcChannelMode[] channelMode;
+    byte[] blockLength;
+    byte[] numSubbands;
+    SbcAllocMethod[] allocMethod;
+    byte[] bitsPerSample;
+    /*
+     * range from 2 to 250.
+     */
+    int minBitpool;
+    /*
+     * range from 2 to 250.
+     */
+    int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcChannelMode.aidl
new file mode 100644
index 0000000..68e3267
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum SbcChannelMode {
+    UNKNOWN,
+    JOINT_STEREO,
+    STEREO,
+    DUAL,
+    MONO,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcConfiguration.aidl
new file mode 100644
index 0000000..054d03e
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.SbcAllocMethod;
+import android.hardware.bluetooth.audio.SbcChannelMode;
+
+/**
+ * Used for Hardware Encoding SBC codec configuration.
+ */
+@VintfStability
+parcelable SbcConfiguration {
+    int sampleRateHz;
+    SbcChannelMode channelMode;
+    byte blockLength;
+    byte numSubbands;
+    SbcAllocMethod allocMethod;
+    byte bitsPerSample;
+    /*
+     * range from 2 to 250.
+     */
+    int minBitpool;
+    /*
+     * range from 2 to 250.
+     */
+    int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
new file mode 100644
index 0000000..30faae3
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum SessionType {
+    UNKNOWN,
+    /**
+     * A2DP legacy that AVDTP media is encoded by Bluetooth Stack
+     */
+    A2DP_SOFTWARE_ENCODING_DATAPATH,
+    /**
+     * The encoding of AVDTP media is done by HW and there is control only
+     */
+    A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+    /**
+     * Used when encoded by Bluetooth Stack and streaming to Hearing Aid
+     */
+    HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+    /**
+     * Used when encoded by Bluetooth Stack and streaming to LE Audio device
+     */
+    LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+    /**
+     * Used when decoded by Bluetooth Stack and streaming to audio framework
+     */
+    LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+    /**
+     * Encoding is done by HW an there is control only
+     */
+    LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+    /**
+     * Decoding is done by HW an there is control only
+     */
+    LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
new file mode 100644
index 0000000..cd8a4c1
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioLocation;
+import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.Lc3Capabilities;
+import android.hardware.bluetooth.audio.LeAudioMode;
+
+/**
+ * Used to specify the le audio unicast codec capabilities for hardware offload.
+ */
+@VintfStability
+parcelable UnicastCapability {
+    @VintfStability
+    parcelable VendorCapabilities {
+        ParcelableHolder extension;
+    }
+    @VintfStability
+    union LeAudioCodecCapabilities {
+        Lc3Capabilities lc3Capabilities;
+        VendorCapabilities vendorCapabillities;
+    }
+    CodecType codecType;
+    AudioLocation supportedChannel;
+    // The number of connected device
+    int deviceCount;
+    // Supported channel count for each device
+    int channelCountPerDevice;
+    LeAudioCodecCapabilities leAudioCodecCapabilities;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastConfiguration.aidl
new file mode 100644
index 0000000..7be2c5b
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/UnicastConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.LeAudioCodecConfiguration;
+
+@VintfStability
+parcelable UnicastConfiguration {
+    @VintfStability
+    parcelable UnicastStreamMap {
+        /*
+         * The connection handle used for a unicast or a broadcast group.
+         * Range: 0x0000 to 0xEFFF
+         */
+        char streamHandle;
+        /*
+         * Audio channel allocation is  a bit field, each enabled bit means that given audio
+         * direction, i.e. "left", or "right" is used. Ordering of audio channels comes from the
+         * least significant bit to the most significant bit. The valus follows the Bluetooth SIG
+         * Audio Location assigned number.
+         */
+        int audioChannelAllocation;
+    }
+    UnicastStreamMap[] streamMap;
+    int peerDelay;
+    LeAudioCodecConfiguration leAudioCodecConfig;
+}
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..fc8a911
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpHW"
+
+#include "A2dpOffloadAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+A2dpOffloadAudioProvider::A2dpOffloadAudioProvider() {
+  session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+bool A2dpOffloadAudioProvider::isValid(const SessionType& session_type) {
+  return (session_type == session_type_);
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+          session_type_, audio_config.get<AudioConfiguration::a2dpConfig>())) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              _aidl_return);
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  *_aidl_return = DataMQDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+                                                nullptr, *audio_config_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
new file mode 100644
index 0000000..5934f5b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+  A2dpOffloadAudioProvider();
+
+  bool isValid(const SessionType& session_type) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..5a413e0
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpSW"
+
+#include "A2dpSoftwareAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+// Here the buffer size is based on SBC
+static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
+// SBC is 128, and here we choose the LCM of 16, 24, and 32
+static constexpr uint32_t kPcmFrameCount = 96;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+// The max counts by 1 tick (20ms) for SBC is about 7. Since using 96 for the
+// PCM counts, here we just choose a greater number
+static constexpr uint32_t kRtpFrameCount = 10;
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 2;  // double buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
+    : BluetoothAudioProvider(), data_mq_(nullptr) {
+  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+            << " byte(s)";
+  std::unique_ptr<DataMQ> data_mq(
+      new DataMQ(kDataMqSize, /* EventFlag */ true));
+  if (data_mq && data_mq->isValid()) {
+    data_mq_ = std::move(data_mq);
+    session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+  } else {
+    ALOGE_IF(!data_mq, "failed to allocate data MQ");
+    ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
+  }
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
+}
+
+ndk::ScopedAStatus A2dpSoftwareAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  const PcmConfiguration& pcm_config =
+      audio_config.get<AudioConfiguration::pcmConfig>();
+  if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << pcm_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              _aidl_return);
+}
+
+ndk::ScopedAStatus A2dpSoftwareAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  if (data_mq_ == nullptr || !data_mq_->isValid()) {
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  *_aidl_return = data_mq_->dupeDesc();
+  auto desc = data_mq_->dupeDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+                                                &desc, *audio_config_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
new file mode 100644
index 0000000..3bc0a13
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+  A2dpSoftwareAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> data_mq_;
+
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp
new file mode 100644
index 0000000..fc882d4
--- /dev/null
+++ b/bluetooth/audio/aidl/default/Android.bp
@@ -0,0 +1,34 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "android.hardware.bluetooth.audio-impl",
+    vendor: true,
+    vintf_fragments: ["bluetooth_audio.xml"],
+    srcs: [
+        "BluetoothAudioProvider.cpp",
+        "BluetoothAudioProviderFactory.cpp",
+        "A2dpOffloadAudioProvider.cpp",
+        "A2dpSoftwareAudioProvider.cpp",
+        "HearingAidAudioProvider.cpp",
+        "LeAudioOffloadAudioProvider.cpp",
+        "LeAudioSoftwareAudioProvider.cpp",
+    ],
+    export_include_dirs: ["."],
+    header_libs: ["libhardware_headers"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "android.hardware.bluetooth.audio-V1-ndk",
+        "libbluetooth_audio_session_aidl",
+    ],
+}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
new file mode 100644
index 0000000..c2ffa2e
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderStub"
+
+#include "BluetoothAudioProvider.h"
+
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+BluetoothAudioProvider::BluetoothAudioProvider() {
+  death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient(
+      AIBinder_DeathRecipient_new(binderDiedCallbackAidl));
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+  if (host_if == nullptr) {
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+  stack_iface_ = host_if;
+
+  AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(),
+                       this);
+
+  onSessionReady(_aidl_return);
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::endSession() {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+  if (stack_iface_ != nullptr) {
+    BluetoothAudioSessionReport::OnSessionEnded(session_type_);
+
+    AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
+                           death_recipient_.get(), this);
+  } else {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO session";
+  }
+
+  stack_iface_ = nullptr;
+  audio_config_ = nullptr;
+
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::streamStarted(
+    BluetoothAudioStatus status) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", status=" << toString(status);
+
+  if (stack_iface_ != nullptr) {
+    BluetoothAudioSessionReport::ReportControlStatus(session_type_, true,
+                                                     status);
+  } else {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", status=" << toString(status) << " has NO session";
+  }
+
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::streamSuspended(
+    BluetoothAudioStatus status) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", status=" << toString(status);
+
+  if (stack_iface_ != nullptr) {
+    BluetoothAudioSessionReport::ReportControlStatus(session_type_, false,
+                                                     status);
+  } else {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", status=" << toString(status) << " has NO session";
+  }
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration(
+    const AudioConfiguration& audio_config) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+  if (stack_iface_ == nullptr || audio_config_ == nullptr) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO session";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  if (audio_config.getTag() != audio_config_->getTag()) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " audio config type is not match";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+  BluetoothAudioSessionReport::ReportAudioConfigChanged(session_type_,
+                                                        *audio_config_);
+  return ndk::ScopedAStatus::ok();
+}
+
+void BluetoothAudioProvider::binderDiedCallbackAidl(void* ptr) {
+  LOG(ERROR) << __func__ << " - BluetoothAudio Service died";
+  auto provider = static_cast<BluetoothAudioProvider*>(ptr);
+  if (provider == nullptr) {
+    LOG(ERROR) << __func__ << ": Null AudioProvider HAL died";
+    return;
+  }
+  provider->endSession();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
new file mode 100644
index 0000000..f7acbdf
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioProvider.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <fmq/AidlMessageQueue.h>
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using MqDataType = int8_t;
+using MqDataMode = SynchronizedReadWrite;
+using DataMQ = AidlMessageQueue<MqDataType, MqDataMode>;
+using DataMQDesc = MQDescriptor<MqDataType, MqDataMode>;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioProvider : public BnBluetoothAudioProvider {
+ public:
+  BluetoothAudioProvider();
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+  ndk::ScopedAStatus endSession();
+  ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status);
+  ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status);
+  ndk::ScopedAStatus updateAudioConfiguration(
+      const AudioConfiguration& audio_config);
+
+  virtual bool isValid(const SessionType& sessionType) = 0;
+
+ protected:
+  virtual ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) = 0;
+  static void binderDiedCallbackAidl(void* cookie_ptr);
+
+  ::ndk::ScopedAIBinder_DeathRecipient death_recipient_;
+
+  std::shared_ptr<IBluetoothAudioPort> stack_iface_;
+  std::unique_ptr<AudioConfiguration> audio_config_ = nullptr;
+  SessionType session_type_;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
new file mode 100644
index 0000000..1e55a0b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderFactoryAIDL"
+
+#include "BluetoothAudioProviderFactory.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <android-base/logging.h>
+
+#include "A2dpOffloadAudioProvider.h"
+#include "A2dpSoftwareAudioProvider.h"
+#include "BluetoothAudioProvider.h"
+#include "HearingAidAudioProvider.h"
+#include "LeAudioOffloadAudioProvider.h"
+#include "LeAudioSoftwareAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
+
+ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
+    const SessionType session_type,
+    std::shared_ptr<IBluetoothAudioProvider>* _aidl_return) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type);
+  std::shared_ptr<BluetoothAudioProvider> provider = nullptr;
+
+  switch (session_type) {
+    case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<A2dpSoftwareAudioProvider>();
+      break;
+    case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<A2dpOffloadAudioProvider>();
+      break;
+    case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<HearingAidAudioProvider>();
+      break;
+    case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<LeAudioSoftwareOutputAudioProvider>();
+      break;
+    case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<LeAudioOffloadOutputAudioProvider>();
+      break;
+    case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<LeAudioSoftwareInputAudioProvider>();
+      break;
+    case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<LeAudioOffloadInputAudioProvider>();
+      break;
+    default:
+      provider = nullptr;
+      break;
+  }
+
+  if (provider == nullptr || !provider->isValid(session_type)) {
+    provider = nullptr;
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  *_aidl_return = provider;
+
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderCapabilities(
+    const SessionType session_type,
+    std::vector<AudioCapabilities>* _aidl_return) {
+  if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    auto codec_capabilities =
+        BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(session_type);
+    _aidl_return->resize(codec_capabilities.size());
+    for (int i = 0; i < codec_capabilities.size(); i++) {
+      _aidl_return->at(i).set<AudioCapabilities::a2dpCapabilities>(
+          codec_capabilities[i]);
+    }
+  } else if (session_type ==
+                 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+             session_type ==
+                 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    std::vector<LeAudioCodecCapabilitiesSetting> db_codec_capabilities =
+        BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(session_type);
+    if (db_codec_capabilities.size()) {
+      _aidl_return->resize(db_codec_capabilities.size());
+      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+        _aidl_return->at(i).set<AudioCapabilities::leAudioCapabilities>(
+            db_codec_capabilities[i]);
+      }
+    }
+  } else if (session_type != SessionType::UNKNOWN) {
+    auto pcm_capabilities = BluetoothAudioCodecs::GetSoftwarePcmCapabilities();
+    _aidl_return->resize(pcm_capabilities.size());
+    for (int i = 0; i < pcm_capabilities.size(); i++) {
+      _aidl_return->at(i).set<AudioCapabilities::pcmCapabilities>(
+          pcm_capabilities[i]);
+    }
+  }
+
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type)
+            << " supports " << _aidl_return->size() << " codecs";
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
new file mode 100644
index 0000000..b38cfd2
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioProviderFactory.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioProviderFactory : public BnBluetoothAudioProviderFactory {
+ public:
+  BluetoothAudioProviderFactory();
+
+  ndk::ScopedAStatus openProvider(
+      const SessionType session_type,
+      std::shared_ptr<IBluetoothAudioProvider>* _aidl_return) override;
+
+  ndk::ScopedAStatus getProviderCapabilities(
+      const SessionType session_type,
+      std::vector<AudioCapabilities>* _aidl_return) override;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
new file mode 100644
index 0000000..66ce93b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderHearingAid"
+
+#include "HearingAidAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
+static constexpr uint32_t kPcmFrameCount = 128;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+static constexpr uint32_t kRtpFrameCount = 7;  // max counts by 1 tick (20ms)
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 1;  // single buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+HearingAidAudioProvider::HearingAidAudioProvider()
+    : BluetoothAudioProvider(), data_mq_(nullptr) {
+  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+            << " byte(s)";
+  std::unique_ptr<DataMQ> data_mq(
+      new DataMQ(kDataMqSize, /* EventFlag */ true));
+  if (data_mq && data_mq->isValid()) {
+    data_mq_ = std::move(data_mq);
+    session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+  } else {
+    ALOGE_IF(!data_mq, "failed to allocate data MQ");
+    ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
+  }
+}
+bool HearingAidAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
+}
+
+ndk::ScopedAStatus HearingAidAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  const auto& pcm_config = audio_config.get<AudioConfiguration::pcmConfig>();
+  if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << pcm_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              _aidl_return);
+}
+
+ndk::ScopedAStatus HearingAidAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  if (data_mq_ == nullptr || !data_mq_->isValid()) {
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  *_aidl_return = data_mq_->dupeDesc();
+  auto desc = data_mq_->dupeDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+                                                &desc, *audio_config_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/HearingAidAudioProvider.h b/bluetooth/audio/aidl/default/HearingAidAudioProvider.h
new file mode 100644
index 0000000..a7e19e9
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HearingAidAudioProvider.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class HearingAidAudioProvider : public BluetoothAudioProvider {
+ public:
+  HearingAidAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> data_mq_;
+
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
new file mode 100644
index 0000000..72ac9bd
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderLeAudioHW"
+
+#include "LeAudioOffloadAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
+    : LeAudioOffloadAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
+    : LeAudioOffloadAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+}
+
+LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
+    : BluetoothAudioProvider() {}
+
+bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  const auto& le_audio_config =
+      audio_config.get<AudioConfiguration::leAudioConfig>();
+  if (!BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
+          session_type_, le_audio_config)) {
+    LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
+                 << le_audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              _aidl_return);
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+                                                nullptr, *audio_config_);
+  *_aidl_return = DataMQDesc();
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
new file mode 100644
index 0000000..a27a2e7
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+  LeAudioOffloadAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+  LeAudioOffloadOutputAudioProvider();
+};
+
+class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+  LeAudioOffloadInputAudioProvider();
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..67b7d60
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderLeAudioSW"
+
+#include "LeAudioSoftwareAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+#include <cstdint>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr uint32_t kBufferOutCount = 2;  // two frame buffer
+static constexpr uint32_t kBufferInCount = 2;   // two frame buffer
+
+inline uint32_t channel_mode_to_channel_count(ChannelMode channel_mode) {
+  switch (channel_mode) {
+    case ChannelMode::MONO:
+      return 1;
+    case ChannelMode::STEREO:
+      return 2;
+    default:
+      return 0;
+  }
+  return 0;
+}
+
+LeAudioSoftwareOutputAudioProvider::LeAudioSoftwareOutputAudioProvider()
+    : LeAudioSoftwareAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+}
+
+LeAudioSoftwareInputAudioProvider::LeAudioSoftwareInputAudioProvider()
+    : LeAudioSoftwareAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH;
+}
+
+LeAudioSoftwareAudioProvider::LeAudioSoftwareAudioProvider()
+    : BluetoothAudioProvider(), data_mq_(nullptr) {}
+
+bool LeAudioSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus LeAudioSoftwareAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  const auto& pcm_config = audio_config.get<AudioConfiguration::pcmConfig>();
+  if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << pcm_config.toString();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  uint32_t buffer_modifier = 0;
+  if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH)
+    buffer_modifier = kBufferOutCount;
+  else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH)
+    buffer_modifier = kBufferInCount;
+
+  uint32_t data_mq_size =
+      (ceil(pcm_config.sampleRateHz) / 1000) *
+      channel_mode_to_channel_count(pcm_config.channelMode) *
+      (pcm_config.bitsPerSample / 8) * (pcm_config.dataIntervalUs / 1000) *
+      buffer_modifier;
+  if (data_mq_size <= 0) {
+    LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
+               << ", SampleRateHz: " << pcm_config.sampleRateHz
+               << ", ChannelMode: " << toString(pcm_config.channelMode)
+               << ", BitsPerSample: "
+               << static_cast<int>(pcm_config.bitsPerSample)
+               << ", DataIntervalUs: " << pcm_config.dataIntervalUs
+               << ", SessionType: " << toString(session_type_);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size
+            << " byte(s)";
+
+  std::unique_ptr<DataMQ> temp_data_mq(
+      new DataMQ(data_mq_size, /* EventFlag */ true));
+  if (temp_data_mq == nullptr || !temp_data_mq->isValid()) {
+    ALOGE_IF(!temp_data_mq, "failed to allocate data MQ");
+    ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid");
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  data_mq_ = std::move(temp_data_mq);
+
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              _aidl_return);
+}
+
+ndk::ScopedAStatus LeAudioSoftwareAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  if (data_mq_ == nullptr || !data_mq_->isValid()) {
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  *_aidl_return = data_mq_->dupeDesc();
+  auto desc = data_mq_->dupeDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+                                                &desc, *audio_config_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
new file mode 100644
index 0000000..fa58182
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class LeAudioSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+  LeAudioSoftwareAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> data_mq_;
+
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class LeAudioSoftwareOutputAudioProvider : public LeAudioSoftwareAudioProvider {
+ public:
+  LeAudioSoftwareOutputAudioProvider();
+};
+
+class LeAudioSoftwareInputAudioProvider : public LeAudioSoftwareAudioProvider {
+ public:
+  LeAudioSoftwareInputAudioProvider();
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/OWNERS b/bluetooth/audio/aidl/default/OWNERS
new file mode 100644
index 0000000..17ea464
--- /dev/null
+++ b/bluetooth/audio/aidl/default/OWNERS
@@ -0,0 +1,4 @@
+include platform/packages/modules/Bluetooth:/OWNERS
+
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/bluetooth_audio.xml b/bluetooth/audio/aidl/default/bluetooth_audio.xml
new file mode 100644
index 0000000..1859a1a
--- /dev/null
+++ b/bluetooth/audio/aidl/default/bluetooth_audio.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.audio</name>
+        <fqname>IBluetoothAudioProviderFactory/default</fqname>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/vts/OWNERS b/bluetooth/audio/aidl/vts/OWNERS
new file mode 100644
index 0000000..17ea464
--- /dev/null
+++ b/bluetooth/audio/aidl/vts/OWNERS
@@ -0,0 +1,4 @@
+include platform/packages/modules/Bluetooth:/OWNERS
+
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 19d2d92..974357e 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -22,6 +22,7 @@
     export_include_dirs: ["session/"],
     header_libs: ["libhardware_headers"],
     shared_libs: [
+        "android.hardware.audio.common@5.0",
         "android.hardware.bluetooth.audio@2.0",
         "android.hardware.bluetooth.audio@2.1",
         "android.hardware.bluetooth.audio@2.2",
@@ -31,5 +32,30 @@
         "libhidlbase",
         "liblog",
         "libutils",
+        "libbluetooth_audio_session_aidl",
+    ],
+}
+
+cc_library_shared {
+    name: "libbluetooth_audio_session_aidl",
+    vendor: true,
+    srcs: [
+        "aidl_session/BluetoothAudioCodecs.cpp",
+        "aidl_session/BluetoothAudioSession.cpp",
+        "aidl_session/HidlToAidlMiddleware.cpp",
+    ],
+    export_include_dirs: ["aidl_session/"],
+    header_libs: ["libhardware_headers"],
+    shared_libs: [
+        "android.hardware.bluetooth.audio@2.0",
+        "android.hardware.bluetooth.audio@2.1",
+        "android.hardware.bluetooth.audio@2.2",
+        "libbase",
+        "libcutils",
+        "libbinder_ndk",
+        "libfmq",
+        "liblog",
+        "android.hardware.bluetooth.audio-V1-ndk",
+        "libhidlbase",
     ],
 }
diff --git a/bluetooth/audio/utils/OWNERS b/bluetooth/audio/utils/OWNERS
index ed92847..17ea464 100644
--- a/bluetooth/audio/utils/OWNERS
+++ b/bluetooth/audio/utils/OWNERS
@@ -1,3 +1,4 @@
 include platform/packages/modules/Bluetooth:/OWNERS
 
-cheneyni@google.com
\ No newline at end of file
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
new file mode 100644
index 0000000..516ebe8
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -0,0 +1,490 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioCodecsAidl"
+
+#include "BluetoothAudioCodecs.h"
+
+#include <aidl/android/hardware/bluetooth/audio/AacCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/AacObjectType.h>
+#include <aidl/android/hardware/bluetooth/audio/AptxCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacQualityIndex.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SbcCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
+    .sampleRateHz = {16000, 24000, 44100, 48000, 88200, 96000},
+    .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
+    .bitsPerSample = {16, 24, 32},
+    .dataIntervalUs = {},
+};
+
+static const SbcCapabilities kDefaultOffloadSbcCapability = {
+    .sampleRateHz = {44100},
+    .channelMode = {SbcChannelMode::MONO, SbcChannelMode::JOINT_STEREO},
+    .blockLength = {4, 8, 12, 16},
+    .numSubbands = {8},
+    .allocMethod = {SbcAllocMethod::ALLOC_MD_L},
+    .bitsPerSample = {16},
+    .minBitpool = 2,
+    .maxBitpool = 53};
+
+static const AacCapabilities kDefaultOffloadAacCapability = {
+    .objectType = {AacObjectType::MPEG2_LC},
+    .sampleRateHz = {44100},
+    .channelMode = {ChannelMode::STEREO},
+    .variableBitRateSupported = true,
+    .bitsPerSample = {16}};
+
+static const LdacCapabilities kDefaultOffloadLdacCapability = {
+    .sampleRateHz = {44100, 48000, 88200, 96000},
+    .channelMode = {LdacChannelMode::DUAL, LdacChannelMode::STEREO},
+    .qualityIndex = {LdacQualityIndex::HIGH},
+    .bitsPerSample = {16, 24, 32}};
+
+static const AptxCapabilities kDefaultOffloadAptxCapability = {
+    .sampleRateHz = {44100, 48000},
+    .channelMode = {ChannelMode::STEREO},
+    .bitsPerSample = {16},
+};
+
+static const AptxCapabilities kDefaultOffloadAptxHdCapability = {
+    .sampleRateHz = {44100, 48000},
+    .channelMode = {ChannelMode::STEREO},
+    .bitsPerSample = {24},
+};
+
+static const Lc3Capabilities kDefaultA2dpOffloadLc3Capability = {
+    .samplingFrequencyHz = {44100, 48000},
+    .frameDurationUs = {7500, 10000},
+    .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
+};
+
+const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
+    {.codecType = CodecType::SBC, .capabilities = {}},
+    {.codecType = CodecType::AAC, .capabilities = {}},
+    {.codecType = CodecType::LDAC, .capabilities = {}},
+    {.codecType = CodecType::APTX, .capabilities = {}},
+    {.codecType = CodecType::APTX_HD, .capabilities = {}},
+    {.codecType = CodecType::LC3, .capabilities = {}}};
+
+std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
+
+static const UnicastCapability kInvalidUnicastCapability = {
+    .codecType = CodecType::UNKNOWN};
+
+static const BroadcastCapability kInvalidBroadcastCapability = {
+    .codecType = CodecType::UNKNOWN};
+
+// Default Supported Codecs
+// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30
+static const Lc3Capabilities kLc3Capability_16_1 = {
+    .samplingFrequencyHz = {16000},
+    .frameDurationUs = {7500},
+    .octetsPerFrame = {30}};
+
+// Default Supported Codecs
+// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
+static const Lc3Capabilities kLc3Capability_16_2 = {
+    .samplingFrequencyHz = {16000},
+    .frameDurationUs = {10000},
+    .octetsPerFrame = {40}};
+
+// Default Supported Codecs
+// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
+static const Lc3Capabilities kLc3Capability_48_4 = {
+    .samplingFrequencyHz = {48000},
+    .frameDurationUs = {10000},
+    .octetsPerFrame = {120}};
+
+static const std::vector<Lc3Capabilities> supportedLc3CapabilityList = {
+    kLc3Capability_48_4, kLc3Capability_16_2, kLc3Capability_16_1};
+
+static AudioLocation stereoAudio = static_cast<AudioLocation>(
+    static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
+    static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
+static AudioLocation monoAudio = AudioLocation::UNKNOWN;
+
+// Stores the supported setting of audio location, connected device, and the
+// channel count for each device
+std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
+    supportedDeviceSetting = {std::make_tuple(stereoAudio, 2, 1),
+                              std::make_tuple(monoAudio, 1, 2),
+                              std::make_tuple(monoAudio, 1, 1)};
+
+template <class T>
+bool BluetoothAudioCodecs::ContainedInVector(
+    const std::vector<T>& vector, const typename identity<T>::type& target) {
+  return std::find(vector.begin(), vector.end(), target) != vector.end();
+}
+
+bool BluetoothAudioCodecs::IsOffloadSbcConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::sbcConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << codec_specific.toString();
+    return false;
+  }
+  const SbcConfiguration sbc_data =
+      codec_specific.get<CodecConfiguration::CodecSpecific::sbcConfig>();
+
+  if (ContainedInVector(kDefaultOffloadSbcCapability.sampleRateHz,
+                        sbc_data.sampleRateHz) &&
+      ContainedInVector(kDefaultOffloadSbcCapability.blockLength,
+                        sbc_data.blockLength) &&
+      ContainedInVector(kDefaultOffloadSbcCapability.numSubbands,
+                        sbc_data.numSubbands) &&
+      ContainedInVector(kDefaultOffloadSbcCapability.bitsPerSample,
+                        sbc_data.bitsPerSample) &&
+      ContainedInVector(kDefaultOffloadSbcCapability.channelMode,
+                        sbc_data.channelMode) &&
+      ContainedInVector(kDefaultOffloadSbcCapability.allocMethod,
+                        sbc_data.allocMethod) &&
+      sbc_data.minBitpool <= sbc_data.maxBitpool &&
+      kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool &&
+      kDefaultOffloadSbcCapability.maxBitpool >= sbc_data.maxBitpool) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << codec_specific.toString();
+  return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::aacConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << codec_specific.toString();
+    return false;
+  }
+  const AacConfiguration aac_data =
+      codec_specific.get<CodecConfiguration::CodecSpecific::aacConfig>();
+
+  if (ContainedInVector(kDefaultOffloadAacCapability.sampleRateHz,
+                        aac_data.sampleRateHz) &&
+      ContainedInVector(kDefaultOffloadAacCapability.bitsPerSample,
+                        aac_data.bitsPerSample) &&
+      ContainedInVector(kDefaultOffloadAacCapability.channelMode,
+                        aac_data.channelMode) &&
+      ContainedInVector(kDefaultOffloadAacCapability.objectType,
+                        aac_data.objectType) &&
+      (!aac_data.variableBitRateEnabled ||
+       kDefaultOffloadAacCapability.variableBitRateSupported)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << codec_specific.toString();
+  return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLdacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getTag() !=
+      CodecConfiguration::CodecSpecific::ldacConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << codec_specific.toString();
+    return false;
+  }
+  const LdacConfiguration ldac_data =
+      codec_specific.get<CodecConfiguration::CodecSpecific::ldacConfig>();
+
+  if (ContainedInVector(kDefaultOffloadLdacCapability.sampleRateHz,
+                        ldac_data.sampleRateHz) &&
+      ContainedInVector(kDefaultOffloadLdacCapability.bitsPerSample,
+                        ldac_data.bitsPerSample) &&
+      ContainedInVector(kDefaultOffloadLdacCapability.channelMode,
+                        ldac_data.channelMode) &&
+      ContainedInVector(kDefaultOffloadLdacCapability.qualityIndex,
+                        ldac_data.qualityIndex)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << codec_specific.toString();
+  return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAptxConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getTag() !=
+      CodecConfiguration::CodecSpecific::aptxConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << codec_specific.toString();
+    return false;
+  }
+  const AptxConfiguration aptx_data =
+      codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
+
+  if (ContainedInVector(kDefaultOffloadAptxCapability.sampleRateHz,
+                        aptx_data.sampleRateHz) &&
+      ContainedInVector(kDefaultOffloadAptxCapability.bitsPerSample,
+                        aptx_data.bitsPerSample) &&
+      ContainedInVector(kDefaultOffloadAptxCapability.channelMode,
+                        aptx_data.channelMode)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << codec_specific.toString();
+  return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAptxHdConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getTag() !=
+      CodecConfiguration::CodecSpecific::aptxConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << codec_specific.toString();
+    return false;
+  }
+  const AptxConfiguration aptx_data =
+      codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
+
+  if (ContainedInVector(kDefaultOffloadAptxHdCapability.sampleRateHz,
+                        aptx_data.sampleRateHz) &&
+      ContainedInVector(kDefaultOffloadAptxHdCapability.bitsPerSample,
+                        aptx_data.bitsPerSample) &&
+      ContainedInVector(kDefaultOffloadAptxHdCapability.channelMode,
+                        aptx_data.channelMode)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << codec_specific.toString();
+  return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLc3ConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::lc3Config) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << codec_specific.toString();
+    return false;
+  }
+  const Lc3Configuration lc3_data =
+      codec_specific.get<CodecConfiguration::CodecSpecific::lc3Config>();
+
+  if (ContainedInVector(kDefaultA2dpOffloadLc3Capability.samplingFrequencyHz,
+                        lc3_data.samplingFrequencyHz) &&
+      ContainedInVector(kDefaultA2dpOffloadLc3Capability.frameDurationUs,
+                        lc3_data.frameDurationUs) &&
+      ContainedInVector(kDefaultA2dpOffloadLc3Capability.channelMode,
+                        lc3_data.channelMode)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << codec_specific.toString();
+  return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
+    const SessionType& session_type, const LeAudioConfiguration&) {
+  if (session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return false;
+  }
+  return true;
+}
+
+std::vector<PcmCapabilities>
+BluetoothAudioCodecs::GetSoftwarePcmCapabilities() {
+  return {kDefaultSoftwarePcmCapabilities};
+}
+
+std::vector<CodecCapabilities>
+BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(
+    const SessionType& session_type) {
+  if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return {};
+  }
+  std::vector<CodecCapabilities> offload_a2dp_codec_capabilities =
+      kDefaultOffloadA2dpCodecCapabilities;
+  for (auto& codec_capability : offload_a2dp_codec_capabilities) {
+    switch (codec_capability.codecType) {
+      case CodecType::SBC:
+        codec_capability.capabilities
+            .set<CodecCapabilities::Capabilities::sbcCapabilities>(
+                kDefaultOffloadSbcCapability);
+        break;
+      case CodecType::AAC:
+        codec_capability.capabilities
+            .set<CodecCapabilities::Capabilities::aacCapabilities>(
+                kDefaultOffloadAacCapability);
+        break;
+      case CodecType::LDAC:
+        codec_capability.capabilities
+            .set<CodecCapabilities::Capabilities::ldacCapabilities>(
+                kDefaultOffloadLdacCapability);
+        break;
+      case CodecType::APTX:
+        codec_capability.capabilities
+            .set<CodecCapabilities::Capabilities::aptxCapabilities>(
+                kDefaultOffloadAptxCapability);
+        break;
+      case CodecType::APTX_HD:
+        codec_capability.capabilities
+            .set<CodecCapabilities::Capabilities::aptxCapabilities>(
+                kDefaultOffloadAptxHdCapability);
+        break;
+      case CodecType::LC3:
+        codec_capability.capabilities
+            .set<CodecCapabilities::Capabilities::lc3Capabilities>(
+                kDefaultA2dpOffloadLc3Capability);
+        break;
+      case CodecType::UNKNOWN:
+      case CodecType::VENDOR:
+        break;
+    }
+  }
+  return offload_a2dp_codec_capabilities;
+}
+
+bool BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(
+    const PcmConfiguration& pcm_config) {
+  if (ContainedInVector(kDefaultSoftwarePcmCapabilities.sampleRateHz,
+                        pcm_config.sampleRateHz) &&
+      ContainedInVector(kDefaultSoftwarePcmCapabilities.bitsPerSample,
+                        pcm_config.bitsPerSample) &&
+      ContainedInVector(kDefaultSoftwarePcmCapabilities.channelMode,
+                        pcm_config.channelMode)
+      // data interval is not checked for now
+      // && pcm_config.dataIntervalUs != 0
+  ) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << pcm_config.toString();
+  return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+    const SessionType& session_type, const CodecConfiguration& codec_config) {
+  if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    LOG(ERROR) << __func__
+               << ": Invalid SessionType=" << toString(session_type);
+    return false;
+  }
+  const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config;
+  switch (codec_config.codecType) {
+    case CodecType::SBC:
+      if (IsOffloadSbcConfigurationValid(codec_specific)) {
+        return true;
+      }
+      break;
+    case CodecType::AAC:
+      if (IsOffloadAacConfigurationValid(codec_specific)) {
+        return true;
+      }
+      break;
+    case CodecType::LDAC:
+      if (IsOffloadLdacConfigurationValid(codec_specific)) {
+        return true;
+      }
+      break;
+    case CodecType::APTX:
+      if (IsOffloadAptxConfigurationValid(codec_specific)) {
+        return true;
+      }
+      break;
+    case CodecType::APTX_HD:
+      if (IsOffloadAptxHdConfigurationValid(codec_specific)) {
+        return true;
+      }
+      break;
+    case CodecType::LC3:
+      if (IsOffloadLc3ConfigurationValid(codec_specific)) {
+        return true;
+      }
+      break;
+    case CodecType::UNKNOWN:
+    case CodecType::VENDOR:
+      break;
+  }
+  return false;
+}
+
+UnicastCapability composeUnicastLc3Capability(
+    AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount,
+    const Lc3Capabilities& capability) {
+  return {
+      .codecType = CodecType::LC3,
+      .supportedChannel = audioLocation,
+      .deviceCount = deviceCnt,
+      .channelCountPerDevice = channelCount,
+      .leAudioCodecCapabilities =
+          UnicastCapability::LeAudioCodecCapabilities(capability),
+  };
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
+    const SessionType& session_type) {
+  if (session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return std::vector<LeAudioCodecCapabilitiesSetting>(0);
+  }
+
+  if (kDefaultOffloadLeAudioCapabilities.empty()) {
+    for (auto [audioLocation, deviceCnt, channelCount] :
+         supportedDeviceSetting) {
+      for (auto capability : supportedLc3CapabilityList) {
+        UnicastCapability lc3Capability = composeUnicastLc3Capability(
+            audioLocation, deviceCnt, channelCount, capability);
+        UnicastCapability lc3MonoDecodeCapability =
+            composeUnicastLc3Capability(monoAudio, 1, 1, capability);
+
+        // Adds the capability for encode only
+        kDefaultOffloadLeAudioCapabilities.push_back(
+            {.unicastEncodeCapability = lc3Capability,
+             .unicastDecodeCapability = kInvalidUnicastCapability,
+             .broadcastCapability = kInvalidBroadcastCapability});
+
+        // Adds the capability for decode only
+        kDefaultOffloadLeAudioCapabilities.push_back(
+            {.unicastEncodeCapability = kInvalidUnicastCapability,
+             .unicastDecodeCapability = lc3Capability,
+             .broadcastCapability = kInvalidBroadcastCapability});
+
+        // Adds the capability for the case that encode and decode exist at the
+        // same time
+        kDefaultOffloadLeAudioCapabilities.push_back(
+            {.unicastEncodeCapability = lc3Capability,
+             .unicastDecodeCapability = lc3MonoDecodeCapability,
+             .broadcastCapability = kInvalidBroadcastCapability});
+      }
+    }
+  }
+
+  return kDefaultOffloadLeAudioCapabilities;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
new file mode 100644
index 0000000..0259a7e
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/CodecCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/Lc3Configuration.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioCodecs {
+ public:
+  static std::vector<PcmCapabilities> GetSoftwarePcmCapabilities();
+  static std::vector<CodecCapabilities> GetA2dpOffloadCodecCapabilities(
+      const SessionType& session_type);
+
+  static bool IsSoftwarePcmConfigurationValid(
+      const PcmConfiguration& pcm_config);
+  static bool IsOffloadCodecConfigurationValid(
+      const SessionType& session_type, const CodecConfiguration& codec_config);
+
+  static bool IsOffloadLeAudioConfigurationValid(
+      const SessionType& session_type, const LeAudioConfiguration&);
+
+  static std::vector<LeAudioCodecCapabilitiesSetting>
+  GetLeAudioOffloadCodecCapabilities(const SessionType& session_type);
+
+ private:
+  template <typename T>
+  struct identity {
+    typedef T type;
+  };
+  template <class T>
+  static bool ContainedInVector(const std::vector<T>& vector,
+                                const typename identity<T>::type& target);
+  template <class T>
+  static bool ContainedInBitmask(const T& bitmask, const T& target);
+  static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield);
+  static bool IsOffloadSbcConfigurationValid(
+      const CodecConfiguration::CodecSpecific& codec_specific);
+  static bool IsOffloadAacConfigurationValid(
+      const CodecConfiguration::CodecSpecific& codec_specific);
+  static bool IsOffloadLdacConfigurationValid(
+      const CodecConfiguration::CodecSpecific& codec_specific);
+  static bool IsOffloadAptxConfigurationValid(
+      const CodecConfiguration::CodecSpecific& codec_specific);
+  static bool IsOffloadAptxHdConfigurationValid(
+      const CodecConfiguration::CodecSpecific& codec_specific);
+  static bool IsOffloadLc3ConfigurationValid(
+      const CodecConfiguration::CodecSpecific& codec_specific);
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
new file mode 100644
index 0000000..f626db8
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -0,0 +1,550 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#define LOG_TAG "BTAudioSessionAidl"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_manager.h>
+
+#include "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr int kFmqSendTimeoutMs = 1000;  // 1000 ms timeout for sending
+static constexpr int kFmqReceiveTimeoutMs =
+    1000;                               // 1000 ms timeout for receiving
+static constexpr int kWritePollMs = 1;  // polled non-blocking interval
+static constexpr int kReadPollMs = 1;   // polled non-blocking interval
+
+BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
+    : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {}
+
+/***
+ *
+ * Callback methods
+ *
+ ***/
+
+void BluetoothAudioSession::OnSessionStarted(
+    const std::shared_ptr<IBluetoothAudioPort> stack_iface,
+    const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (stack_iface == nullptr) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << ", IBluetoothAudioPort Invalid";
+  } else if (!UpdateAudioConfig(audio_config)) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << ", AudioConfiguration=" << audio_config.toString()
+               << " Invalid";
+  } else if (!UpdateDataPath(mq_desc)) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << " MqDescriptor Invalid";
+    audio_config_ = nullptr;
+  } else {
+    stack_iface_ = stack_iface;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << ", AudioConfiguration=" << audio_config.toString();
+    ReportSessionStatus();
+  }
+}
+
+void BluetoothAudioSession::OnSessionEnded() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  bool toggled = IsSessionReady();
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+  audio_config_ = nullptr;
+  stack_iface_ = nullptr;
+  UpdateDataPath(nullptr);
+  if (toggled) {
+    ReportSessionStatus();
+  }
+}
+
+/***
+ *
+ * Util methods
+ *
+ ***/
+
+const AudioConfiguration BluetoothAudioSession::GetAudioConfig() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    switch (session_type_) {
+      case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+        return AudioConfiguration(CodecConfiguration{});
+      case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+      case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+        return AudioConfiguration(LeAudioConfiguration{});
+      default:
+        return AudioConfiguration(PcmConfiguration{});
+    }
+  }
+  return *audio_config_;
+}
+
+void BluetoothAudioSession::ReportAudioConfigChanged(
+    const AudioConfiguration& audio_config) {
+  if (session_type_ !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type_ !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return;
+  }
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+  if (observers_.empty()) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
+    LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_)
+              << ", bluetooth_audio=0x"
+              << ::android::base::StringPrintf("%04x", cookie);
+    if (cb->audio_configuration_changed_cb_ != nullptr) {
+      cb->audio_configuration_changed_cb_(cookie);
+    }
+  }
+}
+
+bool BluetoothAudioSession::IsSessionReady() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+
+  bool is_mq_valid =
+      (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+       session_type_ ==
+           SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+       session_type_ ==
+           SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+       (data_mq_ != nullptr && data_mq_->isValid()));
+  return stack_iface_ != nullptr && is_mq_valid && audio_config_ != nullptr;
+}
+
+/***
+ *
+ * Status callback methods
+ *
+ ***/
+
+uint16_t BluetoothAudioSession::RegisterStatusCback(
+    const PortStatusCallbacks& callbacks) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  uint16_t cookie = ObserversCookieGetInitValue(session_type_);
+  uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
+
+  while (cookie < cookie_upper_bound) {
+    if (observers_.find(cookie) == observers_.end()) {
+      break;
+    }
+    ++cookie;
+  }
+  if (cookie >= cookie_upper_bound) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has " << observers_.size()
+               << " observers already (No Resource)";
+    return kObserversCookieUndefined;
+  }
+  std::shared_ptr<PortStatusCallbacks> cb =
+      std::make_shared<PortStatusCallbacks>();
+  *cb = callbacks;
+  observers_[cookie] = cb;
+  return cookie;
+}
+
+void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (observers_.erase(cookie) != 1) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << " no such provider=0x"
+                 << ::android::base::StringPrintf("%04x", cookie);
+  }
+}
+
+/***
+ *
+ * Stream methods
+ *
+ ***/
+
+bool BluetoothAudioSession::StartStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = stack_iface_->startStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+bool BluetoothAudioSession::SuspendStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = stack_iface_->suspendStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+void BluetoothAudioSession::StopStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    return;
+  }
+  auto hal_retval = stack_iface_->stopStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+  }
+}
+
+/***
+ *
+ * Private methods
+ *
+ ***/
+
+bool BluetoothAudioSession::UpdateDataPath(const DataMQDesc* mq_desc) {
+  if (mq_desc == nullptr) {
+    // usecase of reset by nullptr
+    data_mq_ = nullptr;
+    return true;
+  }
+  std::unique_ptr<DataMQ> temp_mq;
+  temp_mq.reset(new DataMQ(*mq_desc));
+  if (!temp_mq || !temp_mq->isValid()) {
+    data_mq_ = nullptr;
+    return false;
+  }
+  data_mq_ = std::move(temp_mq);
+  return true;
+}
+
+bool BluetoothAudioSession::UpdateAudioConfig(
+    const AudioConfiguration& audio_config) {
+  bool is_software_session =
+      (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
+       session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
+  bool is_offload_a2dp_session =
+      (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+  bool is_offload_le_audio_session =
+      (session_type_ ==
+           SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+       session_type_ ==
+           SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+  auto audio_config_tag = audio_config.getTag();
+  bool is_software_audio_config =
+      (is_software_session &&
+       audio_config_tag == AudioConfiguration::pcmConfig);
+  bool is_a2dp_offload_audio_config =
+      (is_offload_a2dp_session &&
+       audio_config_tag == AudioConfiguration::a2dpConfig);
+  bool is_le_audio_offload_audio_config =
+      (is_offload_le_audio_session &&
+       audio_config_tag == AudioConfiguration::leAudioConfig);
+  if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
+      !is_le_audio_offload_audio_config) {
+    return false;
+  }
+  audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+  return true;
+}
+
+void BluetoothAudioSession::ReportSessionStatus() {
+  // This is locked already by OnSessionStarted / OnSessionEnded
+  if (observers_.empty()) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<PortStatusCallbacks> callback = observer.second;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " notify to bluetooth_audio=0x"
+              << ::android::base::StringPrintf("%04x", cookie);
+    callback->session_changed_cb_(cookie);
+  }
+}
+
+/***
+ *
+ * PCM methods
+ *
+ ***/
+
+size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
+                                              size_t bytes) {
+  if (buffer == nullptr || bytes <= 0) {
+    return 0;
+  }
+  size_t total_written = 0;
+  int timeout_ms = kFmqSendTimeoutMs;
+  do {
+    std::unique_lock<std::recursive_mutex> lock(mutex_);
+    if (!IsSessionReady()) {
+      break;
+    }
+    size_t num_bytes_to_write = data_mq_->availableToWrite();
+    if (num_bytes_to_write) {
+      if (num_bytes_to_write > (bytes - total_written)) {
+        num_bytes_to_write = bytes - total_written;
+      }
+
+      if (!data_mq_->write(
+              static_cast<const MQDataType*>(buffer) + total_written,
+              num_bytes_to_write)) {
+        LOG(ERROR) << "FMQ datapath writing " << total_written << "/" << bytes
+                   << " failed";
+        return total_written;
+      }
+      total_written += num_bytes_to_write;
+    } else if (timeout_ms >= kWritePollMs) {
+      lock.unlock();
+      usleep(kWritePollMs * 1000);
+      timeout_ms -= kWritePollMs;
+    } else {
+      LOG(DEBUG) << "Data " << total_written << "/" << bytes << " overflow "
+                 << (kFmqSendTimeoutMs - timeout_ms) << " ms";
+      return total_written;
+    }
+  } while (total_written < bytes);
+  return total_written;
+}
+
+size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
+  if (buffer == nullptr || bytes <= 0) {
+    return 0;
+  }
+  size_t total_read = 0;
+  int timeout_ms = kFmqReceiveTimeoutMs;
+  do {
+    std::unique_lock<std::recursive_mutex> lock(mutex_);
+    if (!IsSessionReady()) {
+      break;
+    }
+    size_t num_bytes_to_read = data_mq_->availableToRead();
+    if (num_bytes_to_read) {
+      if (num_bytes_to_read > (bytes - total_read)) {
+        num_bytes_to_read = bytes - total_read;
+      }
+      if (!data_mq_->read(static_cast<MQDataType*>(buffer) + total_read,
+                          num_bytes_to_read)) {
+        LOG(ERROR) << "FMQ datapath reading " << total_read << "/" << bytes
+                   << " failed";
+        return total_read;
+      }
+      total_read += num_bytes_to_read;
+    } else if (timeout_ms >= kReadPollMs) {
+      lock.unlock();
+      usleep(kReadPollMs * 1000);
+      timeout_ms -= kReadPollMs;
+      continue;
+    } else {
+      LOG(DEBUG) << "Data " << total_read << "/" << bytes << " overflow "
+                 << (kFmqReceiveTimeoutMs - timeout_ms) << " ms";
+      return total_read;
+    }
+  } while (total_read < bytes);
+  return total_read;
+}
+
+/***
+ *
+ * Other methods
+ *
+ ***/
+
+void BluetoothAudioSession::ReportControlStatus(bool start_resp,
+                                                BluetoothAudioStatus status) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (observers_.empty()) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<PortStatusCallbacks> callback = observer.second;
+    LOG(INFO) << __func__ << " - status=" << toString(status)
+              << " for SessionType=" << toString(session_type_)
+              << ", bluetooth_audio=0x"
+              << ::android::base::StringPrintf("%04x", cookie)
+              << (start_resp ? " started" : " suspended");
+    callback->control_result_cb_(cookie, start_resp, status);
+  }
+}
+
+bool BluetoothAudioSession::GetPresentationPosition(
+    PresentationPosition& presentation_position) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  bool retval = false;
+
+  if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return retval;
+}
+
+void BluetoothAudioSession::UpdateSourceMetadata(
+    const struct source_metadata& source_metadata) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return;
+  }
+
+  ssize_t track_count = source_metadata.track_count;
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
+            << track_count << " track(s)";
+  if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return;
+  }
+
+  SourceMetadata hal_source_metadata;
+  hal_source_metadata.tracks.resize(track_count);
+  for (int i = 0; i < track_count; i++) {
+    hal_source_metadata.tracks[i].usage =
+        static_cast<media::audio::common::AudioUsage>(
+            source_metadata.tracks[i].usage);
+    hal_source_metadata.tracks[i].contentType =
+        static_cast<media::audio::common::AudioContentType>(
+            source_metadata.tracks[i].content_type);
+    hal_source_metadata.tracks[i].gain = source_metadata.tracks[i].gain;
+    LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", usage=" << toString(hal_source_metadata.tracks[i].usage)
+                 << ", content="
+                 << toString(hal_source_metadata.tracks[i].contentType)
+                 << ", gain=" << hal_source_metadata.tracks[i].gain;
+  }
+
+  auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+  }
+}
+
+void BluetoothAudioSession::UpdateSinkMetadata(
+    const struct sink_metadata& sink_metadata) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return;
+  }
+
+  ssize_t track_count = sink_metadata.track_count;
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
+            << track_count << " track(s)";
+  if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return;
+  }
+
+  SinkMetadata hal_sink_metadata;
+  hal_sink_metadata.tracks.resize(track_count);
+  for (int i = 0; i < track_count; i++) {
+    hal_sink_metadata.tracks[i].source =
+        static_cast<media::audio::common::AudioSource>(
+            sink_metadata.tracks[i].source);
+    hal_sink_metadata.tracks[i].gain = sink_metadata.tracks[i].gain;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << ", source=" << sink_metadata.tracks[i].source
+              << ", dest_device=" << sink_metadata.tracks[i].dest_device
+              << ", gain=" << sink_metadata.tracks[i].gain
+              << ", dest_device_address="
+              << sink_metadata.tracks[i].dest_device_address;
+  }
+
+  auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+  }
+}
+
+bool BluetoothAudioSession::IsAidlAvailable() {
+  if (is_aidl_checked) return is_aidl_available;
+  is_aidl_available =
+      (AServiceManager_checkService(
+           kDefaultAudioProviderFactoryInterface.c_str()) != nullptr);
+  is_aidl_checked = true;
+  return is_aidl_available;
+}
+
+/***
+ *
+ * BluetoothAudioSessionInstance
+ *
+ ***/
+std::mutex BluetoothAudioSessionInstance::mutex_;
+std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+    BluetoothAudioSessionInstance::sessions_map_;
+
+std::shared_ptr<BluetoothAudioSession>
+BluetoothAudioSessionInstance::GetSessionInstance(
+    const SessionType& session_type) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (!sessions_map_.empty()) {
+    auto entry = sessions_map_.find(session_type);
+    if (entry != sessions_map_.end()) {
+      return entry->second;
+    }
+  }
+  std::shared_ptr<BluetoothAudioSession> session_ptr =
+      std::make_shared<BluetoothAudioSession>(session_type);
+  sessions_map_[session_type] = session_ptr;
+  return session_ptr;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
new file mode 100644
index 0000000..73bc0f8
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/common/SinkMetadata.h>
+#include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hardware/audio.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using ::aidl::android::hardware::audio::common::SinkMetadata;
+using ::aidl::android::hardware::audio::common::SourceMetadata;
+
+using MQDataType = int8_t;
+using MQDataMode = SynchronizedReadWrite;
+using DataMQ = AidlMessageQueue<MQDataType, MQDataMode>;
+using DataMQDesc =
+    ::aidl::android::hardware::common::fmq::MQDescriptor<MQDataType,
+                                                         MQDataMode>;
+
+static constexpr uint16_t kObserversCookieSize = 0x0010;  // 0x0000 ~ 0x000f
+static constexpr uint16_t kObserversCookieUndefined =
+    (static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00);
+inline SessionType ObserversCookieGetSessionType(uint16_t cookie) {
+  return static_cast<SessionType>(cookie >> 8 & 0x00ff);
+}
+inline uint16_t ObserversCookieGetInitValue(SessionType session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
+}
+inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
+         kObserversCookieSize;
+}
+
+/***
+ * This presents the callbacks of started / suspended and session changed,
+ * and the bluetooth_audio module uses to receive the status notification
+ ***/
+struct PortStatusCallbacks {
+  /***
+   * control_result_cb_ - when the Bluetooth stack reports results of
+   * streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
+   * this callback to report to the bluetooth_audio module.
+   * @param: cookie - indicates which bluetooth_audio output should handle
+   * @param: start_resp - this report is for startStream or not
+   * @param: status - the result of startStream
+   ***/
+  std::function<void(uint16_t cookie, bool start_resp,
+                     BluetoothAudioStatus status)>
+      control_result_cb_;
+  /***
+   * session_changed_cb_ - when the Bluetooth stack start / end session, the
+   * BluetoothAudioProvider will invoke this callback to notify to the
+   * bluetooth_audio module.
+   * @param: cookie - indicates which bluetooth_audio output should handle
+   ***/
+  std::function<void(uint16_t cookie)> session_changed_cb_;
+  /***
+   * audio_configuration_changed_cb_ - when the Bluetooth stack change the audio
+   * configuration, the BluetoothAudioProvider will invoke this callback to
+   * notify to the bluetooth_audio module.
+   * @param: cookie - indicates which bluetooth_audio output should handle
+   ***/
+  std::function<void(uint16_t cookie)> audio_configuration_changed_cb_;
+};
+
+class BluetoothAudioSession {
+ public:
+  BluetoothAudioSession(const SessionType& session_type);
+
+  /***
+   * The function helps to check if this session is ready or not
+   * @return: true if the Bluetooth stack has started the specified session
+   ***/
+  bool IsSessionReady();
+
+  /***
+   * The report function is used to report that the Bluetooth stack has started
+   * this session without any failure, and will invoke session_changed_cb_ to
+   * notify those registered bluetooth_audio outputs
+   ***/
+  void OnSessionStarted(const std::shared_ptr<IBluetoothAudioPort> stack_iface,
+                        const DataMQDesc* mq_desc,
+                        const AudioConfiguration& audio_config);
+
+  /***
+   * The report function is used to report that the Bluetooth stack has ended
+   * the session, and will invoke session_changed_cb_ to notify registered
+   * bluetooth_audio outputs
+   ***/
+  void OnSessionEnded();
+
+  /***
+   * The report function is used to report that the Bluetooth stack has notified
+   * the result of startStream or suspendStream, and will invoke
+   * control_result_cb_ to notify registered bluetooth_audio outputs
+   ***/
+  void ReportControlStatus(bool start_resp, BluetoothAudioStatus status);
+
+  /***
+   * The control function helps the bluetooth_audio module to register
+   * PortStatusCallbacks
+   * @return: cookie - the assigned number to this bluetooth_audio output
+   ***/
+  uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks);
+
+  /***
+   * The control function helps the bluetooth_audio module to unregister
+   * PortStatusCallbacks
+   * @param: cookie - indicates which bluetooth_audio output is
+   ***/
+  void UnregisterStatusCback(uint16_t cookie);
+
+  /***
+   * The control function is for the bluetooth_audio module to get the current
+   * AudioConfiguration
+   ***/
+  const AudioConfiguration GetAudioConfig();
+
+  /***
+   * The report function is used to report that the Bluetooth stack has notified
+   * the audio configuration changed, and will invoke
+   * audio_configuration_changed_cb_ to notify registered bluetooth_audio
+   * outputs
+   ***/
+  void ReportAudioConfigChanged(const AudioConfiguration& audio_config);
+
+  /***
+   * Those control functions are for the bluetooth_audio module to start,
+   * suspend, stop stream, to check position, and to update metadata.
+   ***/
+  bool StartStream();
+  bool SuspendStream();
+  void StopStream();
+  bool GetPresentationPosition(PresentationPosition& presentation_position);
+  void UpdateSourceMetadata(const struct source_metadata& source_metadata);
+  void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
+
+  // The control function writes stream to FMQ
+  size_t OutWritePcmData(const void* buffer, size_t bytes);
+  // The control function read stream from FMQ
+  size_t InReadPcmData(void* buffer, size_t bytes);
+
+  // Return if IBluetoothAudioProviderFactory implementation existed
+  static bool IsAidlAvailable();
+
+ private:
+  // using recursive_mutex to allow hwbinder to re-enter again.
+  std::recursive_mutex mutex_;
+  SessionType session_type_;
+
+  // audio control path to use for both software and offloading
+  std::shared_ptr<IBluetoothAudioPort> stack_iface_;
+  // audio data path (FMQ) for software encoding
+  std::unique_ptr<DataMQ> data_mq_;
+  // audio data configuration for both software and offloading
+  std::unique_ptr<AudioConfiguration> audio_config_;
+
+  // saving those registered bluetooth_audio's callbacks
+  std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
+      observers_;
+
+  bool UpdateDataPath(const DataMQDesc* mq_desc);
+  bool UpdateAudioConfig(const AudioConfiguration& audio_config);
+  // invoking the registered session_changed_cb_
+  void ReportSessionStatus();
+
+  static inline std::atomic<bool> is_aidl_checked = false;
+  static inline std::atomic<bool> is_aidl_available = false;
+  static inline const std::string kDefaultAudioProviderFactoryInterface =
+      std::string() + IBluetoothAudioProviderFactory::descriptor + "/default";
+};
+
+class BluetoothAudioSessionInstance {
+ public:
+  // The API is to fetch the specified session of A2DP / Hearing Aid
+  static std::shared_ptr<BluetoothAudioSession> GetSessionInstance(
+      const SessionType& session_type);
+
+ private:
+  static std::mutex mutex_;
+  static std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+      sessions_map_;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
new file mode 100644
index 0000000..aff01e5
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2018 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 "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionControl {
+ public:
+  /***
+   * The control API helps to check if session is ready or not
+   * @return: true if the Bluetooth stack has started th specified session
+   ***/
+  static bool IsSessionReady(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->IsSessionReady();
+    }
+
+    return false;
+  }
+
+  /***
+   * The control API helps the bluetooth_audio module to register
+   * PortStatusCallbacks
+   * @return: cookie - the assigned number to this bluetooth_audio output
+   ***/
+  static uint16_t RegisterControlResultCback(
+      const SessionType& session_type, const PortStatusCallbacks& cbacks) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->RegisterStatusCback(cbacks);
+    }
+    return kObserversCookieUndefined;
+  }
+
+  /***
+   * The control API helps the bluetooth_audio module to unregister
+   * PortStatusCallbacks
+   * @param: cookie - indicates which bluetooth_audio output is
+   ***/
+  static void UnregisterControlResultCback(const SessionType& session_type,
+                                           uint16_t cookie) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UnregisterStatusCback(cookie);
+    }
+  }
+
+  /***
+   * The control API for the bluetooth_audio module to get current
+   * AudioConfiguration
+   ***/
+  static const AudioConfiguration GetAudioConfig(
+      const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->GetAudioConfig();
+    }
+    switch (session_type) {
+      case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+        return AudioConfiguration(CodecConfiguration{});
+      case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+      case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+        return AudioConfiguration(LeAudioConfiguration{});
+      default:
+        return AudioConfiguration(PcmConfiguration{});
+    }
+  }
+
+  /***
+   * Those control APIs for the bluetooth_audio module to start / suspend /
+  stop
+   * stream, to check position, and to update metadata.
+  ***/
+  static bool StartStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->StartStream();
+    }
+    return false;
+  }
+
+  static bool SuspendStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->SuspendStream();
+    }
+    return false;
+  }
+
+  static void StopStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->StopStream();
+    }
+  }
+
+  static bool GetPresentationPosition(
+      const SessionType& session_type,
+      PresentationPosition& presentation_position) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->GetPresentationPosition(presentation_position);
+    }
+    return false;
+  }
+
+  static void UpdateSourceMetadata(
+      const SessionType& session_type,
+      const struct source_metadata& source_metadata) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UpdateSourceMetadata(source_metadata);
+    }
+  }
+
+  static void UpdateSinkMetadata(const SessionType& session_type,
+                                 const struct sink_metadata& sink_metadata) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UpdateSinkMetadata(sink_metadata);
+    }
+  }
+
+  /***
+   * The control API writes stream to FMQ
+   ***/
+  static size_t OutWritePcmData(const SessionType& session_type,
+                                const void* buffer, size_t bytes) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->OutWritePcmData(buffer, bytes);
+    }
+    return 0;
+  }
+
+  /***
+   * The control API reads stream from FMQ
+   ***/
+  static size_t InReadPcmData(const SessionType& session_type, void* buffer,
+                              size_t bytes) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->InReadPcmData(buffer, bytes);
+    }
+    return 0;
+  }
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
new file mode 100644
index 0000000..18569c3
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionReport {
+ public:
+  /***
+   * The API reports the Bluetooth stack has started the session, and will
+   * inform registered bluetooth_audio outputs
+   ***/
+  static void OnSessionStarted(
+      const SessionType& session_type,
+      const std::shared_ptr<IBluetoothAudioPort> host_iface,
+      const DataMQDesc* data_mq, const AudioConfiguration& audio_config) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->OnSessionStarted(host_iface, data_mq, audio_config);
+    }
+  }
+
+  /***
+   * The API reports the Bluetooth stack has ended the session, and will
+   * inform registered bluetooth_audio outputs
+   ***/
+  static void OnSessionEnded(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->OnSessionEnded();
+    }
+  }
+
+  /***
+   * The API reports the Bluetooth stack has replied the result of startStream
+   * or suspendStream, and will inform registered bluetooth_audio outputs
+   ***/
+  static void ReportControlStatus(const SessionType& session_type,
+                                  const bool& start_resp,
+                                  BluetoothAudioStatus status) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->ReportControlStatus(start_resp, status);
+    }
+  }
+  /***
+   * The API reports the Bluetooth stack has replied the changed of the audio
+   * configuration, and will inform registered bluetooth_audio outputs
+   ***/
+  static void ReportAudioConfigChanged(const SessionType& session_type,
+                                       const AudioConfiguration& audio_config) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->ReportAudioConfigChanged(audio_config);
+    }
+  }
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
new file mode 100644
index 0000000..632a389
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
@@ -0,0 +1,787 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BtAudioNakahara"
+
+#include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <android-base/logging.h>
+
+#include <functional>
+#include <unordered_map>
+
+#include "../aidl_session/BluetoothAudioSession.h"
+#include "../aidl_session/BluetoothAudioSessionControl.h"
+#include "HidlToAidlMiddleware_2_0.h"
+#include "HidlToAidlMiddleware_2_1.h"
+#include "HidlToAidlMiddleware_2_2.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using HidlStatus = ::android::hardware::bluetooth::audio::V2_0::Status;
+using PcmConfig_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using SampleRate_2_0 = ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ChannelMode_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using BitsPerSample_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using CodecConfig_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using CodecType_2_0 = ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using SbcConfig_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+using AacConfig_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using LdacConfig_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using AptxConfig_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using SbcAllocMethod_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using SbcBlockLength_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using SbcChannelMode_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using SbcNumSubbands_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using AacObjectType_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using AacVarBitRate_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using LdacChannelMode_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using LdacQualityIndex_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+
+using PcmConfig_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::PcmParameters;
+using SampleRate_2_1 = ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+using Lc3CodecConfig_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration;
+using Lc3Config_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::Lc3Parameters;
+using Lc3FrameDuration_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::Lc3FrameDuration;
+
+using LeAudioConfig_2_2 =
+    ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
+using LeAudioMode_2_2 =
+    ::android::hardware::bluetooth::audio::V2_2::LeAudioMode;
+
+std::mutex legacy_callback_lock;
+std::unordered_map<
+    SessionType,
+    std::unordered_map<uint16_t, std::shared_ptr<PortStatusCallbacks_2_2>>>
+    legacy_callback_table;
+
+const static std::unordered_map<SessionType_2_1, SessionType>
+    session_type_2_1_to_aidl_map{
+        {SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH,
+         SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH},
+        {SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH,
+         SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
+        {SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+         SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH},
+        {SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+         SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH},
+        {SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH,
+         SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH},
+        {SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
+        {SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH},
+    };
+
+const static std::unordered_map<int32_t, SampleRate_2_1>
+    sample_rate_to_hidl_2_1_map{
+        {44100, SampleRate_2_1::RATE_44100},
+        {48000, SampleRate_2_1::RATE_48000},
+        {88200, SampleRate_2_1::RATE_88200},
+        {96000, SampleRate_2_1::RATE_96000},
+        {176400, SampleRate_2_1::RATE_176400},
+        {192000, SampleRate_2_1::RATE_192000},
+        {16000, SampleRate_2_1::RATE_16000},
+        {24000, SampleRate_2_1::RATE_24000},
+        {8000, SampleRate_2_1::RATE_8000},
+        {32000, SampleRate_2_1::RATE_32000},
+    };
+
+const static std::unordered_map<CodecType, CodecType_2_0>
+    codec_type_to_hidl_2_0_map{
+        {CodecType::UNKNOWN, CodecType_2_0::UNKNOWN},
+        {CodecType::SBC, CodecType_2_0::SBC},
+        {CodecType::AAC, CodecType_2_0::AAC},
+        {CodecType::APTX, CodecType_2_0::APTX},
+        {CodecType::APTX_HD, CodecType_2_0::APTX_HD},
+        {CodecType::LDAC, CodecType_2_0::LDAC},
+        {CodecType::LC3, CodecType_2_0::UNKNOWN},
+    };
+
+const static std::unordered_map<SbcChannelMode, SbcChannelMode_2_0>
+    sbc_channel_mode_to_hidl_2_0_map{
+        {SbcChannelMode::UNKNOWN, SbcChannelMode_2_0::UNKNOWN},
+        {SbcChannelMode::JOINT_STEREO, SbcChannelMode_2_0::JOINT_STEREO},
+        {SbcChannelMode::STEREO, SbcChannelMode_2_0::STEREO},
+        {SbcChannelMode::DUAL, SbcChannelMode_2_0::DUAL},
+        {SbcChannelMode::MONO, SbcChannelMode_2_0::MONO},
+    };
+
+const static std::unordered_map<int8_t, SbcBlockLength_2_0>
+    sbc_block_length_to_hidl_map{
+        {4, SbcBlockLength_2_0::BLOCKS_4},
+        {8, SbcBlockLength_2_0::BLOCKS_8},
+        {12, SbcBlockLength_2_0::BLOCKS_12},
+        {16, SbcBlockLength_2_0::BLOCKS_16},
+    };
+
+const static std::unordered_map<int8_t, SbcNumSubbands_2_0>
+    sbc_subbands_to_hidl_map{
+        {4, SbcNumSubbands_2_0::SUBBAND_4},
+        {8, SbcNumSubbands_2_0::SUBBAND_8},
+    };
+
+const static std::unordered_map<SbcAllocMethod, SbcAllocMethod_2_0>
+    sbc_alloc_method_to_hidl_map{
+        {SbcAllocMethod::ALLOC_MD_S, SbcAllocMethod_2_0::ALLOC_MD_S},
+        {SbcAllocMethod::ALLOC_MD_L, SbcAllocMethod_2_0::ALLOC_MD_L},
+    };
+
+const static std::unordered_map<AacObjectType, AacObjectType_2_0>
+    aac_object_type_to_hidl_map{
+        {AacObjectType::MPEG2_LC, AacObjectType_2_0::MPEG2_LC},
+        {AacObjectType::MPEG4_LC, AacObjectType_2_0::MPEG4_LC},
+        {AacObjectType::MPEG4_LTP, AacObjectType_2_0::MPEG4_LTP},
+        {AacObjectType::MPEG4_SCALABLE, AacObjectType_2_0::MPEG4_SCALABLE},
+    };
+
+const static std::unordered_map<LdacChannelMode, LdacChannelMode_2_0>
+    ldac_channel_mode_to_hidl_map{
+        {LdacChannelMode::UNKNOWN, LdacChannelMode_2_0::UNKNOWN},
+        {LdacChannelMode::STEREO, LdacChannelMode_2_0::STEREO},
+        {LdacChannelMode::DUAL, LdacChannelMode_2_0::DUAL},
+        {LdacChannelMode::MONO, LdacChannelMode_2_0::MONO},
+    };
+
+const static std::unordered_map<LdacQualityIndex, LdacQualityIndex_2_0>
+    ldac_qindex_to_hidl_map{
+        {LdacQualityIndex::HIGH, LdacQualityIndex_2_0::QUALITY_HIGH},
+        {LdacQualityIndex::MID, LdacQualityIndex_2_0::QUALITY_MID},
+        {LdacQualityIndex::LOW, LdacQualityIndex_2_0::QUALITY_LOW},
+        {LdacQualityIndex::ABR, LdacQualityIndex_2_0::QUALITY_ABR},
+    };
+
+inline SessionType from_session_type_2_1(
+    const SessionType_2_1& session_type_hidl) {
+  auto it = session_type_2_1_to_aidl_map.find(session_type_hidl);
+  if (it != session_type_2_1_to_aidl_map.end()) return it->second;
+  return SessionType::UNKNOWN;
+}
+
+inline SessionType from_session_type_2_0(
+    const SessionType_2_0& session_type_hidl) {
+  return from_session_type_2_1(static_cast<SessionType_2_1>(session_type_hidl));
+}
+
+inline HidlStatus to_hidl_status(const BluetoothAudioStatus& status) {
+  switch (status) {
+    case BluetoothAudioStatus::SUCCESS:
+      return HidlStatus::SUCCESS;
+    case BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION:
+      return HidlStatus::UNSUPPORTED_CODEC_CONFIGURATION;
+    default:
+      return HidlStatus::FAILURE;
+  }
+}
+
+inline SampleRate_2_1 to_hidl_sample_rate_2_1(const int32_t sample_rate_hz) {
+  auto it = sample_rate_to_hidl_2_1_map.find(sample_rate_hz);
+  if (it != sample_rate_to_hidl_2_1_map.end()) return it->second;
+  return SampleRate_2_1::RATE_UNKNOWN;
+}
+
+inline SampleRate_2_0 to_hidl_sample_rate_2_0(const int32_t sample_rate_hz) {
+  auto it = sample_rate_to_hidl_2_1_map.find(sample_rate_hz);
+  if (it != sample_rate_to_hidl_2_1_map.end())
+    return static_cast<SampleRate_2_0>(it->second);
+  return SampleRate_2_0::RATE_UNKNOWN;
+}
+
+inline BitsPerSample_2_0 to_hidl_bits_per_sample(const int8_t bit_per_sample) {
+  switch (bit_per_sample) {
+    case 16:
+      return BitsPerSample_2_0::BITS_16;
+    case 24:
+      return BitsPerSample_2_0::BITS_24;
+    case 32:
+      return BitsPerSample_2_0::BITS_32;
+    default:
+      return BitsPerSample_2_0::BITS_UNKNOWN;
+  }
+}
+
+inline ChannelMode_2_0 to_hidl_channel_mode(const ChannelMode channel_mode) {
+  switch (channel_mode) {
+    case ChannelMode::MONO:
+      return ChannelMode_2_0::MONO;
+    case ChannelMode::STEREO:
+      return ChannelMode_2_0::STEREO;
+    default:
+      return ChannelMode_2_0::UNKNOWN;
+  }
+}
+
+inline PcmConfig_2_0 to_hidl_pcm_config_2_0(
+    const PcmConfiguration& pcm_config) {
+  PcmConfig_2_0 hidl_pcm_config;
+  hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_0(pcm_config.sampleRateHz);
+  hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
+  hidl_pcm_config.bitsPerSample =
+      to_hidl_bits_per_sample(pcm_config.bitsPerSample);
+  return hidl_pcm_config;
+}
+
+inline CodecType_2_0 to_hidl_codec_type_2_0(const CodecType codec_type) {
+  auto it = codec_type_to_hidl_2_0_map.find(codec_type);
+  if (it != codec_type_to_hidl_2_0_map.end()) return it->second;
+  return CodecType_2_0::UNKNOWN;
+}
+
+inline SbcConfig_2_0 to_hidl_sbc_config(const SbcConfiguration sbc_config) {
+  SbcConfig_2_0 hidl_sbc_config;
+  hidl_sbc_config.minBitpool = sbc_config.minBitpool;
+  hidl_sbc_config.maxBitpool = sbc_config.maxBitpool;
+  hidl_sbc_config.sampleRate = to_hidl_sample_rate_2_0(sbc_config.sampleRateHz);
+  hidl_sbc_config.bitsPerSample =
+      to_hidl_bits_per_sample(sbc_config.bitsPerSample);
+  if (sbc_channel_mode_to_hidl_2_0_map.find(sbc_config.channelMode) !=
+      sbc_channel_mode_to_hidl_2_0_map.end()) {
+    hidl_sbc_config.channelMode =
+        sbc_channel_mode_to_hidl_2_0_map.at(sbc_config.channelMode);
+  }
+  if (sbc_block_length_to_hidl_map.find(sbc_config.blockLength) !=
+      sbc_block_length_to_hidl_map.end()) {
+    hidl_sbc_config.blockLength =
+        sbc_block_length_to_hidl_map.at(sbc_config.blockLength);
+  }
+  if (sbc_subbands_to_hidl_map.find(sbc_config.numSubbands) !=
+      sbc_subbands_to_hidl_map.end()) {
+    hidl_sbc_config.numSubbands =
+        sbc_subbands_to_hidl_map.at(sbc_config.numSubbands);
+  }
+  if (sbc_alloc_method_to_hidl_map.find(sbc_config.allocMethod) !=
+      sbc_alloc_method_to_hidl_map.end()) {
+    hidl_sbc_config.allocMethod =
+        sbc_alloc_method_to_hidl_map.at(sbc_config.allocMethod);
+  }
+  return hidl_sbc_config;
+}
+
+inline AacConfig_2_0 to_hidl_aac_config(const AacConfiguration aac_config) {
+  AacConfig_2_0 hidl_aac_config;
+  hidl_aac_config.sampleRate = to_hidl_sample_rate_2_0(aac_config.sampleRateHz);
+  hidl_aac_config.bitsPerSample =
+      to_hidl_bits_per_sample(aac_config.bitsPerSample);
+  hidl_aac_config.channelMode = to_hidl_channel_mode(aac_config.channelMode);
+  if (aac_object_type_to_hidl_map.find(aac_config.objectType) !=
+      aac_object_type_to_hidl_map.end()) {
+    hidl_aac_config.objectType =
+        aac_object_type_to_hidl_map.at(aac_config.objectType);
+  }
+  hidl_aac_config.variableBitRateEnabled = aac_config.variableBitRateEnabled
+                                               ? AacVarBitRate_2_0::ENABLED
+                                               : AacVarBitRate_2_0::DISABLED;
+  return hidl_aac_config;
+}
+
+inline LdacConfig_2_0 to_hidl_ldac_config(const LdacConfiguration ldac_config) {
+  LdacConfig_2_0 hidl_ldac_config;
+  hidl_ldac_config.sampleRate =
+      to_hidl_sample_rate_2_0(ldac_config.sampleRateHz);
+  hidl_ldac_config.bitsPerSample =
+      to_hidl_bits_per_sample(ldac_config.bitsPerSample);
+  if (ldac_channel_mode_to_hidl_map.find(ldac_config.channelMode) !=
+      ldac_channel_mode_to_hidl_map.end()) {
+    hidl_ldac_config.channelMode =
+        ldac_channel_mode_to_hidl_map.at(ldac_config.channelMode);
+  }
+  if (ldac_qindex_to_hidl_map.find(ldac_config.qualityIndex) !=
+      ldac_qindex_to_hidl_map.end()) {
+    hidl_ldac_config.qualityIndex =
+        ldac_qindex_to_hidl_map.at(ldac_config.qualityIndex);
+  }
+  return hidl_ldac_config;
+}
+
+inline AptxConfig_2_0 to_hidl_aptx_config(const AptxConfiguration aptx_config) {
+  AptxConfig_2_0 hidl_aptx_config;
+  hidl_aptx_config.sampleRate =
+      to_hidl_sample_rate_2_0(aptx_config.sampleRateHz);
+  hidl_aptx_config.bitsPerSample =
+      to_hidl_bits_per_sample(aptx_config.bitsPerSample);
+  hidl_aptx_config.channelMode = to_hidl_channel_mode(aptx_config.channelMode);
+  return hidl_aptx_config;
+}
+
+inline CodecConfig_2_0 to_hidl_codec_config_2_0(
+    const CodecConfiguration& codec_config) {
+  CodecConfig_2_0 hidl_codec_config;
+  hidl_codec_config.codecType = to_hidl_codec_type_2_0(codec_config.codecType);
+  hidl_codec_config.encodedAudioBitrate =
+      static_cast<uint32_t>(codec_config.encodedAudioBitrate);
+  hidl_codec_config.peerMtu = static_cast<uint32_t>(codec_config.peerMtu);
+  hidl_codec_config.isScmstEnabled = codec_config.isScmstEnabled;
+  switch (codec_config.config.getTag()) {
+    case CodecConfiguration::CodecSpecific::sbcConfig:
+      hidl_codec_config.config.sbcConfig(to_hidl_sbc_config(
+          codec_config.config
+              .get<CodecConfiguration::CodecSpecific::sbcConfig>()));
+      break;
+    case CodecConfiguration::CodecSpecific::aacConfig:
+      hidl_codec_config.config.aacConfig(to_hidl_aac_config(
+          codec_config.config
+              .get<CodecConfiguration::CodecSpecific::aacConfig>()));
+      break;
+    case CodecConfiguration::CodecSpecific::ldacConfig:
+      hidl_codec_config.config.ldacConfig(to_hidl_ldac_config(
+          codec_config.config
+              .get<CodecConfiguration::CodecSpecific::ldacConfig>()));
+      break;
+    case CodecConfiguration::CodecSpecific::aptxConfig:
+      hidl_codec_config.config.aptxConfig(to_hidl_aptx_config(
+          codec_config.config
+              .get<CodecConfiguration::CodecSpecific::aptxConfig>()));
+      break;
+    default:
+      break;
+  }
+  return hidl_codec_config;
+}
+
+inline AudioConfig_2_0 to_hidl_audio_config_2_0(
+    const AudioConfiguration& audio_config) {
+  AudioConfig_2_0 hidl_audio_config;
+  if (audio_config.getTag() == AudioConfiguration::pcmConfig) {
+    hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_0(
+        audio_config.get<AudioConfiguration::pcmConfig>()));
+  } else if (audio_config.getTag() == AudioConfiguration::a2dpConfig) {
+    hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+        audio_config.get<AudioConfiguration::a2dpConfig>()));
+  }
+  return hidl_audio_config;
+}
+
+inline PcmConfig_2_1 to_hidl_pcm_config_2_1(
+    const PcmConfiguration& pcm_config) {
+  PcmConfig_2_1 hidl_pcm_config;
+  hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_1(pcm_config.sampleRateHz);
+  hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
+  hidl_pcm_config.bitsPerSample =
+      to_hidl_bits_per_sample(pcm_config.bitsPerSample);
+  hidl_pcm_config.dataIntervalUs =
+      static_cast<uint32_t>(pcm_config.dataIntervalUs);
+  return hidl_pcm_config;
+}
+
+inline Lc3Config_2_1 to_hidl_lc3_config_2_1(
+    const Lc3Configuration& lc3_config) {
+  Lc3Config_2_1 hidl_lc3_config;
+  hidl_lc3_config.pcmBitDepth = to_hidl_bits_per_sample(lc3_config.pcmBitDepth);
+  hidl_lc3_config.samplingFrequency =
+      to_hidl_sample_rate_2_1(lc3_config.samplingFrequencyHz);
+  if (lc3_config.samplingFrequencyHz == 10000)
+    hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_10000US;
+  else if (lc3_config.samplingFrequencyHz == 7500)
+    hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_7500US;
+  hidl_lc3_config.octetsPerFrame =
+      static_cast<uint32_t>(lc3_config.octetsPerFrame);
+  hidl_lc3_config.blocksPerSdu = static_cast<uint32_t>(lc3_config.blocksPerSdu);
+  return hidl_lc3_config;
+}
+
+inline Lc3CodecConfig_2_1 to_hidl_leaudio_config_2_1(
+    const LeAudioConfiguration& leaudio_config) {
+  Lc3CodecConfig_2_1 hidl_lc3_codec_config = {
+      .audioChannelAllocation = 0,
+  };
+  if (leaudio_config.modeConfig.getTag() ==
+      LeAudioConfiguration::LeAudioModeConfig::unicastConfig) {
+    auto& unicast_config =
+        leaudio_config.modeConfig
+            .get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
+    if (unicast_config.leAudioCodecConfig.getTag() ==
+        LeAudioCodecConfiguration::lc3Config) {
+      LOG(FATAL) << __func__ << ": unexpected codec type(vendor?)";
+    }
+    auto& le_codec_config = unicast_config.leAudioCodecConfig
+                                .get<LeAudioCodecConfiguration::lc3Config>();
+
+    hidl_lc3_codec_config.lc3Config = to_hidl_lc3_config_2_1(le_codec_config);
+
+    for (const auto& map : unicast_config.streamMap) {
+      hidl_lc3_codec_config.audioChannelAllocation |=
+          map.audioChannelAllocation;
+    }
+  } else {
+    // NOTE: Broadcast is not officially supported in HIDL
+    auto& bcast_config =
+        leaudio_config.modeConfig
+            .get<LeAudioConfiguration::LeAudioModeConfig::broadcastConfig>();
+    if (bcast_config.streamMap.empty()) {
+      return hidl_lc3_codec_config;
+    }
+    if (bcast_config.streamMap[0].leAudioCodecConfig.getTag() !=
+        LeAudioCodecConfiguration::lc3Config) {
+      LOG(FATAL) << __func__ << ": unexpected codec type(vendor?)";
+    }
+    auto& le_codec_config =
+        bcast_config.streamMap[0]
+            .leAudioCodecConfig.get<LeAudioCodecConfiguration::lc3Config>();
+    hidl_lc3_codec_config.lc3Config = to_hidl_lc3_config_2_1(le_codec_config);
+
+    for (const auto& map : bcast_config.streamMap) {
+      hidl_lc3_codec_config.audioChannelAllocation |=
+          map.audioChannelAllocation;
+    }
+  }
+
+  return hidl_lc3_codec_config;
+}
+
+inline LeAudioConfig_2_2 to_hidl_leaudio_config_2_2(
+    const LeAudioConfiguration& leaudio_config) {
+  LeAudioConfig_2_2 hidl_leaudio_config;
+
+  if (leaudio_config.modeConfig.getTag() ==
+      LeAudioConfiguration::LeAudioModeConfig::unicastConfig) {
+    hidl_leaudio_config.mode = LeAudioMode_2_2::UNICAST;
+    auto& unicast_config =
+        leaudio_config.modeConfig
+            .get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
+    ::android::hardware::bluetooth::audio::V2_2::UnicastConfig
+        hidl_unicast_config;
+    hidl_unicast_config.peerDelay =
+        static_cast<uint32_t>(unicast_config.peerDelay);
+
+    auto& lc3_config = unicast_config.leAudioCodecConfig
+                           .get<LeAudioCodecConfiguration::lc3Config>();
+    hidl_unicast_config.lc3Config = to_hidl_lc3_config_2_1(lc3_config);
+
+    hidl_unicast_config.streamMap.resize(unicast_config.streamMap.size());
+    for (int i = 0; i < unicast_config.streamMap.size(); i++) {
+      hidl_unicast_config.streamMap[i].audioChannelAllocation =
+          static_cast<uint32_t>(
+              unicast_config.streamMap[i].audioChannelAllocation);
+      hidl_unicast_config.streamMap[i].streamHandle =
+          static_cast<uint16_t>(unicast_config.streamMap[i].streamHandle);
+    }
+  } else if (leaudio_config.modeConfig.getTag() ==
+             LeAudioConfiguration::LeAudioModeConfig::broadcastConfig) {
+    hidl_leaudio_config.mode = LeAudioMode_2_2::BROADCAST;
+    auto bcast_config =
+        leaudio_config.modeConfig
+            .get<LeAudioConfiguration::LeAudioModeConfig::broadcastConfig>();
+    ::android::hardware::bluetooth::audio::V2_2::BroadcastConfig
+        hidl_bcast_config;
+    hidl_bcast_config.streamMap.resize(bcast_config.streamMap.size());
+    for (int i = 0; i < bcast_config.streamMap.size(); i++) {
+      hidl_bcast_config.streamMap[i].audioChannelAllocation =
+          static_cast<uint32_t>(
+              bcast_config.streamMap[i].audioChannelAllocation);
+      hidl_bcast_config.streamMap[i].streamHandle =
+          static_cast<uint16_t>(bcast_config.streamMap[i].streamHandle);
+      hidl_bcast_config.streamMap[i].lc3Config = to_hidl_lc3_config_2_1(
+          bcast_config.streamMap[i]
+              .leAudioCodecConfig.get<LeAudioCodecConfiguration::lc3Config>());
+    }
+  }
+  return hidl_leaudio_config;
+}
+
+inline AudioConfig_2_1 to_hidl_audio_config_2_1(
+    const AudioConfiguration& audio_config) {
+  AudioConfig_2_1 hidl_audio_config;
+  switch (audio_config.getTag()) {
+    case AudioConfiguration::pcmConfig:
+      hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
+          audio_config.get<AudioConfiguration::pcmConfig>()));
+      break;
+    case AudioConfiguration::a2dpConfig:
+      hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+          audio_config.get<AudioConfiguration::a2dpConfig>()));
+      break;
+    case AudioConfiguration::leAudioConfig:
+      hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_config_2_1(
+          audio_config.get<AudioConfiguration::leAudioConfig>()));
+      break;
+  }
+  return hidl_audio_config;
+}
+
+inline AudioConfig_2_2 to_hidl_audio_config_2_2(
+    const AudioConfiguration& audio_config) {
+  AudioConfig_2_2 hidl_audio_config;
+  switch (audio_config.getTag()) {
+    case AudioConfiguration::pcmConfig:
+      hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
+          audio_config.get<AudioConfiguration::pcmConfig>()));
+      break;
+    case AudioConfiguration::a2dpConfig:
+      hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+          audio_config.get<AudioConfiguration::a2dpConfig>()));
+      break;
+    case AudioConfiguration::leAudioConfig:
+      hidl_audio_config.leAudioConfig(to_hidl_leaudio_config_2_2(
+          audio_config.get<AudioConfiguration::leAudioConfig>()));
+      break;
+  }
+  return hidl_audio_config;
+}
+
+/***
+ *
+ * 2.0
+ *
+ ***/
+
+bool HidlToAidlMiddleware_2_0::IsSessionReady(
+    const SessionType_2_0& session_type) {
+  return BluetoothAudioSessionControl::IsSessionReady(
+      from_session_type_2_0(session_type));
+}
+
+uint16_t HidlToAidlMiddleware_2_0::RegisterControlResultCback(
+    const SessionType_2_0& session_type,
+    const PortStatusCallbacks_2_0& cbacks) {
+  PortStatusCallbacks_2_2 callback_2_2{
+      .control_result_cb_ = cbacks.control_result_cb_,
+      .session_changed_cb_ = cbacks.session_changed_cb_,
+  };
+  return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+      static_cast<SessionType_2_1>(session_type), callback_2_2);
+}
+
+void HidlToAidlMiddleware_2_0::UnregisterControlResultCback(
+    const SessionType_2_0& session_type, uint16_t cookie) {
+  HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+      static_cast<SessionType_2_1>(session_type), cookie);
+}
+
+const AudioConfig_2_0 HidlToAidlMiddleware_2_0::GetAudioConfig(
+    const SessionType_2_0& session_type) {
+  return to_hidl_audio_config_2_0(BluetoothAudioSessionControl::GetAudioConfig(
+      from_session_type_2_0(session_type)));
+}
+
+bool HidlToAidlMiddleware_2_0::StartStream(
+    const SessionType_2_0& session_type) {
+  return BluetoothAudioSessionControl::StartStream(
+      from_session_type_2_0(session_type));
+}
+
+void HidlToAidlMiddleware_2_0::StopStream(const SessionType_2_0& session_type) {
+  return BluetoothAudioSessionControl::StopStream(
+      from_session_type_2_0(session_type));
+}
+
+bool HidlToAidlMiddleware_2_0::SuspendStream(
+    const SessionType_2_0& session_type) {
+  return BluetoothAudioSessionControl::SuspendStream(
+      from_session_type_2_0(session_type));
+}
+
+bool HidlToAidlMiddleware_2_0::GetPresentationPosition(
+    const SessionType_2_0& session_type, uint64_t* remote_delay_report_ns,
+    uint64_t* total_bytes_readed, timespec* data_position) {
+  PresentationPosition presentation_position;
+  auto ret_val = BluetoothAudioSessionControl::GetPresentationPosition(
+      from_session_type_2_0(session_type), presentation_position);
+  if (remote_delay_report_ns)
+    *remote_delay_report_ns = presentation_position.remoteDeviceAudioDelayNanos;
+  if (total_bytes_readed)
+    *total_bytes_readed = presentation_position.transmittedOctets;
+  if (data_position)
+    *data_position = {
+        .tv_sec = static_cast<__kernel_old_time_t>(
+            presentation_position.transmittedOctetsTimestamp.tvSec),
+        .tv_nsec = static_cast<long>(
+            presentation_position.transmittedOctetsTimestamp.tvNSec)};
+  return ret_val;
+}
+
+void HidlToAidlMiddleware_2_0::UpdateTracksMetadata(
+    const SessionType_2_0& session_type,
+    const struct source_metadata* source_metadata) {
+  return BluetoothAudioSessionControl::UpdateSourceMetadata(
+      from_session_type_2_0(session_type), *source_metadata);
+}
+
+size_t HidlToAidlMiddleware_2_0::OutWritePcmData(
+    const SessionType_2_0& session_type, const void* buffer, size_t bytes) {
+  return BluetoothAudioSessionControl::OutWritePcmData(
+      from_session_type_2_0(session_type), buffer, bytes);
+}
+
+size_t HidlToAidlMiddleware_2_0::InReadPcmData(
+    const SessionType_2_0& session_type, void* buffer, size_t bytes) {
+  return BluetoothAudioSessionControl::InReadPcmData(
+      from_session_type_2_0(session_type), buffer, bytes);
+}
+
+bool HidlToAidlMiddleware_2_0::IsAidlAvailable() {
+  return BluetoothAudioSession::IsAidlAvailable();
+}
+
+/***
+ *
+ * 2.1
+ *
+ ***/
+
+const AudioConfig_2_1 HidlToAidlMiddleware_2_1::GetAudioConfig(
+    const SessionType_2_1& session_type) {
+  return to_hidl_audio_config_2_1(BluetoothAudioSessionControl::GetAudioConfig(
+      from_session_type_2_1(session_type)));
+}
+
+/***
+ *
+ * 2.2
+ *
+ ***/
+
+bool HidlToAidlMiddleware_2_2::IsSessionReady(
+    const SessionType_2_1& session_type) {
+  return BluetoothAudioSessionControl::IsSessionReady(
+      from_session_type_2_1(session_type));
+}
+
+uint16_t HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+    const SessionType_2_1& session_type,
+    const PortStatusCallbacks_2_2& cbacks) {
+  LOG(INFO) << __func__ << ": " << toString(session_type);
+  auto aidl_session_type = from_session_type_2_1(session_type);
+  // Pass the exact reference to the lambda
+  auto& session_legacy_callback_table =
+      legacy_callback_table[aidl_session_type];
+  PortStatusCallbacks aidl_callbacks{};
+  if (cbacks.control_result_cb_) {
+    aidl_callbacks.control_result_cb_ =
+        [&session_legacy_callback_table](uint16_t cookie, bool start_resp,
+                                         const BluetoothAudioStatus& status) {
+          if (session_legacy_callback_table.find(cookie) ==
+              session_legacy_callback_table.end()) {
+            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+            return;
+          }
+          auto& cback = session_legacy_callback_table[cookie];
+          cback->control_result_cb_(cookie, start_resp, to_hidl_status(status));
+        };
+  }
+  if (cbacks.session_changed_cb_) {
+    aidl_callbacks.session_changed_cb_ =
+        [&session_legacy_callback_table](uint16_t cookie) {
+          if (session_legacy_callback_table.find(cookie) ==
+              session_legacy_callback_table.end()) {
+            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+            return;
+          }
+          auto& cback = session_legacy_callback_table[cookie];
+          cback->session_changed_cb_(cookie);
+        };
+  };
+  if (cbacks.audio_configuration_changed_cb_) {
+    aidl_callbacks.audio_configuration_changed_cb_ =
+        [&session_legacy_callback_table](uint16_t cookie) {
+          if (session_legacy_callback_table.find(cookie) ==
+              session_legacy_callback_table.end()) {
+            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+            return;
+          }
+          auto& cback = session_legacy_callback_table[cookie];
+          cback->audio_configuration_changed_cb_(cookie);
+        };
+  };
+  auto cookie = BluetoothAudioSessionControl::RegisterControlResultCback(
+      aidl_session_type, aidl_callbacks);
+  {
+    std::lock_guard<std::mutex> guard(legacy_callback_lock);
+    session_legacy_callback_table[cookie] =
+        std::make_shared<PortStatusCallbacks_2_2>(cbacks);
+  }
+  return cookie;
+}
+
+void HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+    const SessionType_2_1& session_type, uint16_t cookie) {
+  LOG(INFO) << __func__ << ": " << toString(session_type);
+  auto aidl_session_type = from_session_type_2_1(session_type);
+  BluetoothAudioSessionControl::UnregisterControlResultCback(aidl_session_type,
+                                                             cookie);
+  auto& session_callback_table = legacy_callback_table[aidl_session_type];
+  if (session_callback_table.find(cookie) != session_callback_table.end()) {
+    std::lock_guard<std::mutex> guard(legacy_callback_lock);
+    session_callback_table.erase(cookie);
+  }
+}
+
+const AudioConfig_2_2 HidlToAidlMiddleware_2_2::GetAudioConfig(
+    const SessionType_2_1& session_type) {
+  return to_hidl_audio_config_2_2(BluetoothAudioSessionControl::GetAudioConfig(
+      from_session_type_2_1(session_type)));
+}
+
+bool HidlToAidlMiddleware_2_2::StartStream(
+    const SessionType_2_1& session_type) {
+  return BluetoothAudioSessionControl::StartStream(
+      from_session_type_2_1(session_type));
+}
+
+bool HidlToAidlMiddleware_2_2::SuspendStream(
+    const SessionType_2_1& session_type) {
+  return BluetoothAudioSessionControl::SuspendStream(
+      from_session_type_2_1(session_type));
+}
+
+void HidlToAidlMiddleware_2_2::StopStream(const SessionType_2_1& session_type) {
+  return BluetoothAudioSessionControl::StopStream(
+      from_session_type_2_1(session_type));
+}
+
+void HidlToAidlMiddleware_2_2::UpdateTracksMetadata(
+    const SessionType_2_1& session_type,
+    const struct source_metadata* source_metadata) {
+  return BluetoothAudioSessionControl::UpdateSourceMetadata(
+      from_session_type_2_1(session_type), *source_metadata);
+}
+
+void HidlToAidlMiddleware_2_2::UpdateSinkMetadata(
+    const SessionType_2_1& session_type,
+    const struct sink_metadata* sink_metadata) {
+  return BluetoothAudioSessionControl::UpdateSinkMetadata(
+      from_session_type_2_1(session_type), *sink_metadata);
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h
new file mode 100644
index 0000000..b124d8f
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.0/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::SessionType;
+using PortStatusCallbacks_2_0 =
+    ::android::bluetooth::audio::PortStatusCallbacks;
+using AudioConfig_2_0 =
+    ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_0 {
+ public:
+  static bool IsAidlAvailable();
+
+  static bool IsSessionReady(const SessionType_2_0& session_type);
+
+  static uint16_t RegisterControlResultCback(
+      const SessionType_2_0& session_type,
+      const PortStatusCallbacks_2_0& cbacks);
+
+  static void UnregisterControlResultCback(const SessionType_2_0& session_type,
+                                           uint16_t cookie);
+
+  static const AudioConfig_2_0 GetAudioConfig(
+      const SessionType_2_0& session_type);
+
+  static bool StartStream(const SessionType_2_0& session_type);
+
+  static void StopStream(const SessionType_2_0& session_type);
+
+  static bool SuspendStream(const SessionType_2_0& session_type);
+
+  static bool GetPresentationPosition(const SessionType_2_0& session_type,
+                                      uint64_t* remote_delay_report_ns,
+                                      uint64_t* total_bytes_readed,
+                                      timespec* data_position);
+
+  static void UpdateTracksMetadata(
+      const SessionType_2_0& session_type,
+      const struct source_metadata* source_metadata);
+
+  static size_t OutWritePcmData(const SessionType_2_0& session_type,
+                                const void* buffer, size_t bytes);
+
+  static size_t InReadPcmData(const SessionType_2_0& session_type, void* buffer,
+                              size_t bytes);
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h
new file mode 100644
index 0000000..82dce96
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.1/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::SessionType;
+using AudioConfig_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_1 {
+ public:
+  static const AudioConfig_2_1 GetAudioConfig(
+      const SessionType_2_1& session_type);
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
new file mode 100644
index 0000000..f6c3e5c
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.2/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+#include "../session/BluetoothAudioSession_2_2.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::SessionType;
+using PortStatusCallbacks_2_0 =
+    ::android::bluetooth::audio::PortStatusCallbacks;
+using PortStatusCallbacks_2_2 =
+    ::android::bluetooth::audio::PortStatusCallbacks_2_2;
+using AudioConfig_2_2 =
+    ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_2 {
+ public:
+  static bool IsSessionReady(const SessionType_2_1& session_type);
+
+  static uint16_t RegisterControlResultCback(
+      const SessionType_2_1& session_type,
+      const PortStatusCallbacks_2_2& cbacks);
+
+  static void UnregisterControlResultCback(const SessionType_2_1& session_type,
+                                           uint16_t cookie);
+
+  static const AudioConfig_2_2 GetAudioConfig(
+      const SessionType_2_1& session_type);
+
+  static bool StartStream(const SessionType_2_1& session_type);
+
+  static bool SuspendStream(const SessionType_2_1& session_type);
+
+  static void StopStream(const SessionType_2_1& session_type);
+
+  static void UpdateTracksMetadata(
+      const SessionType_2_1& session_type,
+      const struct source_metadata* source_metadata);
+
+  static void UpdateSinkMetadata(const SessionType_2_1& session_type,
+                                 const struct sink_metadata* sink_metadata);
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
index 2f3ddaf..283952e 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
@@ -21,10 +21,13 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+
 namespace android {
 namespace bluetooth {
 namespace audio {
 
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
 using ::android::hardware::audio::common::V5_0::AudioContentType;
 using ::android::hardware::audio::common::V5_0::AudioUsage;
 using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
@@ -149,6 +152,8 @@
 // The function helps to check if this session is ready or not
 // @return: true if the Bluetooth stack has started the specified session
 bool BluetoothAudioSession::IsSessionReady() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::IsSessionReady(session_type_);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   bool dataMQ_valid =
       (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
@@ -200,6 +205,9 @@
 // @return: cookie - the assigned number to this bluetooth_audio output
 uint16_t BluetoothAudioSession::RegisterStatusCback(
     const PortStatusCallbacks& cbacks) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::RegisterControlResultCback(session_type_,
+                                                                cbacks);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   uint16_t cookie = ObserversCookieGetInitValue(session_type_);
   uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
@@ -227,6 +235,9 @@
 // PortStatusCallbacks
 // @param: cookie - indicates which bluetooth_audio output is
 void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::UnregisterControlResultCback(session_type_,
+                                                                  cookie);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (observers_.erase(cookie) != 1) {
     LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
@@ -238,6 +249,9 @@
 // The control function is for the bluetooth_audio module to get the current
 // AudioConfiguration
 const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return (audio_config_ =
+                HidlToAidlMiddleware_2_0::GetAudioConfig(session_type_));
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (IsSessionReady()) {
     return audio_config_;
@@ -251,6 +265,8 @@
 // Those control functions are for the bluetooth_audio module to start, suspend,
 // stop stream, to check position, and to update metadata.
 bool BluetoothAudioSession::StartStream() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::StartStream(session_type_);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (!IsSessionReady()) {
     LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -267,6 +283,8 @@
 }
 
 bool BluetoothAudioSession::SuspendStream() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::SuspendStream(session_type_);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (!IsSessionReady()) {
     LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -283,6 +301,8 @@
 }
 
 void BluetoothAudioSession::StopStream() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::StopStream(session_type_);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (!IsSessionReady()) {
     return;
@@ -297,6 +317,10 @@
 bool BluetoothAudioSession::GetPresentationPosition(
     uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed,
     timespec* data_position) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::GetPresentationPosition(
+        session_type_, remote_delay_report_ns, total_bytes_readed,
+        data_position);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (!IsSessionReady()) {
     LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -330,6 +354,9 @@
 
 void BluetoothAudioSession::UpdateTracksMetadata(
     const struct source_metadata* source_metadata) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::UpdateTracksMetadata(session_type_,
+                                                          source_metadata);
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (!IsSessionReady()) {
     LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -374,6 +401,9 @@
 // The control function writes stream to FMQ
 size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
                                               size_t bytes) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::OutWritePcmData(session_type_, buffer,
+                                                     bytes);
   if (buffer == nullptr || !bytes) return 0;
   size_t totalWritten = 0;
   int ms_timeout = kFmqSendTimeoutMs;
@@ -407,6 +437,9 @@
 
 // The control function reads stream from FMQ
 size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_0::InReadPcmData(session_type_, buffer,
+                                                   bytes);
   if (buffer == nullptr || !bytes) return 0;
   size_t totalRead = 0;
   int ms_timeout = kFmqReceiveTimeoutMs;
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
index 95f7408..4d7be21 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
@@ -35,7 +35,7 @@
     std::shared_ptr<BluetoothAudioSession_2_1> session_ptr =
         BluetoothAudioSessionInstance_2_1::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      return session_ptr->IsSessionReady();
+      return session_ptr->GetAudioSession()->IsSessionReady();
     }
     return false;
   }
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
index e20914e..c270ef0 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
@@ -48,20 +48,38 @@
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      return session_ptr->GetAudioSession()->RegisterStatusCback(cbacks);
+      PortStatusCallbacks_2_2 cb = {
+          .control_result_cb_ = cbacks.control_result_cb_,
+          .session_changed_cb_ = cbacks.session_changed_cb_,
+          .audio_configuration_changed_cb_ = nullptr};
+      return session_ptr->RegisterStatusCback(cb);
+    }
+    return kObserversCookieUndefined;
+  }
+
+  // The control API helps the bluetooth_audio module to register
+  // PortStatusCallbacks_2_2
+  // @return: cookie - the assigned number to this bluetooth_audio output
+  static uint16_t RegisterControlResultCback(
+      const SessionType_2_1& session_type,
+      const PortStatusCallbacks_2_2& cbacks) {
+    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
+        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->RegisterStatusCback(cbacks);
     }
     return kObserversCookieUndefined;
   }
 
   // The control API helps the bluetooth_audio module to unregister
-  // PortStatusCallbacks
+  // PortStatusCallbacks and PortStatusCallbacks_2_2
   // @param: cookie - indicates which bluetooth_audio output is
   static void UnregisterControlResultCback(const SessionType_2_1& session_type,
                                            uint16_t cookie) {
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      session_ptr->GetAudioSession()->UnregisterStatusCback(cookie);
+      session_ptr->UnregisterStatusCback(cookie);
     }
   }
 
@@ -76,6 +94,12 @@
     } else if (session_type ==
                SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
       return BluetoothAudioSession_2_2::kInvalidOffloadAudioConfiguration;
+    } else if (
+        session_type ==
+            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+        session_type ==
+            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+      return BluetoothAudioSession_2_2::kInvalidLeOffloadAudioConfiguration;
     } else {
       return BluetoothAudioSession_2_2::kInvalidSoftwareAudioConfiguration;
     }
@@ -87,7 +111,7 @@
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      return session_ptr->GetAudioSession()->StartStream();
+      return session_ptr->StartStream();
     }
     return false;
   }
@@ -96,7 +120,7 @@
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      return session_ptr->GetAudioSession()->SuspendStream();
+      return session_ptr->SuspendStream();
     }
     return false;
   }
@@ -105,7 +129,7 @@
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      session_ptr->GetAudioSession()->StopStream();
+      session_ptr->StopStream();
     }
   }
 
@@ -128,7 +152,16 @@
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      session_ptr->GetAudioSession()->UpdateTracksMetadata(source_metadata);
+      session_ptr->UpdateTracksMetadata(source_metadata);
+    }
+  }
+
+  static void UpdateSinkMetadata(const SessionType_2_1& session_type,
+                                 const struct sink_metadata* sink_metadata) {
+    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
+        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UpdateSinkMetadata(sink_metadata);
     }
   }
 
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h
index 194259a..17e140e 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h
@@ -48,7 +48,7 @@
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      session_ptr->GetAudioSession()->OnSessionEnded();
+      session_ptr->OnSessionEnded();
     }
   }
   // The API reports the Bluetooth stack has replied the result of startStream
@@ -60,7 +60,20 @@
     std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
         BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      session_ptr->GetAudioSession()->ReportControlStatus(start_resp, status);
+      session_ptr->ReportControlStatus(start_resp, status);
+    }
+  }
+  // The API reports the Bluetooth stack has replied the changed of the audio
+  // configuration, and will inform registered bluetooth_audio outputs
+  static void ReportAudioConfigChanged(
+      const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+          session_type,
+      const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
+          audio_config) {
+    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
+        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->ReportAudioConfigChanged(audio_config);
     }
   }
 };
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
index c250ef1..276a291 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
@@ -21,9 +21,14 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+#include "../aidl_session/HidlToAidlMiddleware_2_1.h"
+
 namespace android {
 namespace bluetooth {
 namespace audio {
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_1;
 using SessionType_2_1 =
     ::android::hardware::bluetooth::audio::V2_1::SessionType;
 using SessionType_2_0 =
@@ -46,6 +51,19 @@
     return false;
   }
 }
+
+bool is_unsupported_2_1_session_type(
+    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+        session_type) {
+  if (session_type ==
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+      session_type ==
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return true;
+  } else {
+    return false;
+  }
+}
 }  // namespace
 
 BluetoothAudioSession_2_1::BluetoothAudioSession_2_1(
@@ -53,21 +71,13 @@
         session_type)
     : audio_session(BluetoothAudioSessionInstance::GetSessionInstance(
           static_cast<SessionType_2_0>(session_type))) {
-  if (is_2_0_session_type(session_type)) {
+  if (is_2_0_session_type(session_type) ||
+      is_unsupported_2_1_session_type(session_type)) {
     session_type_2_1_ = (SessionType_2_1::UNKNOWN);
   } else {
     session_type_2_1_ = (session_type);
   }
-}
-
-bool BluetoothAudioSession_2_1::IsSessionReady() {
-  if (session_type_2_1_ !=
-      SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
-    return audio_session->IsSessionReady();
-  }
-
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  return audio_session->stack_iface_ != nullptr;
+  raw_session_type_ = session_type;
 }
 
 std::shared_ptr<BluetoothAudioSession>
@@ -79,8 +89,10 @@
 // AudioConfiguration
 const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
 BluetoothAudioSession_2_1::GetAudioConfig() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_1::GetAudioConfig(raw_session_type_);
   std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (IsSessionReady()) {
+  if (audio_session->IsSessionReady()) {
     // If session is unknown it means it should be 2.0 type
     if (session_type_2_1_ != SessionType_2_1::UNKNOWN)
       return audio_config_2_1_;
@@ -90,7 +102,7 @@
     // pcmConfig only differs between 2.0 and 2.1 in AudioConfiguration
     if (fromConf.getDiscriminator() ==
         AudioConfiguration::hidl_discriminator::codecConfig) {
-      toConf.codecConfig() = fromConf.codecConfig();
+      toConf.codecConfig(fromConf.codecConfig());
     } else {
       toConf.pcmConfig() = {
           .sampleRate = static_cast<
@@ -122,9 +134,6 @@
            SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
   bool is_offload_a2dp_session =
       (session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH);
-  bool is_offload_le_audio_session =
-      (session_type_2_1_ == SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
-       session_type_2_1_ == SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
   auto audio_config_discriminator = audio_config.getDiscriminator();
   bool is_software_audio_config =
       (is_software_session &&
@@ -136,13 +145,7 @@
        audio_config_discriminator ==
            ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
                hidl_discriminator::codecConfig);
-  bool is_le_audio_offload_audio_config =
-      (is_offload_le_audio_session &&
-       audio_config_discriminator ==
-           ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
-               hidl_discriminator::leAudioCodecConfig);
-  if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
-      !is_le_audio_offload_audio_config) {
+  if (!is_software_audio_config && !is_a2dp_offload_audio_config) {
     return false;
   }
   audio_config_2_1_ = audio_config;
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
index db82c73..e634064 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
@@ -31,6 +31,7 @@
   std::shared_ptr<BluetoothAudioSession> audio_session;
 
   ::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
+  ::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
 
   // audio data configuration for both software and offloading
   ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
@@ -50,10 +51,6 @@
       const ::android::hardware::bluetooth::audio::V2_1::SessionType&
           session_type);
 
-  // The function helps to check if this session is ready or not
-  // @return: true if the Bluetooth stack has started the specified session
-  bool IsSessionReady();
-
   std::shared_ptr<BluetoothAudioSession> GetAudioSession();
 
   // The report function is used to report that the Bluetooth stack has started
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
index 5a6b2e7..ceb0662 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
@@ -20,10 +20,32 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioPort.h>
+
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+#include "../aidl_session/HidlToAidlMiddleware_2_2.h"
 
 namespace android {
 namespace bluetooth {
 namespace audio {
+
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_2;
+using ::android::hardware::audio::common::V5_0::AudioContentType;
+using ::android::hardware::audio::common::V5_0::AudioSource;
+using ::android::hardware::audio::common::V5_0::AudioUsage;
+using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
+using ::android::hardware::audio::common::V5_0::RecordTrackMetadata;
+using ::android::hardware::audio::common::V5_0::SinkMetadata;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
+using ::android::hardware::bluetooth::audio::V2_2::LeAudioMode;
+using PcmParameters_2_1 =
+    ::android::hardware::bluetooth::audio::V2_1::PcmParameters;
+using SampleRate_2_1 = ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
 using SessionType_2_1 =
     ::android::hardware::bluetooth::audio::V2_1::SessionType;
 using SessionType_2_0 =
@@ -32,10 +54,27 @@
 using AudioConfiguration_2_1 =
     ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
 
+static constexpr PcmParameters_2_1 kInvalidPcmParameters = {
+    .sampleRate = SampleRate_2_1::RATE_UNKNOWN,
+    .channelMode = ChannelMode::UNKNOWN,
+    .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
+    .dataIntervalUs = 0,
+};
+
+static LeAudioConfiguration kInvalidLeAudioConfig = {
+    .mode = LeAudioMode::UNKNOWN,
+    .config = {},
+};
+
 ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
     BluetoothAudioSession_2_2::invalidSoftwareAudioConfiguration = {};
 ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
     BluetoothAudioSession_2_2::invalidOffloadAudioConfiguration = {};
+::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+    BluetoothAudioSession_2_2::invalidLeOffloadAudioConfiguration = {};
+
+using IBluetoothAudioPort_2_2 =
+    ::android::hardware::bluetooth::audio::V2_2::IBluetoothAudioPort;
 
 namespace {
 bool is_2_0_session_type(
@@ -63,11 +102,20 @@
   } else {
     session_type_2_1_ = (session_type);
   }
+  raw_session_type_ = session_type;
+  invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
+  invalidOffloadAudioConfiguration.codecConfig(
+      audio_session->kInvalidCodecConfiguration);
+  invalidLeOffloadAudioConfiguration.leAudioConfig(kInvalidLeAudioConfig);
 }
 
 bool BluetoothAudioSession_2_2::IsSessionReady() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::IsSessionReady(raw_session_type_);
   if (session_type_2_1_ !=
-      SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
     return audio_session->IsSessionReady();
   }
 
@@ -84,15 +132,123 @@
   return audio_session_2_1;
 }
 
+void BluetoothAudioSession_2_2::UpdateTracksMetadata(
+    const struct source_metadata* source_metadata) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::UpdateTracksMetadata(raw_session_type_,
+                                                          source_metadata);
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+               << " has NO session";
+    return;
+  }
+
+  ssize_t track_count = source_metadata->track_count;
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+            << ", " << track_count << " track(s)";
+
+  if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
+    audio_session->UpdateTracksMetadata(source_metadata);
+    return;
+  }
+
+  struct playback_track_metadata* track = source_metadata->tracks;
+  SourceMetadata sourceMetadata;
+  PlaybackTrackMetadata* halMetadata;
+
+  sourceMetadata.tracks.resize(track_count);
+  halMetadata = sourceMetadata.tracks.data();
+  while (track_count && track) {
+    halMetadata->usage = static_cast<AudioUsage>(track->usage);
+    halMetadata->contentType =
+        static_cast<AudioContentType>(track->content_type);
+    halMetadata->gain = track->gain;
+    LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+                 << ", usage=" << toString(halMetadata->usage)
+                 << ", content=" << toString(halMetadata->contentType)
+                 << ", gain=" << halMetadata->gain;
+    --track_count;
+    ++track;
+    ++halMetadata;
+  }
+  auto hal_retval = audio_session->stack_iface_->updateMetadata(sourceMetadata);
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_2_1_) << " failed";
+  }
+}
+
+void BluetoothAudioSession_2_2::UpdateSinkMetadata(
+    const struct sink_metadata* sink_metadata) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::UpdateSinkMetadata(raw_session_type_,
+                                                        sink_metadata);
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+               << " has NO session";
+    return;
+  }
+
+  ssize_t track_count = sink_metadata->track_count;
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+            << ", " << track_count << " track(s)";
+  if (session_type_2_1_ == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+      session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    return;
+  }
+
+  struct record_track_metadata* track = sink_metadata->tracks;
+  SinkMetadata sinkMetadata;
+  RecordTrackMetadata* halMetadata;
+
+  sinkMetadata.tracks.resize(track_count);
+  halMetadata = sinkMetadata.tracks.data();
+  while (track_count && track) {
+    halMetadata->source = static_cast<AudioSource>(track->source);
+    halMetadata->gain = track->gain;
+    // halMetadata->destination leave unspecified
+    LOG(INFO) << __func__
+              << " - SessionType=" << toString(GetAudioSession()->session_type_)
+              << ", source=" << track->source
+              << ", dest_device=" << track->dest_device
+              << ", gain=" << track->gain
+              << ", dest_device_address=" << track->dest_device_address;
+    --track_count;
+    ++track;
+    ++halMetadata;
+  }
+
+  /* This is called just for 2.2 sessions, so it's safe to do this casting*/
+  IBluetoothAudioPort_2_2* stack_iface_2_2_ =
+      static_cast<IBluetoothAudioPort_2_2*>(audio_session->stack_iface_.get());
+  auto hal_retval = stack_iface_2_2_->updateSinkMetadata(sinkMetadata);
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_2_1_) << " failed";
+  }
+}
+
 // The control function is for the bluetooth_audio module to get the current
 // AudioConfiguration
 const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
 BluetoothAudioSession_2_2::GetAudioConfig() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::GetAudioConfig(raw_session_type_);
   std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
   if (IsSessionReady()) {
+    auto audio_config_discriminator = audio_config_2_2_.getDiscriminator();
     // If session is unknown it means it should be 2.0 type
     if (session_type_2_1_ != SessionType_2_1::UNKNOWN) {
-      if (audio_config_2_2_ != invalidSoftwareAudioConfiguration)
+      if ((audio_config_discriminator ==
+               ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
+                   hidl_discriminator::pcmConfig &&
+           audio_config_2_2_ != kInvalidSoftwareAudioConfiguration) ||
+          (audio_config_discriminator ==
+               ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
+                   hidl_discriminator::leAudioConfig &&
+           audio_config_2_2_ != kInvalidLeOffloadAudioConfiguration))
         return audio_config_2_2_;
 
       ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration toConf;
@@ -100,7 +256,7 @@
           GetAudioSession_2_1()->GetAudioConfig();
       if (fromConf.getDiscriminator() ==
           AudioConfiguration_2_1::hidl_discriminator::pcmConfig) {
-        toConf.pcmConfig() = fromConf.pcmConfig();
+        toConf.pcmConfig(fromConf.pcmConfig());
         return toConf;
       }
     }
@@ -110,7 +266,7 @@
     // pcmConfig only differs between 2.0 and 2.1 in AudioConfiguration
     if (fromConf.getDiscriminator() ==
         AudioConfiguration::hidl_discriminator::codecConfig) {
-      toConf.codecConfig() = fromConf.codecConfig();
+      toConf.codecConfig(fromConf.codecConfig());
     } else {
       toConf.pcmConfig() = {
           .sampleRate = static_cast<
@@ -122,13 +278,67 @@
     }
     return toConf;
   } else if (session_type_2_1_ ==
-             SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
-    return kInvalidOffloadAudioConfiguration;
+                 SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+             session_type_2_1_ ==
+                 SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return kInvalidLeOffloadAudioConfiguration;
   } else {
     return kInvalidSoftwareAudioConfiguration;
   }
 }
 
+// Those control functions are for the bluetooth_audio module to start, suspend,
+// stop stream, to check position, and to update metadata.
+bool BluetoothAudioSession_2_2::StartStream() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::StartStream(raw_session_type_);
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = audio_session->stack_iface_->startStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_2_1_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+bool BluetoothAudioSession_2_2::SuspendStream() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::SuspendStream(raw_session_type_);
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = audio_session->stack_iface_->suspendStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_2_1_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+void BluetoothAudioSession_2_2::StopStream() {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::StopStream(raw_session_type_);
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  if (!IsSessionReady()) {
+    return;
+  }
+  auto hal_retval = audio_session->stack_iface_->stopStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_2_1_) << " failed";
+  }
+}
+
 bool BluetoothAudioSession_2_2::UpdateAudioConfig(
     const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
         audio_config) {
@@ -209,18 +419,196 @@
       LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
                  << " DataMQ Invalid";
       audio_config_2_2_ =
-          (session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH
-               ? kInvalidOffloadAudioConfiguration
+          ((session_type_2_1_ ==
+                SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+            session_type_2_1_ ==
+                SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH)
+               ? kInvalidLeOffloadAudioConfiguration
                : kInvalidSoftwareAudioConfiguration);
     } else {
       audio_session->stack_iface_ = stack_iface;
       LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
                 << ", AudioConfiguration=" << toString(audio_config);
-      audio_session->ReportSessionStatus();
+      ReportSessionStatus();
     };
   }
 }
 
+// The report function is used to report that the Bluetooth stack has ended the
+// session, and will invoke session_changed_cb_ to notify registered
+// bluetooth_audio outputs
+void BluetoothAudioSession_2_2::OnSessionEnded() {
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  bool toggled = IsSessionReady();
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_);
+  if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
+    audio_session->OnSessionEnded();
+    return;
+  }
+
+  audio_config_2_2_ =
+      ((session_type_2_1_ ==
+            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+        session_type_2_1_ ==
+            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH)
+           ? kInvalidLeOffloadAudioConfiguration
+           : kInvalidSoftwareAudioConfiguration);
+  audio_session->stack_iface_ = nullptr;
+  audio_session->UpdateDataPath(nullptr);
+  if (toggled) {
+    ReportSessionStatus();
+  }
+}
+
+// The control function helps the bluetooth_audio module to register
+// PortStatusCallbacks_2_2
+// @return: cookie - the assigned number to this bluetooth_audio output
+uint16_t BluetoothAudioSession_2_2::RegisterStatusCback(
+    const PortStatusCallbacks_2_2& cbacks) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+        raw_session_type_, cbacks);
+  if (session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    PortStatusCallbacks cb = {
+        .control_result_cb_ = cbacks.control_result_cb_,
+        .session_changed_cb_ = cbacks.session_changed_cb_};
+    return audio_session->RegisterStatusCback(cb);
+  }
+
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  uint16_t cookie = ObserversCookieGetInitValue(session_type_2_1_);
+  uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_2_1_);
+
+  while (cookie < cookie_upper_bound) {
+    if (observers_.find(cookie) == observers_.end()) {
+      break;
+    }
+    ++cookie;
+  }
+  if (cookie >= cookie_upper_bound) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+               << " has " << observers_.size()
+               << " observers already (No Resource)";
+    return kObserversCookieUndefined;
+  }
+  std::shared_ptr<struct PortStatusCallbacks_2_2> cb =
+      std::make_shared<struct PortStatusCallbacks_2_2>();
+  *cb = cbacks;
+  observers_[cookie] = cb;
+  return cookie;
+}
+
+// The control function helps the bluetooth_audio module to unregister
+// PortStatusCallbacks_2_2
+// @param: cookie - indicates which bluetooth_audio output is
+void BluetoothAudioSession_2_2::UnregisterStatusCback(uint16_t cookie) {
+  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+    return HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+        raw_session_type_, cookie);
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  if (session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    audio_session->UnregisterStatusCback(cookie);
+    return;
+  }
+  if (observers_.erase(cookie) != 1) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+                 << " no such provider=0x"
+                 << android::base::StringPrintf("%04x", cookie);
+  }
+}
+
+// invoking the registered session_changed_cb_
+void BluetoothAudioSession_2_2::ReportSessionStatus() {
+  // This is locked already by OnSessionStarted / OnSessionEnded
+  if (session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    audio_session->ReportSessionStatus();
+    return;
+  }
+  if (observers_.empty()) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+              << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks_2_2> cb = observer.second;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+              << " notify to bluetooth_audio=0x"
+              << android::base::StringPrintf("%04x", cookie);
+    cb->session_changed_cb_(cookie);
+  }
+}
+
+// The report function is used to report that the Bluetooth stack has notified
+// the result of startStream or suspendStream, and will invoke
+// control_result_cb_ to notify registered bluetooth_audio outputs
+void BluetoothAudioSession_2_2::ReportControlStatus(
+    bool start_resp, const BluetoothAudioStatus& status) {
+  if (session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    audio_session->ReportControlStatus(start_resp, status);
+    return;
+  }
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  if (observers_.empty()) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+                 << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks_2_2> cb = observer.second;
+    LOG(INFO) << __func__ << " - status=" << toString(status)
+              << " for SessionType=" << toString(session_type_2_1_)
+              << ", bluetooth_audio=0x"
+              << android::base::StringPrintf("%04x", cookie)
+              << (start_resp ? " started" : " suspended");
+    cb->control_result_cb_(cookie, start_resp, status);
+  }
+}
+
+// The report function is used to report that the Bluetooth stack has notified
+// the result of startStream or suspendStream, and will invoke
+// control_result_cb_ to notify registered bluetooth_audio outputs
+void BluetoothAudioSession_2_2::ReportAudioConfigChanged(
+    const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
+        audio_config) {
+  if (session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type_2_1_ !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return;
+  }
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  audio_config_2_2_ = audio_config;
+  if (observers_.empty()) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+                 << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks_2_2> cb = observer.second;
+    LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_2_1_)
+              << ", bluetooth_audio=0x"
+              << android::base::StringPrintf("%04x", cookie);
+    if (cb->audio_configuration_changed_cb_ != nullptr) {
+      cb->audio_configuration_changed_cb_(cookie);
+    }
+  }
+}
+
 std::unique_ptr<BluetoothAudioSessionInstance_2_2>
     BluetoothAudioSessionInstance_2_2::instance_ptr =
         std::unique_ptr<BluetoothAudioSessionInstance_2_2>(
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
index 7213ede..e04ad80 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
@@ -28,12 +28,47 @@
 namespace bluetooth {
 namespace audio {
 
+inline uint16_t ObserversCookieGetInitValue(
+    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+        session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
+}
+inline uint16_t ObserversCookieGetUpperBound(
+    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+        session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
+         kObserversCookieSize;
+}
+
+struct PortStatusCallbacks_2_2 {
+  // control_result_cb_ - when the Bluetooth stack reports results of
+  // streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
+  // this callback to report to the bluetooth_audio module.
+  // @param: cookie - indicates which bluetooth_audio output should handle
+  // @param: start_resp - this report is for startStream or not
+  // @param: status - the result of startStream
+  std::function<void(uint16_t cookie, bool start_resp,
+                     const BluetoothAudioStatus& status)>
+      control_result_cb_;
+  // session_changed_cb_ - when the Bluetooth stack start / end session, the
+  // BluetoothAudioProvider will invoke this callback to notify to the
+  // bluetooth_audio module.
+  // @param: cookie - indicates which bluetooth_audio output should handle
+  std::function<void(uint16_t cookie)> session_changed_cb_;
+  // audio_configuration_changed_cb_ - when the Bluetooth stack change the audio
+  // configuration, the BluetoothAudioProvider will invoke this callback to
+  // notify to the bluetooth_audio module.
+  // @param: cookie - indicates which bluetooth_audio output should handle
+  std::function<void(uint16_t cookie)> audio_configuration_changed_cb_;
+};
+
 class BluetoothAudioSession_2_2 {
  private:
   std::shared_ptr<BluetoothAudioSession> audio_session;
   std::shared_ptr<BluetoothAudioSession_2_1> audio_session_2_1;
 
   ::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
+  ::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
 
   // audio data configuration for both software and offloading
   ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
@@ -47,6 +82,15 @@
       invalidSoftwareAudioConfiguration;
   static ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
       invalidOffloadAudioConfiguration;
+  static ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
+      invalidLeOffloadAudioConfiguration;
+
+  // saving those registered bluetooth_audio's callbacks
+  std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks_2_2>>
+      observers_;
+
+  // invoking the registered session_changed_cb_
+  void ReportSessionStatus();
 
  public:
   BluetoothAudioSession_2_2(
@@ -69,17 +113,57 @@
       const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
           audio_config);
 
+  // The report function is used to report that the Bluetooth stack has ended
+  // the session, and will invoke session_changed_cb_ to notify registered
+  // bluetooth_audio outputs
+  void OnSessionEnded();
+
+  // Those control functions are for the bluetooth_audio module to start,
+  // suspend, stop stream, to check position, and to update metadata.
+  bool StartStream();
+  bool SuspendStream();
+  void StopStream();
+
+  // The control function helps the bluetooth_audio module to register
+  // PortStatusCallbacks_2_2
+  // @return: cookie - the assigned number to this bluetooth_audio output
+  uint16_t RegisterStatusCback(const PortStatusCallbacks_2_2& cbacks);
+
+  // The control function helps the bluetooth_audio module to unregister
+  // PortStatusCallbacks_2_2
+  // @param: cookie - indicates which bluetooth_audio output is
+  void UnregisterStatusCback(uint16_t cookie);
+
+  // The report function is used to report that the Bluetooth stack has notified
+  // the result of startStream or suspendStream, and will invoke
+  // control_result_cb_ to notify registered bluetooth_audio outputs
+  void ReportControlStatus(bool start_resp, const BluetoothAudioStatus& status);
+
+  // The report function is used to report that the Bluetooth stack has notified
+  // the audio configuration changed, and will invoke
+  // audio_configuration_changed_cb_ to notify registered bluetooth_audio
+  // outputs
+  void ReportAudioConfigChanged(
+      const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
+          audio_config);
+
   // The control function is for the bluetooth_audio module to get the current
   // AudioConfiguration
   const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
   GetAudioConfig();
 
+  void UpdateTracksMetadata(const struct source_metadata* source_metadata);
+  void UpdateSinkMetadata(const struct sink_metadata* sink_metadata);
+
   static constexpr ::android::hardware::bluetooth::audio::V2_2::
       AudioConfiguration& kInvalidSoftwareAudioConfiguration =
           invalidSoftwareAudioConfiguration;
   static constexpr ::android::hardware::bluetooth::audio::V2_2::
       AudioConfiguration& kInvalidOffloadAudioConfiguration =
           invalidOffloadAudioConfiguration;
+  static constexpr ::android::hardware::bluetooth::audio::V2_2::
+      AudioConfiguration& kInvalidLeOffloadAudioConfiguration =
+          invalidLeOffloadAudioConfiguration;
 };
 
 class BluetoothAudioSessionInstance_2_2 {
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp
index 5becdaa..4c99b0f 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp
@@ -24,9 +24,63 @@
 namespace bluetooth {
 namespace audio {
 
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_1::CodecType;
+using ::android::hardware::bluetooth::audio::V2_1::Lc3FrameDuration;
+using ::android::hardware::bluetooth::audio::V2_1::Lc3Parameters;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_2::AudioLocation;
+using ::android::hardware::bluetooth::audio::V2_2::BroadcastCapability;
+using ::android::hardware::bluetooth::audio::V2_2::
+    LeAudioCodecCapabilitiesSetting;
+using ::android::hardware::bluetooth::audio::V2_2::UnicastCapability;
 using SessionType_2_1 =
     ::android::hardware::bluetooth::audio::V2_1::SessionType;
 
+// Stores the list of offload supported capability
+std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
+
+static const UnicastCapability kInvalidUnicastCapability = {
+    .codecType = CodecType::UNKNOWN};
+
+static const BroadcastCapability kInvalidBroadcastCapability = {
+    .codecType = CodecType::UNKNOWN};
+
+// Default Supported Codecs
+// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30
+static const Lc3Parameters kLc3Capability_16_1 = {
+    .samplingFrequency = SampleRate::RATE_16000,
+    .frameDuration = Lc3FrameDuration::DURATION_7500US,
+    .octetsPerFrame = 30};
+
+// Default Supported Codecs
+// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
+static const Lc3Parameters kLc3Capability_16_2 = {
+    .samplingFrequency = SampleRate::RATE_16000,
+    .frameDuration = Lc3FrameDuration::DURATION_10000US,
+    .octetsPerFrame = 40};
+
+// Default Supported Codecs
+// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
+static const Lc3Parameters kLc3Capability_48_4 = {
+    .samplingFrequency = SampleRate::RATE_48000,
+    .frameDuration = Lc3FrameDuration::DURATION_10000US,
+    .octetsPerFrame = 120};
+
+static const std::vector<Lc3Parameters> supportedLc3CapabilityList = {
+    kLc3Capability_48_4, kLc3Capability_16_2, kLc3Capability_16_1};
+
+static AudioLocation stereoAudio = static_cast<AudioLocation>(
+    AudioLocation::FRONT_LEFT | AudioLocation::FRONT_RIGHT);
+static AudioLocation monoAudio = AudioLocation::UNKNOWN;
+
+// Stores the supported setting of audio location, connected device, and the
+// channel count for each device
+std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
+    supportedDeviceSetting = {std::make_tuple(stereoAudio, 2, 1),
+                              std::make_tuple(monoAudio, 1, 2),
+                              std::make_tuple(monoAudio, 1, 1)};
+
 bool IsOffloadLeAudioConfigurationValid(
     const ::android::hardware::bluetooth::audio::V2_1::SessionType&
         session_type,
@@ -44,6 +98,60 @@
   return true;
 }
 
+UnicastCapability composeUnicastLc3Capability(AudioLocation audioLocation,
+                                              uint8_t deviceCnt,
+                                              uint8_t channelCount,
+                                              Lc3Parameters capability) {
+  return UnicastCapability{.codecType = CodecType::LC3,
+                           .supportedChannel = audioLocation,
+                           .deviceCount = deviceCnt,
+                           .channelCountPerDevice = channelCount,
+                           .capabilities = capability};
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting> GetLeAudioOffloadCodecCapabilities(
+    const SessionType_2_1& session_type) {
+  if (session_type !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type !=
+          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return std::vector<LeAudioCodecCapabilitiesSetting>(0);
+  }
+
+  if (kDefaultOffloadLeAudioCapabilities.empty()) {
+    for (auto [audioLocation, deviceCnt, channelCount] :
+         supportedDeviceSetting) {
+      for (auto capability : supportedLc3CapabilityList) {
+        UnicastCapability lc3Capability = composeUnicastLc3Capability(
+            audioLocation, deviceCnt, channelCount, capability);
+        UnicastCapability lc3MonoDecodeCapability =
+            composeUnicastLc3Capability(monoAudio, 1, 1, capability);
+
+        // Adds the capability for encode only
+        kDefaultOffloadLeAudioCapabilities.push_back(
+            {.unicastEncodeCapability = lc3Capability,
+             .unicastDecodeCapability = kInvalidUnicastCapability,
+             .broadcastCapability = kInvalidBroadcastCapability});
+
+        // Adds the capability for decode only
+        kDefaultOffloadLeAudioCapabilities.push_back(
+            {.unicastEncodeCapability = kInvalidUnicastCapability,
+             .unicastDecodeCapability = lc3Capability,
+             .broadcastCapability = kInvalidBroadcastCapability});
+
+        // Adds the capability for the case that encode and decode exist at the
+        // same time
+        kDefaultOffloadLeAudioCapabilities.push_back(
+            {.unicastEncodeCapability = lc3Capability,
+             .unicastDecodeCapability = lc3MonoDecodeCapability,
+             .broadcastCapability = kInvalidBroadcastCapability});
+      }
+    }
+  }
+
+  return kDefaultOffloadLeAudioCapabilities;
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h
index 59d22b7..34bba5f 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h
@@ -19,6 +19,7 @@
 #include <android/hardware/bluetooth/audio/2.2/types.h>
 
 #include "BluetoothAudioSupportedCodecsDB.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
 
 namespace android {
 namespace bluetooth {
@@ -29,6 +30,11 @@
         session_type,
     const ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration&
         le_audio_codec_config);
+
+std::vector<hardware::bluetooth::audio::V2_2::LeAudioCodecCapabilitiesSetting>
+GetLeAudioOffloadCodecCapabilities(
+    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+        session_type);
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index 7fcf523..fbe8686 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -30,6 +30,7 @@
 using aidl::android::hardware::graphics::common::PlaneLayout;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
 using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
 using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
 using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
@@ -123,6 +124,21 @@
     return layout;
 }
 
+bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
+        MetadataType metadataType) {
+    auto buffer = const_cast<native_handle_t*>(buf);
+    mapper->get(buffer, metadataType, [] (const auto& tmpError,
+                const auto& tmpMetadata) {
+                    if (tmpError == MapperErrorV4::NONE) {
+                        return tmpMetadata.size() > 0;
+                    } else {
+                        ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
+                        return false;
+                    }});
+
+    return false;
+}
+
 std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
     auto buffer = const_cast<native_handle_t*>(buf);
     std::vector<PlaneLayout> planeLayouts;
@@ -449,6 +465,55 @@
     return -1;
 }
 
+bool HandleImporter::isSmpte2086Present(const buffer_handle_t& buf) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2086);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    }
+
+    return false;
+}
+
+bool HandleImporter::isSmpte2094_10Present(const buffer_handle_t& buf) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_10);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    }
+
+    return false;
+}
+
+bool HandleImporter::isSmpte2094_40Present(const buffer_handle_t& buf) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_40);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    }
+
+    return false;
+}
+
+
 } // namespace helper
 } // namespace V1_0
 } // namespace common
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index e404439..83fa755 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -61,6 +61,11 @@
 
     int unlock(buffer_handle_t& buf); // returns release fence
 
+    // Query Gralloc4 metadata
+    bool isSmpte2086Present(const buffer_handle_t& buf);
+    bool isSmpte2094_10Present(const buffer_handle_t& buf);
+    bool isSmpte2094_40Present(const buffer_handle_t& buf);
+
 private:
     void initializeLocked();
     void cleanup();
diff --git a/camera/device/3.8/Android.bp b/camera/device/3.8/Android.bp
index 2a1f215..c3c2941 100644
--- a/camera/device/3.8/Android.bp
+++ b/camera/device/3.8/Android.bp
@@ -9,7 +9,6 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-
 hidl_interface {
     name: "android.hardware.camera.device@3.8",
     root: "android.hardware",
@@ -17,6 +16,7 @@
         "types.hal",
         "ICameraDevice.hal",
         "ICameraDeviceCallback.hal",
+        "ICameraDeviceSession.hal",
     ],
     interfaces: [
         "android.hardware.camera.common@1.0",
@@ -31,6 +31,7 @@
         "android.hardware.camera.metadata@3.4",
         "android.hardware.camera.metadata@3.5",
         "android.hardware.camera.metadata@3.6",
+        "android.hardware.camera.metadata@3.8",
         "android.hardware.graphics.common@1.0",
         "android.hidl.base@1.0",
     ],
diff --git a/camera/device/3.8/ICameraDevice.hal b/camera/device/3.8/ICameraDevice.hal
index 448f176..8832c68 100644
--- a/camera/device/3.8/ICameraDevice.hal
+++ b/camera/device/3.8/ICameraDevice.hal
@@ -16,6 +16,7 @@
 
 package android.hardware.camera.device@3.8;
 
+import android.hardware.camera.common@1.0::Status;
 import @3.7::ICameraDevice;
 
 /**
@@ -25,8 +26,96 @@
  * API at LIMITED or better hardware level.
  *
  * ICameraDevice.open() must return @3.2::ICameraDeviceSession,
- * @3.5::ICameraDeviceSession, @3.6::ICameraDeviceSession, or
- * @3.7::ICameraDeviceSession.
+ * @3.5::ICameraDeviceSession, @3.6::ICameraDeviceSession,
+ * @3.7::ICameraDeviceSession, or @3.8::ICameraDeviceSession.
  */
 interface ICameraDevice extends @3.7::ICameraDevice {
+    /**
+     * turnOnTorchWithStrengthLevel:
+     *
+     * Change the brightness level of the flash unit associated with this camera device
+     * and set it to value in torchStrength. This function also turns ON the torch
+     * with specified torchStrength if the torch is OFF.
+     *
+     * The torchStrength value must be within the valid range i.e. >=1 and
+     * <= FLASH_INFO_STRENGTH_MAXIMUM_LEVEL. Whenever the torch is turned OFF,
+     * the brightness level will reset to FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
+     * When the client calls setTorchMode(ON) after turnOnTorchWithStrengthLevel(N),
+     * the flash unit will have brightness level equal to N. This level does not
+     * represent the real brightness units. It is linear in nature i.e. flashlight
+     * at level 10 is twice as bright as at level 5.
+     *
+     * @param torchStrength Brightness level to be set for the flashlight.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On a successful change to the torch strength level.
+     *     INTERNAL_ERROR:
+     *         The flash unit cannot be operated due to an unexpected internal
+     *         error.
+     *     CAMERA_IN_USE:
+     *         This status code is returned when:
+     *           - This camera device has been opened, so the torch cannot be
+     *             controlled until it is closed.
+     *           - Due to other camera devices being open, or due to other
+     *             resource constraints, the torch cannot be controlled currently.
+     *     ILLEGAL_ARGUMENT:
+     *         If the torchStrength value is not within the range i.e. < 1 or
+     *         > FLASH_INFO_STRENGTH_MAXIMUM_LEVEL.
+     *     METHOD_NOT_SUPPORTED:
+     *         This status code is returned when:
+     *           - This camera device does not support direct operation of flashlight
+     *             torch mode. The framework must open the camera device and turn
+     *             the torch on through the device interface.
+     *           - This camera device does not have a flash unit.
+     *           - This camera device has flash unit but does not support torch
+     *             strength control.
+     *     CAMERA_DISCONNECTED:
+     *         An external camera device has been disconnected, and is no longer
+     *         available. This camera device interface is now stale, and a new
+     *         instance must be acquired if the device is reconnected. All
+     *         subsequent calls on this interface must return
+     *         CAMERA_DISCONNECTED.
+     *
+     */
+    turnOnTorchWithStrengthLevel(int32_t torchStrength) generates (Status status);
+
+    /**
+     * getTorchStrengthLevel:
+     *
+     * Get current torch strength level.
+     * If the device supports torch strength control, when the torch is OFF the
+     * strength level will reset to default level, so the return
+     * value in this case will be equal to FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
+     *
+     * @return status Status code for the operation, one of:
+     *      OK:
+     *           On success.
+     *      INTERNAL_ERROR:
+     *           An unexpected error occurred and the information is not
+     *           available.
+     *      METHOD_NOT_SUPPORTED:
+     *          This status code is returned when:
+     *            - This camera device does not support direct operation of flashlight
+     *              torch mode. The framework must open the camera device and turn
+     *              the torch on through the device interface.
+     *            - This camera device does not have a flash unit.
+     *            - This camera device has flash unit but does not support torch
+     *              strength control.
+     *
+     * @return torchStrength Current torch strength level.
+     *
+     */
+    getTorchStrengthLevel() generates (Status status, int32_t torchStrength);
+
+     /**
+     * isStreamCombinationSupported_3_8:
+     *
+     * Identical to @3.7::ICameraDevice.isStreamCombinationSupported, except
+     * that it takes a @3.8::StreamConfiguration parameter, which could contain
+     * additional information about a specific 10-bit dynamic range profile.
+     *
+     */
+    isStreamCombinationSupported_3_8(StreamConfiguration streams)
+            generates (Status status, bool queryStatus);
 };
diff --git a/camera/device/3.8/ICameraDeviceSession.hal b/camera/device/3.8/ICameraDeviceSession.hal
new file mode 100644
index 0000000..88e4338
--- /dev/null
+++ b/camera/device/3.8/ICameraDeviceSession.hal
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.8;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.5::StreamConfiguration;
+import @3.7::ICameraDeviceSession;
+import @3.6::HalStreamConfiguration;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.7::ICameraDeviceSession {
+    /**
+     * configureStreams_3_8:
+     *
+     * Identical to @3.7::ICameraDeviceSession.configureStreams_3_7, except that:
+     *
+     * - The requestedConfiguration allows the camera framework to configure
+     *   10-bit dynamic range profile.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On successful stream configuration.
+     *     INTERNAL_ERROR:
+     *         If there has been a fatal error and the device is no longer
+     *         operational. Only close() can be called successfully by the
+     *         framework after this error is returned.
+     *     ILLEGAL_ARGUMENT:
+     *         If the requested stream configuration is invalid. Some examples
+     *         of invalid stream configurations include:
+     *           - Including more than 1 INPUT stream
+     *           - Not including any OUTPUT streams
+     *           - Including streams with unsupported formats, or an unsupported
+     *             size for that format.
+     *           - Including too many output streams of a certain format.
+     *           - Unsupported rotation configuration
+     *           - Stream sizes/formats don't satisfy the
+     *             StreamConfigurationMode requirements
+     *             for non-NORMAL mode, or the requested operation_mode is not
+     *             supported by the HAL.
+     *           - Unsupported usage flag
+     *           - Unsupported stream groupIds, or unsupported multi-resolution
+     *             input stream.
+     *           - Invalid combination between a 10-bit dynamic range profile
+     *             and none impl. defined 8-bit format for a particular stream.
+     *         The camera service cannot filter out all possible illegal stream
+     *         configurations, since some devices may support more simultaneous
+     *         streams or larger stream resolutions than the minimum required
+     *         for a given camera device hardware level. The HAL must return an
+     *         ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+     *         ready to accept a future valid stream configuration in a later
+     *         configureStreams call.
+     * @return halConfiguration The stream parameters desired by the HAL for
+     *     each stream, including maximum buffers, the usage flags, and the
+     *     override format and dataspace.
+     */
+    configureStreams_3_8(StreamConfiguration requestedConfiguration)
+        generates (Status status, @3.6::HalStreamConfiguration halConfiguration);
+
+    /**
+     * repeatingRequestEnd:
+     *
+     * Notification about the last frame number in a repeating request along with the
+     * ids of all streams included in the repeating request.
+     *
+     * This can be called at any point after 'processCaptureRequest' in response
+     * to camera clients disabling an active repeating request.
+     *
+     * Performance requirements:
+     * The call must not be blocked for extensive periods and should be extremely lightweight. There
+     * must be no frame rate degradation or frame jitter introduced.
+     *
+     * This method must always succeed, even if the device has encountered a
+     * serious error.
+     */
+    repeatingRequestEnd(uint32_t frameNumber, vec<int32_t> streamIds);
+};
diff --git a/camera/device/3.8/types.hal b/camera/device/3.8/types.hal
index 6daa0e1..9d1ac22 100644
--- a/camera/device/3.8/types.hal
+++ b/camera/device/3.8/types.hal
@@ -19,6 +19,11 @@
 import @3.2::ErrorMsg;
 import @3.2::MsgType;
 import @3.2::ShutterMsg;
+import @3.2::CameraMetadata;
+import @3.2::StreamConfigurationMode;
+import @3.7::Stream;
+
+import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
 
 /**
  * ShutterMsg:
@@ -35,8 +40,9 @@
 
     /**
      * Timestamp for the capture readout. This must be in the same time domain
-     * as v3_2.timestamp, and the value must be v3_2.timestamp + exposureTime
-     * for a rolling shutter sensor.
+     * as v3_2.timestamp, and for a rolling shutter sensor, the value must be
+     * v3_2.timestamp + exposureTime + t_crop_top where t_crop_top is the exposure time
+     * skew of the cropped lines on the top.
      */
     uint64_t readoutTimestamp;
 };
@@ -66,3 +72,75 @@
         ShutterMsg shutter;
     } msg;
 };
+
+/**
+ * Stream:
+ *
+ * A descriptor for a single camera input or output stream. A stream is defined
+ * by the framework by its buffer resolution and format, and additionally by the
+ * HAL with the gralloc usage flags and the maximum in-flight buffer count.
+ *
+ * This version extends the @3.7 Stream with the dynamic range profile field.
+ */
+struct Stream {
+    /**
+     * The definition of Stream from the prior version.
+     */
+    @3.7::Stream v3_7;
+
+    /**
+     * The dynamic range profile for this stream.
+     *
+     * This field is valid and must only be considered for streams with format
+     * android.hardware.graphics.common.PixelFormat.YCBCR_P010 or
+     * android.hardware.graphics.common.PixelFormat.IMPLEMENTATION_DEFINED on devices supporting the
+     * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_10_BIT capability.
+     *
+     */
+    CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap dynamicRangeProfile;
+};
+
+/**
+ * StreamConfiguration:
+ *
+ * Identical to @3.7::StreamConfiguration, except that the streams
+ * vector contains @3.8::Stream.
+ */
+struct StreamConfiguration {
+    /**
+     * An array of camera stream pointers, defining the input/output
+     * configuration for the camera HAL device.
+     */
+    vec<Stream> streams;
+
+    /**
+     * The definition of operation mode from prior version.
+     *
+     */
+    @3.2::StreamConfigurationMode operationMode;
+
+    /**
+     * The definition of session parameters from prior version.
+     */
+    @3.2::CameraMetadata sessionParams;
+
+    /**
+     * The definition of stream configuration counter from prior version.
+     */
+    uint32_t streamConfigCounter;
+
+    /**
+     * If an input stream is configured, whether the input stream is expected to
+     * receive variable resolution images.
+     *
+     * This flag can only be set to true if the camera device supports
+     * multi-resolution input streams by advertising input stream configurations in
+     * physicalCameraMultiResolutionStreamConfigurations in its physical cameras'
+     * characteristics.
+     *
+     * When this flag is set to true, the input stream's width and height can be
+     * any one of the supported multi-resolution input stream sizes.
+     */
+    bool multiResolutionInputImage;
+};
+
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
index 11360da..4c70eb9 100644
--- a/camera/metadata/3.8/types.hal
+++ b/camera/metadata/3.8/types.hal
@@ -53,6 +53,21 @@
 
     ANDROID_FLASH_INFO_END_3_8,
 
+    /** android.request.availableDynamicRangeProfilesMap [static, enum[], ndk_public]
+     *
+     * <p>A map of all available 10-bit dynamic range profiles along with their
+     * capture request constraints.</p>
+     */
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_REQUEST_END_3_4,
+
+    /** android.request.recommendedTenBitDynamicRangeProfile [static, int32, java_public]
+     *
+     * <p>Recommended 10-bit dynamic range profile.</p>
+     */
+    ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE,
+
+    ANDROID_REQUEST_END_3_8,
+
 };
 
 /*
@@ -66,3 +81,51 @@
         @3.2::CameraMetadataEnumAndroidControlVideoStabilizationMode {
     ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION,
 };
+
+/** android.request.availableCapabilities enumeration values added since v3.6
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+        @3.6::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT,
+};
+
+/** android.request.availableDynamicRangeProfilesMap enumeration values
+ * @see ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+ */
+enum CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap : uint32_t {
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD
+                                                                 = 0x1,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10  = 0x2,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10  = 0x4,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS
+                                                                 = 0x8,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF
+                                                                 = 0x10,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO
+                                                                 = 0x20,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM
+                                                                 = 0x40,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO
+                                                                 = 0x80,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF
+                                                                 = 0x100,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO
+                                                                 = 0x200,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM
+                                                                 = 0x400,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO
+                                                                 = 0x800,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX    = 0x1000,
+};
+
+/** android.scaler.availableRecommendedStreamConfigurations enumeration values added since v3.4
+ * @see ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
+ */
+enum CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations :
+        @3.4::CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations {
+    ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_10BIT_OUTPUT
+                                                                 = 0x8,
+    ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8
+                                                                 = 0x9,
+};
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2c141ee..0e62265 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -51,11 +51,15 @@
         "android.hardware.camera.device@3.7",
         "android.hardware.camera.device@3.8",
         "android.hardware.camera.metadata@3.4",
+        "android.hardware.camera.metadata@3.8",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.6",
         "android.hardware.camera.provider@2.7",
         "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "libgrallocusage",
         "libhidlmemory",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index ff8cd49..8c44010 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -30,6 +30,7 @@
 
 #include <CameraMetadata.h>
 #include <CameraParameters.h>
+#include <HandleImporter.h>
 #include <android/hardware/camera/device/1.0/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
@@ -41,10 +42,13 @@
 #include <android/hardware/camera/device/3.6/ICameraDevice.h>
 #include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.7/ICameraDevice.h>
+#include <android/hardware/camera/device/3.8/ICameraDevice.h>
 #include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
 #include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
 #include <android/hardware/camera/metadata/3.4/types.h>
+#include <android/hardware/camera/metadata/3.8/types.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <android/hardware/camera/provider/2.5/ICameraProvider.h>
 #include <android/hardware/camera/provider/2.6/ICameraProvider.h>
@@ -96,6 +100,7 @@
 using ::android::hardware::camera::common::V1_0::TorchMode;
 using ::android::hardware::camera::common::V1_0::TorchModeStatus;
 using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
 using ::android::hardware::camera::common::V1_0::helper::Size;
 using ::android::hardware::camera::device::V1_0::CameraFacing;
 using ::android::hardware::camera::device::V1_0::CameraFrameMetadata;
@@ -128,6 +133,8 @@
         CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
 using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag;
 using ::android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
+using ::android::hardware::camera::metadata::V3_8::
+        CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
 using ::android::hardware::camera::provider::V2_4::ICameraProvider;
 using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
 using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
@@ -135,7 +142,6 @@
 using ::android::hardware::graphics::common::V1_0::Dataspace;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
 using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMapper;
 using ::android::hidl::memory::V1_0::IMemory;
 using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 using ::android::hidl::manager::V1_0::IServiceManager;
@@ -666,7 +672,7 @@
 
         void waitForBuffersReturned();
 
-     private:
+      private:
         bool processCaptureResultLocked(const CaptureResult& results,
                 hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata);
         Return<void> notifyHelper(const hidl_vec<NotifyMsg>& msgs,
@@ -780,13 +786,15 @@
             sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
             sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
             sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
-            sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/);
+            sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
+            sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/);
     void castInjectionSession(
             const sp<ICameraDeviceSession>& session,
             sp<device::V3_7::ICameraInjectionSession>* injectionSession3_7 /*out*/);
     void castDevice(const sp<device::V3_2::ICameraDevice>& device, int32_t deviceVersion,
                     sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
-                    sp<device::V3_7::ICameraDevice>* device3_7 /*out*/);
+                    sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
+                    sp<device::V3_8::ICameraDevice>* device3_8 /*out*/);
     void createStreamConfiguration(
             const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
             StreamConfigurationMode configMode,
@@ -816,6 +824,16 @@
                              uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
                              sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
                              bool maxResolution);
+    void configureStreams3_8(const std::string& name, int32_t deviceVersion,
+                             sp<ICameraProvider> provider, PixelFormat format,
+                             sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
+                             V3_2::Stream* previewStream /*out*/,
+                             device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
+                             bool* supportsPartialResults /*out*/,
+                             uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+                             sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
+                             bool maxResolution,
+                             CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof);
 
     void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
@@ -895,6 +913,9 @@
     static bool isDepthOnly(const camera_metadata_t* staticMeta);
 
     static bool isUltraHighResolution(const camera_metadata_t* staticMeta);
+    static void get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
+        std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles);
+    static bool is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta);
 
     static Status getAvailableOutputStreams(const camera_metadata_t* staticMeta,
                                             std::vector<AvailableStream>& outputStreams,
@@ -906,11 +927,12 @@
 
     static Status getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta,
                                                 std::vector<AvailableStream>* outputStreams);
-
+    static bool supportsPreviewStabilization(const std::string& name, sp<ICameraProvider> provider);
     static Status getJpegBufferSize(camera_metadata_t *staticMeta,
             uint32_t* outBufSize);
     static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
     static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta);
+    static bool isTorchStrengthControlSupported(const camera_metadata_t *staticMeta);
     static Status isOfflineSessionSupported(const camera_metadata_t *staticMeta);
     static Status getPhysicalCameraIds(const camera_metadata_t *staticMeta,
             std::unordered_set<std::string> *physicalIds/*out*/);
@@ -947,12 +969,14 @@
     void getPrivacyTestPatternModes(
             const camera_metadata_t* staticMetadata,
             std::unordered_set<int32_t>* privacyTestPatternModes/*out*/);
-    static bool isColorCamera(const camera_metadata_t *metadata);
 
     static V3_2::DataspaceFlags getDataspace(PixelFormat format);
 
     void processCaptureRequestInternal(uint64_t bufferusage, RequestTemplate reqTemplate,
                                        bool useSecureOnlyCameras);
+    void processPreviewStabilizationCaptureRequestInternal(
+            bool previewStabilizationOn,
+            /*inout*/ std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag);
 
     // Used by switchToOffline where a new result queue is created for offline reqs
     void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
@@ -1006,7 +1030,11 @@
 
         // Buffers are added by process_capture_result when output buffers
         // return from HAL but framework.
-        ::android::Vector<StreamBuffer> resultOutputBuffers;
+        struct StreamBufferAndTimestamp {
+            StreamBuffer buffer;
+            nsecs_t timeStamp;
+        };
+        ::android::Vector<StreamBufferAndTimestamp> resultOutputBuffers;
 
         std::unordered_set<std::string> expectedPhysicalResults;
 
@@ -1068,6 +1096,10 @@
                 expectedPhysicalResults(extraPhysicalResult) {}
     };
 
+    static void verify10BitMetadata(HandleImporter& importer,
+            const InFlightRequest& request,
+            CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile);
+
     // Map from frame number to the in-flight request state
     typedef ::android::KeyedVector<uint32_t, InFlightRequest*> InFlightMap;
 
@@ -1096,6 +1128,8 @@
 
     // Camera provider type.
     std::string mProviderType;
+
+    HandleImporter mHandleImporter;
 };
 
 Return<void> CameraHidlTest::Camera1DeviceCb::notifyCallback(
@@ -1421,8 +1455,25 @@
         return notify;
     }
 
-    request->resultOutputBuffers.appendArray(results.outputBuffers.data(),
-            results.outputBuffers.size());
+    for (const auto& buffer : results.outputBuffers) {
+        // wait for the fence timestamp and store it along with the buffer
+        // TODO: Check if we really need the dup here
+        sp<android::Fence> releaseFence = nullptr;
+        if (buffer.releaseFence && (buffer.releaseFence->numFds == 1) &&
+            buffer.releaseFence->data[0] >= 0) {
+            releaseFence = new android::Fence(dup(buffer.releaseFence->data[0]));
+        }
+        InFlightRequest::StreamBufferAndTimestamp streamBufferAndTimestamp;
+        streamBufferAndTimestamp.buffer = buffer;
+        streamBufferAndTimestamp.timeStamp = systemTime();
+        if (releaseFence && releaseFence->isValid()) {
+            releaseFence->wait(/*ms*/ 300);
+            nsecs_t releaseTime = releaseFence->getSignalTime();
+            if (streamBufferAndTimestamp.timeStamp < releaseTime)
+                streamBufferAndTimestamp.timeStamp = releaseTime;
+        }
+        request->resultOutputBuffers.push_back(streamBufferAndTimestamp);
+    }
     // If shutter event is received notify the pending threads.
     if (request->shutterTimestamp != 0) {
         notify = true;
@@ -2933,6 +2984,137 @@
     }
 }
 
+// Verify that the torch strength level can be set and retrieved successfully.
+TEST_P(CameraHidlTest, turnOnTorchWithStrengthLevel) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    bool torchControlSupported = false;
+    bool torchStrengthControlSupported = false;
+    Return<void> ret;
+
+    ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) {
+        ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support);
+        ASSERT_EQ(Status::OK, status);
+        torchControlSupported = support;
+    });
+
+    sp<TorchProviderCb> cb = new TorchProviderCb(this);
+    Return<Status> returnStatus = mProvider->setCallback(cb);
+    ASSERT_TRUE(returnStatus.isOk());
+    ASSERT_EQ(Status::OK, returnStatus);
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        int32_t defaultLevel;
+        switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_8: {
+                ::android::sp<::android::hardware::camera::device::V3_8::ICameraDevice> device3_8;
+                ALOGI("%s: Testing camera device %s", __FUNCTION__, name.c_str());
+                ret = mProvider->getCameraDeviceInterface_V3_x(
+                        name, [&](auto status, const auto& device) {
+                            ASSERT_EQ(Status::OK, status);
+                            ASSERT_NE(device, nullptr);
+                            auto castResult = device::V3_8::ICameraDevice::castFrom(device);
+                            ASSERT_TRUE(castResult.isOk());
+                            device3_8 = castResult;
+                        });
+                ASSERT_TRUE(ret.isOk());
+
+                ret = device3_8->getCameraCharacteristics([&] (auto s, const auto& chars) {
+                    ASSERT_EQ(Status::OK, s);
+                    const camera_metadata_t* staticMeta =
+                            reinterpret_cast<const camera_metadata_t*>(chars.data());
+                    ASSERT_NE(nullptr, staticMeta);
+                    torchStrengthControlSupported = isTorchStrengthControlSupported(staticMeta);
+                    camera_metadata_ro_entry entry;
+                    int rc = find_camera_metadata_ro_entry(staticMeta,
+                            ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL, &entry);
+                    if (torchStrengthControlSupported) {
+                        ASSERT_EQ(rc, 0);
+                        ASSERT_GT(entry.count, 0);
+                        defaultLevel = *entry.data.i32;
+                        ALOGI("Default level is:%d", defaultLevel);
+                    }
+                });
+                ASSERT_TRUE(ret.isOk());
+                // If torchStrengthControl is supported, torchControlSupported should be true.
+                if (torchStrengthControlSupported) {
+                    ASSERT_TRUE(torchControlSupported);
+                }
+                mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+                returnStatus = device3_8->turnOnTorchWithStrengthLevel(2);
+                ASSERT_TRUE(returnStatus.isOk());
+                // Method_not_supported check
+                if (!torchStrengthControlSupported) {
+                    ALOGI("Torch strength control not supported.");
+                    ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
+                } else {
+                    ASSERT_EQ(Status::OK, returnStatus);
+                    if (returnStatus == Status::OK) {
+                        {
+                            std::unique_lock<std::mutex> l(mTorchLock);
+                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                                auto timeout = std::chrono::system_clock::now() +
+                                        std::chrono::seconds(kTorchTimeoutSec);
+                                ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l,
+                                        timeout));
+                            }
+                            ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
+                            mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+                        }
+                        ALOGI("getTorchStrengthLevel: Testing");
+                        ret = device3_8->getTorchStrengthLevel([&]
+                                (auto status, const auto& strengthLevel) {
+                                    ASSERT_TRUE(ret.isOk());
+                                    ASSERT_EQ(Status::OK, status);
+                                    ALOGI("Torch strength level is : %d", strengthLevel);
+                                    ASSERT_EQ(strengthLevel, 2);
+                                });
+                        // Turn OFF the torch and verify torch strength level is reset to default level.
+                        ALOGI("Testing torch strength level reset after turning the torch OFF.");
+                        returnStatus = device3_8->setTorchMode(TorchMode::OFF);
+                        ASSERT_TRUE(returnStatus.isOk());
+                        ASSERT_EQ(Status::OK, returnStatus);
+                        {
+                            std::unique_lock<std::mutex> l(mTorchLock);
+                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                                auto timeout = std::chrono::system_clock::now() +
+                                        std::chrono::seconds(kTorchTimeoutSec);
+                                ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l,
+                                        timeout));
+                            }
+                            ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
+                        }
+                        ret = device3_8->getTorchStrengthLevel([&]
+                                (auto status, const auto& strengthLevel) {
+                                    ASSERT_TRUE(ret.isOk());
+                                    ASSERT_EQ(Status::OK, status);
+                                    ALOGI("Torch strength level after turning OFF torch is : %d",
+                                            strengthLevel);
+                                    ASSERT_EQ(strengthLevel, defaultLevel);
+                                });
+                    }
+                }
+            }
+            break;
+            case CAMERA_DEVICE_API_VERSION_3_7:
+            case CAMERA_DEVICE_API_VERSION_3_6:
+            case CAMERA_DEVICE_API_VERSION_3_5:
+            case CAMERA_DEVICE_API_VERSION_3_4:
+            case CAMERA_DEVICE_API_VERSION_3_3:
+            case CAMERA_DEVICE_API_VERSION_3_2:
+            case CAMERA_DEVICE_API_VERSION_1_0: {
+                ALOGI("Torch strength control feature not supported.");
+            }
+            break;
+            default: {
+                ALOGI("Invalid device version.");
+                ADD_FAILURE();
+            }
+            break;
+        }
+    }
+}
+
 //In case it is supported verify that torch can be enabled.
 //Check for corresponding toch callbacks as well.
 TEST_P(CameraHidlTest, setTorchMode) {
@@ -3185,10 +3367,13 @@
                 sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
                 sp<device::V3_6::ICameraDeviceSession> sessionV3_6;
                 sp<device::V3_7::ICameraDeviceSession> sessionV3_7;
+                sp<device::V3_8::ICameraDeviceSession> sessionV3_8;
                 castSession(session, deviceVersion, &sessionV3_3,
                         &sessionV3_4, &sessionV3_5, &sessionV3_6,
-                        &sessionV3_7);
-                if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7) {
+                        &sessionV3_7, &sessionV3_8);
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_8) {
+                    ASSERT_TRUE(sessionV3_8.get() != nullptr);
+                } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_7) {
                     ASSERT_TRUE(sessionV3_7.get() != nullptr);
                 } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
                     ASSERT_TRUE(sessionV3_6.get() != nullptr);
@@ -3356,14 +3541,17 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider,
                 &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+                &session3_6, &session3_7, &session3_8);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+                &cameraDevice3_8);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -3459,9 +3647,11 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         ::android::hardware::camera::device::V3_7::StreamConfiguration config3_7;
         ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
         ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
@@ -3498,8 +3688,9 @@
             openEmptyDeviceSession(name, mProvider2_6, &cti.session /*out*/,
                                    &cti.staticMeta /*out*/, &cti.cameraDevice /*out*/);
             castSession(cti.session, deviceVersion, &cti.session3_3, &cti.session3_4,
-                        &cti.session3_5, &cti.session3_6, &cti.session3_7);
-            castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7);
+                        &cti.session3_5, &cti.session3_6, &cti.session3_7, &cti.session3_8);
+            castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7,
+                    &cti.cameraDevice3_8);
 
             outputStreams.clear();
             ASSERT_EQ(Status::OK, getMandatoryConcurrentStreams(cti.staticMeta, &outputStreams));
@@ -3628,14 +3819,17 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+                &session3_6, &session3_7, &session3_8);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+                &cameraDevice3_8);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -3841,14 +4035,17 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+                &session3_6, &session3_7, &session3_8);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+                &cameraDevice3_8);
 
         Status rc = isZSLModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4027,9 +4224,10 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7);
+                &session3_6, &session3_7, &session3_8);
         if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
             ASSERT_NE(session3_4, nullptr);
         } else {
@@ -4168,14 +4366,17 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+                &session3_6, &session3_7, &session3_8);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+                &cameraDevice3_8);
 
         // Check if camera support depth only
         if (isDepthOnly(staticMeta)) {
@@ -4302,14 +4503,17 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+                &session3_6, &session3_7, &session3_8);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+                &cameraDevice3_8);
 
         Status rc = isConstrainedModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4549,14 +4753,17 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+                &session3_6, &session3_7, &session3_8);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+                &cameraDevice3_8);
 
         // Check if camera support depth only
         if (isDepthOnly(staticMeta)) {
@@ -4793,18 +5000,27 @@
 
             ASSERT_FALSE(inflightReq.errorCodeValid);
             ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
+            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
 
             // For camera device 3.8 or newer, shutterReadoutTimestamp must be
-            // available, and it must be shutterTimestamp + exposureTime.
+            // available, and it must be >= shutterTimestamp + exposureTime, and
+            // < shutterTimestamp + exposureTime + rollingShutterSkew / 2.
             if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8) {
                 ASSERT_TRUE(inflightReq.shutterReadoutTimestampValid);
                 ASSERT_FALSE(inflightReq.collectedResult.isEmpty());
                 if (inflightReq.collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
                     camera_metadata_entry_t exposureTimeResult = inflightReq.collectedResult.find(
                             ANDROID_SENSOR_EXPOSURE_TIME);
-                    ASSERT_EQ(inflightReq.shutterReadoutTimestamp - inflightReq.shutterTimestamp,
-                            exposureTimeResult.data.i64[0]);
+                    nsecs_t exposureToReadout =
+                            inflightReq.shutterReadoutTimestamp - inflightReq.shutterTimestamp;
+                    ASSERT_GE(exposureToReadout, exposureTimeResult.data.i64[0]);
+                    if (inflightReq.collectedResult.exists(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW)) {
+                        camera_metadata_entry_t rollingShutterSkew =
+                                inflightReq.collectedResult.find(
+                                        ANDROID_SENSOR_ROLLING_SHUTTER_SKEW);
+                        ASSERT_LT(exposureToReadout, exposureTimeResult.data.i64[0] +
+                                                             rollingShutterSkew.data.i64[0] / 2);
+                    }
                 }
             }
 
@@ -4831,6 +5047,20 @@
         ASSERT_EQ(Status::OK, status);
         ASSERT_EQ(numRequestProcessed, 1u);
 
+        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8) {
+            sp<device::V3_3::ICameraDeviceSession> session3_3;
+            sp<device::V3_4::ICameraDeviceSession> session3_4;
+            sp<device::V3_5::ICameraDeviceSession> session3_5;
+            sp<device::V3_6::ICameraDeviceSession> session3_6;
+            sp<device::V3_7::ICameraDeviceSession> session3_7;
+            sp<device::V3_8::ICameraDeviceSession> session3_8;
+            castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
+                    &session3_6, &session3_7, &session3_8);
+            ASSERT_TRUE(session3_8.get() != nullptr);
+            hidl_vec<int32_t> streamIds = { halStreamConfig.streams[0].id };
+            session3_8->repeatingRequestEnd(request.frameNumber, streamIds);
+        }
+
         {
             std::unique_lock<std::mutex> l(mLock);
             while (!inflightReq.errorCodeValid &&
@@ -4844,7 +5074,197 @@
 
             ASSERT_FALSE(inflightReq.errorCodeValid);
             ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
+            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
+        }
+
+        if (useHalBufManager) {
+            verifyBuffersReturned(session, deviceVersion, testStream.id, cb);
+        }
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+TEST_P(CameraHidlTest, processCaptureRequestPreviewStabilization) {
+    std::unordered_map<std::string, nsecs_t> cameraDeviceToTimeLag;
+    processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ false,
+                                                      cameraDeviceToTimeLag);
+    processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ true,
+                                                      cameraDeviceToTimeLag);
+}
+
+void CameraHidlTest::processPreviewStabilizationCaptureRequestInternal(
+        bool previewStabilizationOn,
+        // Used as output when preview stabilization is off, as output when its
+        // on.
+        std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                       static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    uint64_t bufferId = 1;
+    uint32_t frameNumber = 1;
+    ::android::hardware::hidl_vec<uint8_t> settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
+
+        if (!supportsPreviewStabilization(name, mProvider)) {
+            ALOGI(" %s Camera device %s doesn't support preview stabilization, skipping", __func__,
+                  name.c_str());
+            continue;
+        }
+
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
+            ALOGE("%s: device version < 3.8 must not advertise preview stabilization,"
+                  " camera metadata validation will fail",
+                  __func__);
+            ADD_FAILURE();
+        }
+
+        V3_2::Stream testStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        uint32_t partialResultCount = 0;
+        configureSingleStream(name, deviceVersion, mProvider, &streamThreshold,
+                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW,
+                              &session /*out*/, &testStream /*out*/, &halStreamConfig /*out*/,
+                              &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                              &useHalBufManager /*out*/, &cb /*out*/);
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+                session->getCaptureResultMetadataQueue([&resultQueue](const auto& descriptor) {
+                    resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
+                    if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: HAL returns empty result metadata fmq,"
+                              " not use it",
+                              __func__);
+                        resultQueue = nullptr;
+                        // Don't use the queue onwards.
+                    }
+                });
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        InFlightRequest inflightReq = {1, false, supportsPartialResults, partialResultCount,
+                                       resultQueue};
+
+        Return<void> ret;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+        ret = session->constructDefaultRequestSettings(
+                RequestTemplate::PREVIEW, [&](auto status, const auto& req) {
+                    ASSERT_EQ(Status::OK, status);
+                    const camera_metadata_t* metadata =
+                            reinterpret_cast<const camera_metadata_t*>(req.data());
+                    defaultSettings = metadata;
+                    settings = req;
+                });
+        ASSERT_TRUE(ret.isOk());
+        android::status_t metadataRet = ::android::OK;
+        uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+        if (previewStabilizationOn) {
+            videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
+            metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                                                 &videoStabilizationMode, 1);
+        } else {
+            metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                                                 &videoStabilizationMode, 1);
+        }
+        ASSERT_EQ(metadataRet, ::android::OK);
+        hidl_handle buffer_handle;
+        StreamBuffer outputBuffer;
+        if (useHalBufManager) {
+            outputBuffer = {halStreamConfig.streams[0].id,
+                            /*bufferId*/ 0,
+                            buffer_handle,
+                            BufferStatus::OK,
+                            nullptr,
+                            nullptr};
+        } else {
+            allocateGraphicBuffer(
+                    testStream.width, testStream.height,
+                    /* We don't look at halStreamConfig.streams[0].consumerUsage
+                     * since that is 0 for output streams
+                     */
+                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                                                    GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                    halStreamConfig.streams[0].overrideFormat, &buffer_handle);
+            outputBuffer = {halStreamConfig.streams[0].id,
+                            bufferId,
+                            buffer_handle,
+                            BufferStatus::OK,
+                            nullptr,
+                            nullptr};
+        }
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, emptyInputBuffer,
+                                  outputBuffers};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.add(frameNumber, &inflightReq);
+        }
+
+        Status status = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        Return<void> returnStatus = session->processCaptureRequest(
+                {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, uint32_t n) {
+                    status = s;
+                    numRequestProcessed = n;
+                });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                   ((0 < inflightReq.numBuffersLeft) || (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq.errorCodeValid);
+            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
+            ASSERT_TRUE(inflightReq.shutterReadoutTimestampValid);
+            nsecs_t readoutTimestamp = inflightReq.shutterReadoutTimestamp;
+
+            if (previewStabilizationOn) {
+                // Here we collect the time difference between the buffer ready
+                // timestamp - notify readout timestamp.
+                // timeLag = buffer ready timestamp - notify readout timestamp.
+                // timeLag(previewStabilization) must be <=
+                //        timeLag(stabilization off) + 1 frame duration.
+                auto it = cameraDeviceToTimeLag.find(name.c_str());
+                camera_metadata_entry e;
+                e = inflightReq.collectedResult.find(ANDROID_SENSOR_FRAME_DURATION);
+                ASSERT_TRUE(e.count > 0);
+                nsecs_t frameDuration = e.data.i64[0];
+                ASSERT_TRUE(it != cameraDeviceToTimeLag.end());
+
+                nsecs_t previewStabOnLagTime =
+                        inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
+                ASSERT_TRUE(previewStabOnLagTime <= (it->second + frameDuration));
+            } else {
+                // Fill in the buffer ready timestamp - notify timestamp;
+                cameraDeviceToTimeLag[std::string(name.c_str())] =
+                        inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
+            }
         }
 
         if (useHalBufManager) {
@@ -5284,6 +5704,188 @@
     }
 }
 
+// Generate and verify 10-bit dynamic range request
+TEST_P(CameraHidlTest, process10BitDynamicRangeRequest) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    uint64_t bufferId = 1;
+    uint32_t frameNumber = 1;
+    ::android::hardware::hidl_vec<uint8_t> settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
+            continue;
+        }
+        std::string version, deviceId;
+        ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &deviceId));
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        openEmptyDeviceSession(name, mProvider, &session, &staticMeta);
+        if (!is10BitDynamicRangeCapable(staticMeta)) {
+            free_camera_metadata(staticMeta);
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> profileList;
+        get10BitDynamicRangeProfiles(staticMeta, &profileList);
+        ASSERT_FALSE(profileList.empty());
+
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+        ret = session->constructDefaultRequestSettings(
+                RequestTemplate::STILL_CAPTURE,
+                [&defaultSettings](auto status, const auto& req) mutable {
+                    ASSERT_EQ(Status::OK, status);
+
+                    const camera_metadata_t* metadata =
+                            reinterpret_cast<const camera_metadata_t*>(req.data());
+                    size_t expectedSize = req.size();
+                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+                    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+                    size_t entryCount = get_camera_metadata_entry_count(metadata);
+                    ASSERT_GT(entryCount, 0u);
+                    defaultSettings = metadata;
+                });
+        ASSERT_TRUE(ret.isOk());
+
+        const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
+        settings.setToExternal(
+                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(settingsBuffer)),
+                get_camera_metadata_size(settingsBuffer));
+        overrideRotateAndCrop(&settings);
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+        V3_6::HalStreamConfiguration halStreamConfig;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        uint32_t partialResultCount = 0;
+        V3_2::Stream previewStream;
+        sp<device::V3_8::ICameraDeviceSession> session3_8;
+        sp<DeviceCb> cb;
+        for (const auto& profile : profileList) {
+            configureStreams3_8(name, deviceVersion, mProvider, PixelFormat::IMPLEMENTATION_DEFINED,
+                                &session3_8, &previewStream, &halStreamConfig,
+                                &supportsPartialResults, &partialResultCount, &useHalBufManager,
+                                &cb, 0, /*maxResolution*/ false, profile);
+            ASSERT_NE(session3_8, nullptr);
+
+            std::shared_ptr<ResultMetadataQueue> resultQueue;
+            auto resultQueueRet = session3_8->getCaptureResultMetadataQueue(
+                    [&resultQueue](const auto& descriptor) {
+                        resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
+                        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+                            ALOGE("%s: HAL returns empty result metadata fmq,"
+                                  " not use it",
+                                  __func__);
+                            resultQueue = nullptr;
+                            // Don't use the queue onwards.
+                        }
+                    });
+            ASSERT_TRUE(resultQueueRet.isOk());
+
+            std::vector<hidl_handle> graphicBuffers;
+            graphicBuffers.reserve(halStreamConfig.streams.size());
+            ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
+            outputBuffers.resize(halStreamConfig.streams.size());
+            InFlightRequest inflightReq = {static_cast<ssize_t>(halStreamConfig.streams.size()),
+                                           false,
+                                           supportsPartialResults,
+                                           partialResultCount,
+                                           std::unordered_set<std::string>(),
+                                           resultQueue};
+
+            size_t k = 0;
+            for (const auto& halStream : halStreamConfig.streams) {
+                hidl_handle buffer_handle;
+                if (useHalBufManager) {
+                    outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
+                                        0,
+                                        buffer_handle,
+                                        BufferStatus::OK,
+                                        nullptr,
+                                        nullptr};
+                } else {
+                    allocateGraphicBuffer(
+                            previewStream.width, previewStream.height,
+                            android_convertGralloc1To0Usage(halStream.v3_4.v3_3.v3_2.producerUsage,
+                                                            halStream.v3_4.v3_3.v3_2.consumerUsage),
+                            halStream.v3_4.v3_3.v3_2.overrideFormat, &buffer_handle);
+
+                    graphicBuffers.push_back(buffer_handle);
+                    outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
+                                        bufferId,
+                                        buffer_handle,
+                                        BufferStatus::OK,
+                                        nullptr,
+                                        nullptr};
+                    bufferId++;
+                }
+                k++;
+            }
+
+            StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+            V3_4::CaptureRequest request3_4;
+            request3_4.v3_2.frameNumber = frameNumber;
+            request3_4.v3_2.fmqSettingsSize = 0;
+            request3_4.v3_2.settings = settings;
+            request3_4.v3_2.inputBuffer = emptyInputBuffer;
+            request3_4.v3_2.outputBuffers = outputBuffers;
+            V3_7::CaptureRequest request3_7;
+            request3_7.v3_4 = request3_4;
+            request3_7.inputWidth = 0;
+            request3_7.inputHeight = 0;
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                mInflightMap.clear();
+                mInflightMap.add(frameNumber, &inflightReq);
+            }
+
+            Status stat = Status::INTERNAL_ERROR;
+            uint32_t numRequestProcessed = 0;
+            hidl_vec<BufferCache> cachesToRemove;
+            Return<void> returnStatus = session3_8->processCaptureRequest_3_7(
+                    {request3_7}, cachesToRemove,
+                    [&stat, &numRequestProcessed](auto s, uint32_t n) {
+                        stat = s;
+                        numRequestProcessed = n;
+                    });
+            ASSERT_TRUE(returnStatus.isOk());
+            ASSERT_EQ(Status::OK, stat);
+            ASSERT_EQ(numRequestProcessed, 1u);
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                while (!inflightReq.errorCodeValid &&
+                       ((0 < inflightReq.numBuffersLeft) || (!inflightReq.haveResultMetadata))) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kStreamBufferTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+                }
+
+                ASSERT_FALSE(inflightReq.errorCodeValid);
+                ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+                verify10BitMetadata(mHandleImporter, inflightReq, profile);
+            }
+            if (useHalBufManager) {
+                hidl_vec<int32_t> streamIds(halStreamConfig.streams.size());
+                for (size_t i = 0; i < streamIds.size(); i++) {
+                    streamIds[i] = halStreamConfig.streams[i].v3_4.v3_3.v3_2.id;
+                }
+                session3_8->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
+                cb->waitForBuffersReturned();
+            }
+
+            ret = session3_8->close();
+            ASSERT_TRUE(ret.isOk());
+        }
+    }
+}
+
 // Generate and verify a burst containing alternating sensor sensitivity values
 TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -5425,7 +6027,7 @@
 
             ASSERT_FALSE(inflightReqs[i].errorCodeValid);
             ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(previewStream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
+            ASSERT_EQ(previewStream.id, inflightReqs[i].resultOutputBuffers[0].buffer.streamId);
             ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
             ASSERT_TRUE(inflightReqs[i].collectedResult.exists(ANDROID_SENSOR_SENSITIVITY));
             camera_metadata_entry_t isoResult = inflightReqs[i].collectedResult.find(
@@ -5709,7 +6311,7 @@
 
             ASSERT_FALSE(inflightReqs[i].errorCodeValid);
             ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
+            ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].buffer.streamId);
             ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
         }
 
@@ -5905,7 +6507,7 @@
 
             if (!inflightReq.errorCodeValid) {
                 ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+                ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
             } else {
                 switch (inflightReq.errorCode) {
                     case ErrorCode::ERROR_REQUEST:
@@ -6277,142 +6879,6 @@
     }
 }
 
-// Test the multi-camera API requirement for Google Requirement Freeze S
-// Note that this requirement can only be partially tested. If a vendor
-// device doesn't expose a physical camera in any shape or form, there is no way
-// the test can catch it.
-TEST_P(CameraHidlTest, grfSMultiCameraTest) {
-    const int socGrfApi = property_get_int32("ro.board.first_api_level", /*default*/ -1);
-    if (socGrfApi < 31 /*S*/) {
-        // Non-GRF devices, or version < 31 Skip
-        ALOGI("%s: socGrfApi level is %d. Skipping", __FUNCTION__, socGrfApi);
-        return;
-    }
-
-    // Test that if more than one rear-facing color camera is
-    // supported, there must be at least one rear-facing logical camera.
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-    // Back facing non-logical color cameras
-    std::set<std::string> rearColorCameras;
-    // Back facing logical cameras' physical camera Id sets
-    std::set<std::set<std::string>> rearPhysicalIds;
-    for (const auto& name : cameraDeviceNames) {
-        std::string cameraId;
-        int deviceVersion = getCameraDeviceVersionAndId(name, mProviderType, &cameraId);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
-            case CAMERA_DEVICE_API_VERSION_3_7:
-            case CAMERA_DEVICE_API_VERSION_3_6:
-            case CAMERA_DEVICE_API_VERSION_3_5:
-            case CAMERA_DEVICE_API_VERSION_3_4:
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
-                ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
-                Return<void> ret;
-                ret = mProvider->getCameraDeviceInterface_V3_x(
-                        name, [&](auto status, const auto& device) {
-                            ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                            ASSERT_EQ(Status::OK, status);
-                            ASSERT_NE(device, nullptr);
-                            device3_x = device;
-                        });
-                ASSERT_TRUE(ret.isOk());
-
-                ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
-                    ASSERT_EQ(Status::OK, status);
-                    const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
-
-                    // Skip if this is not a color camera.
-                    if (!CameraHidlTest::isColorCamera(metadata)) {
-                        return;
-                    }
-
-                    // Check camera facing. Skip if facing is not BACK.
-                    // If this is not a logical camera, only note down
-                    // the camera ID, and skip.
-                    camera_metadata_ro_entry entry;
-                    int retcode = find_camera_metadata_ro_entry(
-                            metadata, ANDROID_LENS_FACING, &entry);
-                    ASSERT_EQ(retcode, 0);
-                    ASSERT_GT(entry.count, 0);
-                    uint8_t facing = entry.data.u8[0];
-                    bool isLogicalCamera = (isLogicalMultiCamera(metadata) == Status::OK);
-                    if (facing != ANDROID_LENS_FACING_BACK) {
-                        // Not BACK facing. Skip.
-                        return;
-                    }
-                    if (!isLogicalCamera) {
-                        rearColorCameras.insert(cameraId);
-                        return;
-                    }
-
-                    // Check logical camera's physical camera IDs for color
-                    // cameras.
-                    std::unordered_set<std::string> physicalCameraIds;
-                    Status s = getPhysicalCameraIds(metadata, &physicalCameraIds);
-                    ASSERT_EQ(Status::OK, s);
-                    rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
-                    for (const auto& physicalId : physicalCameraIds) {
-                        // Skip if the physicalId is publicly available
-                        for (auto& deviceName : cameraDeviceNames) {
-                            std::string publicVersion, publicId;
-                            ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType,
-                                                          &publicVersion, &publicId));
-                            if (physicalId == publicId) {
-                                // Skip because public Ids will be iterated in outer loop.
-                                return;
-                            }
-                        }
-
-                        auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x);
-                        ASSERT_TRUE(castResult.isOk());
-                        ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice>
-                                device3_5 = castResult;
-                        ASSERT_NE(device3_5, nullptr);
-
-                        // Check camera characteristics for hidden camera id
-                        Return<void> ret = device3_5->getPhysicalCameraCharacteristics(
-                                physicalId, [&](auto status, const auto& chars) {
-                            ASSERT_EQ(Status::OK, status);
-                            const camera_metadata_t* physicalMetadata =
-                                    (camera_metadata_t*)chars.data();
-
-                            if (CameraHidlTest::isColorCamera(physicalMetadata)) {
-                                rearColorCameras.insert(physicalId);
-                            }
-                        });
-                        ASSERT_TRUE(ret.isOk());
-                    }
-                });
-                ASSERT_TRUE(ret.isOk());
-            } break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                // Not applicable
-            } break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            } break;
-        }
-    }
-
-    // If there are more than one rear-facing color camera, a logical
-    // multi-camera must be defined consisting of all rear-facing color
-    // cameras.
-    if (rearColorCameras.size() > 1) {
-        bool hasRearLogical = false;
-        for (const auto& physicalIds : rearPhysicalIds) {
-            if (std::includes(physicalIds.begin(), physicalIds.end(),
-                    rearColorCameras.begin(), rearColorCameras.end())) {
-                hasRearLogical = true;
-                break;
-            }
-        }
-        ASSERT_TRUE(hasRearLogical);
-    }
-}
-
 // Retrieve all valid output stream resolutions from the camera
 // static characteristics.
 Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
@@ -6591,6 +7057,22 @@
     return ret;
 }
 
+bool CameraHidlTest::isTorchStrengthControlSupported(const camera_metadata_t *staticMetadata) {
+    int32_t maxLevel = 0;
+    camera_metadata_ro_entry maxEntry;
+    int rc = find_camera_metadata_ro_entry(staticMetadata,
+            ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL, &maxEntry);
+    if (rc != 0) {
+        return false;
+    }
+    maxLevel = *maxEntry.data.i32;
+    if (maxLevel > 1) {
+        ALOGI("Torch strength control supported.");
+        return true;
+    }
+    return false;
+}
+
 // Check if the camera device has logical multi-camera capability.
 Status CameraHidlTest::isOfflineSessionSupported(const camera_metadata_t *staticMeta) {
     Status ret = Status::METHOD_NOT_SUPPORTED;
@@ -6904,23 +7386,6 @@
     return ret;
 }
 
-bool CameraHidlTest::isColorCamera(const camera_metadata_t *metadata) {
-    camera_metadata_ro_entry entry;
-    int retcode = find_camera_metadata_ro_entry(
-            metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
-    if ((0 == retcode) && (entry.count > 0)) {
-        bool isBackwardCompatible = (std::find(entry.data.u8, entry.data.u8 + entry.count,
-                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) !=
-                entry.data.u8 + entry.count);
-        bool isMonochrome = (std::find(entry.data.u8, entry.data.u8 + entry.count,
-                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) !=
-                entry.data.u8 + entry.count);
-        bool isColor = isBackwardCompatible && !isMonochrome;
-        return isColor;
-    }
-    return false;
-}
-
 // Retrieve the reprocess input-output format map from the static
 // camera characteristics.
 Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta,
@@ -7076,8 +7541,9 @@
     sp<device::V3_4::ICameraDeviceSession> session3_4;
     sp<device::V3_5::ICameraDeviceSession> session3_5;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
+    sp<device::V3_8::ICameraDeviceSession> session3_8;
     castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
-                session3_7);
+                session3_7, &session3_8);
     ASSERT_NE(nullptr, (*session3_7).get());
 
     *useHalBufManager = false;
@@ -7125,7 +7591,8 @@
     ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7);
     sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
     sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
-    castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+    sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
+    castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
     ASSERT_NE(cameraDevice3_7, nullptr);
     bool supported = false;
     ret = cameraDevice3_7->isStreamCombinationSupported_3_7(
@@ -7158,6 +7625,153 @@
     ASSERT_TRUE(ret.isOk());
 }
 
+// Configure streams
+void CameraHidlTest::configureStreams3_8(
+        const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
+        PixelFormat format, sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
+        V3_2::Stream* previewStream /*out*/,
+        device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
+        bool* supportsPartialResults /*out*/, uint32_t* partialResultCount /*out*/,
+        bool* useHalBufManager /*out*/, sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
+        bool maxResolution,
+        CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof) {
+    ASSERT_NE(nullptr, session3_8);
+    ASSERT_NE(nullptr, halStreamConfig);
+    ASSERT_NE(nullptr, previewStream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, outCb);
+    ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8);
+
+    std::vector<AvailableStream> outputStreams;
+    ::android::sp<ICameraDevice> device3_x;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    Return<void> ret;
+    ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
+        ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_NE(device, nullptr);
+        device3_x = device;
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_t* staticMeta;
+    ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        staticMeta =
+                clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+        ASSERT_NE(nullptr, staticMeta);
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_ro_entry entry;
+    auto status =
+            find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
+    sp<ICameraDeviceSession> session;
+    ret = device3_x->open(cb, [&session](auto status, const auto& newSession) {
+        ALOGI("device::open returns status:%d", (int)status);
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_NE(newSession, nullptr);
+        session = newSession;
+    });
+    ASSERT_TRUE(ret.isOk());
+    *outCb = cb;
+
+    sp<device::V3_3::ICameraDeviceSession> session3_3;
+    sp<device::V3_4::ICameraDeviceSession> session3_4;
+    sp<device::V3_5::ICameraDeviceSession> session3_5;
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    sp<device::V3_7::ICameraDeviceSession> session3_7;
+    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                &session3_7, session3_8);
+    ASSERT_NE(nullptr, (*session3_8).get());
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    outputStreams.clear();
+    Size maxSize;
+    auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
+    ASSERT_EQ(Status::OK, rc);
+    free_camera_metadata(staticMeta);
+
+    ::android::hardware::hidl_vec<V3_8::Stream> streams3_8(1);
+    streams3_8[0].v3_7.groupId = -1;
+    streams3_8[0].v3_7.sensorPixelModesUsed = {
+            CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
+    streams3_8[0].v3_7.v3_4.bufferSize = 0;
+    streams3_8[0].v3_7.v3_4.v3_2.id = 0;
+    streams3_8[0].v3_7.v3_4.v3_2.streamType = StreamType::OUTPUT;
+    streams3_8[0].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(maxSize.width);
+    streams3_8[0].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(maxSize.height);
+    streams3_8[0].v3_7.v3_4.v3_2.format = static_cast<PixelFormat>(format);
+    streams3_8[0].v3_7.v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
+    streams3_8[0].v3_7.v3_4.v3_2.dataSpace = 0;
+    streams3_8[0].v3_7.v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
+    streams3_8[0].dynamicRangeProfile = prof;
+
+    ::android::hardware::camera::device::V3_8::StreamConfiguration config3_8;
+    config3_8.streams = streams3_8;
+    config3_8.operationMode = StreamConfigurationMode::NORMAL_MODE;
+    config3_8.streamConfigCounter = streamConfigCounter;
+    config3_8.multiResolutionInputImage = false;
+    RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+    ret = (*session3_8)
+                  ->constructDefaultRequestSettings(reqTemplate,
+                                                    [&config3_8](auto status, const auto& req) {
+                                                        ASSERT_EQ(Status::OK, status);
+                                                        config3_8.sessionParams = req;
+                                                    });
+    ASSERT_TRUE(ret.isOk());
+
+    sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
+    sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
+    sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
+    castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
+    ASSERT_NE(cameraDevice3_8, nullptr);
+    bool supported = false;
+    ret = cameraDevice3_8->isStreamCombinationSupported_3_8(
+            config3_8, [&supported](Status s, bool combStatus) {
+                ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
+                if (Status::OK == s) {
+                    supported = combStatus;
+                }
+            });
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(supported, true);
+
+    if (*session3_8 != nullptr) {
+        ret = (*session3_8)
+                      ->configureStreams_3_8(
+                              config3_8,
+                              [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
+                                  ASSERT_EQ(Status::OK, s);
+                                  *halStreamConfig = halConfig;
+                                  if (*useHalBufManager) {
+                                      hidl_vec<V3_4::Stream> streams(1);
+                                      hidl_vec<V3_2::HalStream> halStreams(1);
+                                      streams[0] = streams3_8[0].v3_7.v3_4;
+                                      halStreams[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
+                                      cb->setCurrentStreamConfig(streams, halStreams);
+                                  }
+                              });
+    }
+    *previewStream = streams3_8[0].v3_7.v3_4.v3_2;
+    ASSERT_TRUE(ret.isOk());
+}
+
 // Configure multiple preview streams using different physical ids.
 void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
@@ -7232,8 +7846,9 @@
     sp<device::V3_3::ICameraDeviceSession> session3_3;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
     sp<device::V3_7::ICameraDeviceSession> session3_7;
+    sp<device::V3_8::ICameraDeviceSession> session3_8;
     castSession(session, deviceVersion, &session3_3, session3_4, session3_5,
-            &session3_6, &session3_7);
+            &session3_6, &session3_7, &session3_8);
     ASSERT_NE(nullptr, (*session3_4).get());
 
     *useHalBufManager = false;
@@ -7278,7 +7893,8 @@
     if (allowUnsupport) {
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
+        castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
 
         bool supported = false;
         ret = cameraDevice3_5->isStreamCombinationSupported(config3_4,
@@ -7471,6 +8087,95 @@
     return false;
 }
 
+void CameraHidlTest::get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
+        std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles) {
+    ASSERT_NE(nullptr, staticMeta);
+    ASSERT_NE(nullptr, profiles);
+    camera_metadata_ro_entry entry;
+    std::unordered_set<int32_t> entries;
+    int rc = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, &entry);
+    ASSERT_EQ(rc, 0);
+    ASSERT_TRUE(entry.count > 0);
+    ASSERT_EQ(entry.count % 2, 0);
+
+    for (uint32_t i = 0; i < entry.count; i += 2) {
+        ASSERT_NE(entry.data.i32[i],
+                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+        ASSERT_EQ(entries.find(entry.data.i32[i]), entries.end());
+        entries.insert(static_cast<int32_t>(entry.data.i32[i]));
+        profiles->emplace_back(
+                static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
+                (entry.data.i32[i]));
+    }
+
+    if (!entries.empty()) {
+        ASSERT_NE(entries.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10),
+                entries.end());
+    }
+}
+
+bool CameraHidlTest::is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry scalarEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &scalarEntry);
+    if (rc == 0) {
+        for (uint32_t i = 0; i < scalarEntry.count; i++) {
+            if (scalarEntry.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void CameraHidlTest::verify10BitMetadata(HandleImporter& importer,
+        const InFlightRequest& request,
+        CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile) {
+    for (const auto& b : request.resultOutputBuffers) {
+        bool smpte2086Present = importer.isSmpte2086Present(b.buffer.buffer.getNativeHandle());
+        bool smpte2094_10Present = importer.isSmpte2094_10Present(
+                b.buffer.buffer.getNativeHandle());
+        bool smpte2094_40Present = importer.isSmpte2094_40Present(
+                b.buffer.buffer.getNativeHandle());
+
+        switch (static_cast<uint32_t>(profile)) {
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
+                ASSERT_FALSE(smpte2086Present);
+                ASSERT_FALSE(smpte2094_10Present);
+                ASSERT_FALSE(smpte2094_40Present);
+                break;
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+                ASSERT_TRUE(smpte2086Present);
+                ASSERT_FALSE(smpte2094_10Present);
+                ASSERT_FALSE(smpte2094_40Present);
+                break;
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+                ASSERT_FALSE(smpte2086Present);
+                ASSERT_FALSE(smpte2094_10Present);
+                ASSERT_TRUE(smpte2094_40Present);
+                break;
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO:
+                ASSERT_FALSE(smpte2086Present);
+                ASSERT_TRUE(smpte2094_10Present);
+                ASSERT_FALSE(smpte2094_40Present);
+                break;
+            default:
+                ALOGE("%s: Unexpected 10-bit dynamic range profile: %d",
+                        __FUNCTION__, profile);
+                ADD_FAILURE();
+        }
+    }
+}
+
 bool CameraHidlTest::isDepthOnly(const camera_metadata_t* staticMeta) {
     camera_metadata_ro_entry scalarEntry;
     camera_metadata_ro_entry depthEntry;
@@ -7527,6 +8232,47 @@
                           previewStream, halStreamConfig, supportsPartialResults,
                           partialResultCount, useHalBufManager, outCb, streamConfigCounter);
 }
+
+bool CameraHidlTest::supportsPreviewStabilization(const std::string& name,
+                                                  sp<ICameraProvider> provider) {
+    Return<void> ret;
+    sp<ICameraDevice> device3_x = nullptr;
+    ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
+        ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_NE(device, nullptr);
+        device3_x = device;
+    });
+    if (!(ret.isOk())) {
+        ADD_FAILURE() << "Failed to get camera device interface for " << name;
+    }
+
+    camera_metadata_t* staticMeta = nullptr;
+    ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        staticMeta =
+                clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+    });
+    if (!(ret.isOk())) {
+        ADD_FAILURE() << "Failed to get camera characteristics for " << name;
+    }
+    // Go through the characteristics and see if video stabilization modes have
+    // preview stabilization
+    camera_metadata_ro_entry entry;
+
+    int retcode = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (auto i = 0; i < entry.count; i++) {
+            if (entry.data.u8[i] ==
+                ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 // Open a device session and configure a preview stream.
 void CameraHidlTest::configureSingleStream(
         const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
@@ -7593,8 +8339,9 @@
     sp<device::V3_5::ICameraDeviceSession> session3_5;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
     sp<device::V3_7::ICameraDeviceSession> session3_7;
+    sp<device::V3_8::ICameraDeviceSession> session3_8;
     castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5,
-            &session3_6, &session3_7);
+            &session3_6, &session3_7, &session3_8);
 
     *useHalBufManager = false;
     status = find_camera_metadata_ro_entry(staticMeta,
@@ -7725,12 +8472,19 @@
 void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice>& device,
                                 int32_t deviceVersion,
                                 sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
-                                sp<device::V3_7::ICameraDevice>* device3_7 /*out*/) {
+                                sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
+                                sp<device::V3_8::ICameraDevice>* device3_8 /*out*/) {
     ASSERT_NE(nullptr, device3_5);
     ASSERT_NE(nullptr, device3_7);
+    ASSERT_NE(nullptr, device3_8);
 
     switch (deviceVersion) {
-        case CAMERA_DEVICE_API_VERSION_3_8:
+        case CAMERA_DEVICE_API_VERSION_3_8: {
+            auto castResult = device::V3_8::ICameraDevice::castFrom(device);
+            ASSERT_TRUE(castResult.isOk());
+            *device3_8 = castResult;
+        }
+            [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_7: {
             auto castResult = device::V3_7::ICameraDevice::castFrom(device);
             ASSERT_TRUE(castResult.isOk());
@@ -7779,15 +8533,22 @@
         sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
         sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
         sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
-        sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/) {
+        sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
+        sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/) {
     ASSERT_NE(nullptr, session3_3);
     ASSERT_NE(nullptr, session3_4);
     ASSERT_NE(nullptr, session3_5);
     ASSERT_NE(nullptr, session3_6);
     ASSERT_NE(nullptr, session3_7);
+    ASSERT_NE(nullptr, session3_8);
 
     switch (deviceVersion) {
-        case CAMERA_DEVICE_API_VERSION_3_8:
+        case CAMERA_DEVICE_API_VERSION_3_8: {
+            auto castResult = device::V3_8::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_8 = castResult;
+        }
+        [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_7: {
             auto castResult = device::V3_7::ICameraDeviceSession::castFrom(session);
             ASSERT_TRUE(castResult.isOk());
@@ -8664,8 +9425,9 @@
     sp<device::V3_5::ICameraDeviceSession> session3_5;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
     sp<device::V3_7::ICameraDeviceSession> session3_7;
+    sp<device::V3_8::ICameraDeviceSession> session3_8;
     castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-            &session3_6, &session3_7);
+            &session3_6, &session3_7, &session3_8);
     ASSERT_NE(nullptr, session3_5.get());
 
     hidl_vec<int32_t> streamIds(1);
@@ -8907,7 +9669,7 @@
     size_t CONFIG_ENTRY_TYPE_OFFSET = 3;
     size_t CONFIG_ENTRY_BITFIELD_OFFSET = 4;
     uint32_t maxPublicUsecase =
-            ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END;
+            ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8;
     uint32_t vendorUsecaseStart =
             ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START;
     uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1;
diff --git a/camera/provider/2.7/default/Android.bp b/camera/provider/2.7/default/Android.bp
new file mode 100644
index 0000000..bd5da2d
--- /dev/null
+++ b/camera/provider/2.7/default/Android.bp
@@ -0,0 +1,111 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "android.hardware.camera.provider@2.7-external",
+    proprietary: true,
+    srcs: ["ExternalCameraProviderImpl_2_7.cpp"],
+    shared_libs: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+        "android.hardware.camera.device@3.6",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.provider@2.5",
+        "android.hardware.camera.provider@2.6",
+        "android.hardware.camera.provider@2.7",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "camera.device@3.3-impl",
+        "camera.device@3.4-external-impl",
+        "camera.device@3.4-impl",
+        "camera.device@3.5-external-impl",
+        "camera.device@3.5-impl",
+        "camera.device@3.6-external-impl",
+        "libcamera_metadata",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libtinyxml2",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    header_libs: [
+        "camera.device@3.4-external-impl_headers",
+        "camera.device@3.5-external-impl_headers",
+        "camera.device@3.6-external-impl_headers",
+    ],
+    export_include_dirs: ["."],
+}
+
+cc_defaults {
+    name: "camera_external_service_2_7_defaults",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: ["external-service.cpp"],
+    compile_multilib: "32",
+    shared_libs: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.provider@2.4-external",
+        "android.hardware.camera.provider@2.5",
+        "android.hardware.camera.provider@2.5-external",
+        "android.hardware.camera.provider@2.6",
+        "android.hardware.camera.provider@2.7",
+        "android.hardware.camera.provider@2.7-external",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "libbinder",
+        "libcamera_metadata",
+        "libhidlbase",
+        "liblog",
+        "libtinyxml2",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    header_libs: [
+        "camera.device@3.4-external-impl_headers",
+        "camera.device@3.4-impl_headers",
+        "camera.device@3.5-external-impl_headers",
+        "camera.device@3.5-impl_headers",
+        "camera.device@3.6-external-impl_headers",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.camera.provider@2.7-external-service",
+    defaults: ["camera_external_service_2_7_defaults"],
+    init_rc: ["android.hardware.camera.provider@2.7-external-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.camera.provider@2.7-external-service-lazy",
+    overrides: ["android.hardware.camera.provider@2.7-external-service"],
+    defaults: ["camera_external_service_2_7_defaults"],
+    init_rc: ["android.hardware.camera.provider@2.7-external-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/camera/provider/2.7/default/CameraProvider_2_7.h b/camera/provider/2.7/default/CameraProvider_2_7.h
new file mode 100644
index 0000000..c34905f
--- /dev/null
+++ b/camera/provider/2.7/default/CameraProvider_2_7.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_CAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_CAMERAPROVIDER_H
+
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
+#include <android/hardware/camera/provider/2.7/ICameraProvider.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_7 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::common::V1_0::VendorTag;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::provider::V2_5::DeviceState;
+using ::android::hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
+using ::android::hardware::camera::provider::V2_7::ICameraProvider;
+using ::android::hidl::base::V1_0::IBase;
+
+// Default recommended RPC thread count for camera provider implementations
+const int HWBINDER_THREAD_COUNT = 6;
+
+template <typename IMPL>
+struct CameraProvider : public ICameraProvider {
+    CameraProvider() : impl() {}
+    ~CameraProvider() {}
+
+    // Caller must use this method to check if CameraProvider ctor failed
+    bool isInitFailed() { return impl.isInitFailed(); }
+
+    // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+    Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override {
+        return impl.setCallback(callback);
+    }
+
+    Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override {
+        return impl.getVendorTags(_hidl_cb);
+    }
+
+    Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override {
+        return impl.getCameraIdList(_hidl_cb);
+    }
+
+    Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override {
+        return impl.isSetTorchModeSupported(_hidl_cb);
+    }
+
+    Return<void> getCameraDeviceInterface_V1_x(const hidl_string& cameraDeviceName,
+                                               getCameraDeviceInterface_V1_x_cb _hidl_cb) override {
+        return impl.getCameraDeviceInterface_V1_x(cameraDeviceName, _hidl_cb);
+    }
+
+    Return<void> getCameraDeviceInterface_V3_x(const hidl_string& cameraDeviceName,
+                                               getCameraDeviceInterface_V3_x_cb _hidl_cb) override {
+        return impl.getCameraDeviceInterface_V3_x(cameraDeviceName, _hidl_cb);
+    }
+
+    // Methods from ::android::hardware::camera::provider::V2_5::ICameraProvider follow.
+    Return<void> notifyDeviceStateChange(hardware::hidl_bitfield<DeviceState> newState) override {
+        return impl.notifyDeviceStateChange(newState);
+    }
+
+    // Methods from ::android::hardware::camera::provider::V2_7::ICameraProvider follow.
+    Return<void> getConcurrentStreamingCameraIds(
+            getConcurrentStreamingCameraIds_cb _hidl_cb) override {
+        return impl.getConcurrentStreamingCameraIds(_hidl_cb);
+    }
+
+    Return<void> isConcurrentStreamCombinationSupported(
+            const hidl_vec<
+                    ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination>&
+                    configs,
+            isConcurrentStreamCombinationSupported_cb _hidl_cb) override {
+        return impl.isConcurrentStreamCombinationSupported(configs, _hidl_cb);
+    }
+
+    Return<void> isConcurrentStreamCombinationSupported_2_7(
+            const hidl_vec<CameraIdAndStreamCombination>& configs,
+            isConcurrentStreamCombinationSupported_2_7_cb _hidl_cb) override {
+        return impl.isConcurrentStreamCombinationSupported_2_7(configs, _hidl_cb);
+    }
+
+  private:
+    IMPL impl;
+};
+
+}  // namespace implementation
+}  // namespace V2_7
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
\ No newline at end of file
diff --git a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
new file mode 100644
index 0000000..b63e3bb
--- /dev/null
+++ b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamPrvdr@2.7-external"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include <cutils/properties.h>
+#include <errno.h>
+#include <linux/videodev2.h>
+#include <sys/inotify.h>
+#include <regex>
+#include "ExternalCameraDevice_3_4.h"
+#include "ExternalCameraDevice_3_5.h"
+#include "ExternalCameraDevice_3_6.h"
+#include "ExternalCameraProviderImpl_2_7.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_7 {
+namespace implementation {
+
+namespace {
+// "device@<version>/external/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
+const int kMaxDevicePathLen = 256;
+const char* kDevicePath = "/dev/";
+constexpr char kPrefix[] = "video";
+constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
+
+bool matchDeviceName(int cameraIdOffset, const hidl_string& deviceName, std::string* deviceVersion,
+                     std::string* cameraDevicePath) {
+    std::string deviceNameStd(deviceName.c_str());
+    std::smatch sm;
+    if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
+        if (deviceVersion != nullptr) {
+            *deviceVersion = sm[1];
+        }
+        if (cameraDevicePath != nullptr) {
+            *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
+        }
+        return true;
+    }
+    return false;
+}
+
+}  // anonymous namespace
+
+ExternalCameraProviderImpl_2_7::ExternalCameraProviderImpl_2_7()
+    : mCfg(ExternalCameraConfig::loadFromCfg()) {
+    mHotPlugThread = sp<HotplugThread>::make(this);
+    mHotPlugThread->run("ExtCamHotPlug", PRIORITY_BACKGROUND);
+
+    mPreferredHal3MinorVersion =
+            property_get_int32("ro.vendor.camera.external.hal3TrebleMinorVersion", 4);
+    ALOGV("Preferred HAL 3 minor version is %d", mPreferredHal3MinorVersion);
+    switch (mPreferredHal3MinorVersion) {
+        case 4:
+        case 5:
+        case 6:
+            // OK
+            break;
+        default:
+            ALOGW("Unknown minor camera device HAL version %d in property "
+                  "'camera.external.hal3TrebleMinorVersion', defaulting to 4",
+                  mPreferredHal3MinorVersion);
+            mPreferredHal3MinorVersion = 4;
+    }
+}
+
+ExternalCameraProviderImpl_2_7::~ExternalCameraProviderImpl_2_7() {
+    mHotPlugThread->requestExit();
+}
+
+Return<Status> ExternalCameraProviderImpl_2_7::setCallback(
+        const sp<ICameraProviderCallback>& callback) {
+    Mutex::Autolock _l(mLock);
+    mCallbacks = callback;
+    if (mCallbacks == nullptr) {
+        return Status::OK;
+    }
+    // Send a callback for all devices to initialize
+    {
+        for (const auto& pair : mCameraStatusMap) {
+            mCallbacks->cameraDeviceStatusChange(pair.first, pair.second);
+        }
+    }
+
+    return Status::OK;
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getVendorTags(
+        ICameraProvider::getVendorTags_cb _hidl_cb) {
+    // No vendor tag support for USB camera
+    hidl_vec<VendorTagSection> zeroSections;
+    _hidl_cb(Status::OK, zeroSections);
+    return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getCameraIdList(
+        ICameraProvider::getCameraIdList_cb _hidl_cb) {
+    // External camera HAL always report 0 camera, and extra cameras
+    // are just reported via cameraDeviceStatusChange callbacks
+    hidl_vec<hidl_string> hidlDeviceNameList;
+    _hidl_cb(Status::OK, hidlDeviceNameList);
+    return Void();
+}
+
+void ExternalCameraProviderImpl_2_7::updateAttachedCameras() {
+    ALOGV("%s start scaning for existing V4L2 devices", __FUNCTION__);
+    // Find existing /dev/video* devices
+    DIR* devdir = opendir(kDevicePath);
+    if (devdir == 0) {
+        ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath);
+        return;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(devdir)) != 0) {
+        // Find external v4l devices that's existing before we start watching and add them
+        if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {
+            // TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
+            //       is added.
+            std::string deviceId(de->d_name + kPrefixLen);
+            if (mCfg.mInternalDevices.count(deviceId) == 0) {
+                ALOGV("Non-internal v4l device %s found", de->d_name);
+                char v4l2DevicePath[kMaxDevicePathLen];
+                snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath, de->d_name);
+                deviceAdded(v4l2DevicePath);
+            }
+        }
+    }
+    closedir(devdir);
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::isSetTorchModeSupported(
+        ICameraProvider::isSetTorchModeSupported_cb _hidl_cb) {
+    // setTorchMode API is supported, though right now no external camera device
+    // has a flash unit.
+    _hidl_cb(Status::OK, true);
+    return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getCameraDeviceInterface_V1_x(
+        const hidl_string&, ICameraProvider::getCameraDeviceInterface_V1_x_cb _hidl_cb) {
+    // External Camera HAL does not support HAL1
+    _hidl_cb(Status::OPERATION_NOT_SUPPORTED, nullptr);
+    return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getCameraDeviceInterface_V3_x(
+        const hidl_string& cameraDeviceName,
+        ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) {
+    std::string cameraDevicePath, deviceVersion;
+    bool match = matchDeviceName(mCfg.cameraIdOffset, cameraDeviceName, &deviceVersion,
+                                 &cameraDevicePath);
+    if (!match) {
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    if (mCameraStatusMap.count(cameraDeviceName) == 0 ||
+        mCameraStatusMap[cameraDeviceName] != CameraDeviceStatus::PRESENT) {
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl;
+    switch (mPreferredHal3MinorVersion) {
+        case 4: {
+            ALOGV("Constructing v3.4 external camera device");
+            deviceImpl =
+                    new device::V3_4::implementation::ExternalCameraDevice(cameraDevicePath, mCfg);
+            break;
+        }
+        case 5: {
+            ALOGV("Constructing v3.5 external camera device");
+            deviceImpl =
+                    new device::V3_5::implementation::ExternalCameraDevice(cameraDevicePath, mCfg);
+            break;
+        }
+        case 6: {
+            ALOGV("Constructing v3.6 external camera device");
+            deviceImpl =
+                    new device::V3_6::implementation::ExternalCameraDevice(cameraDevicePath, mCfg);
+            break;
+        }
+        default:
+            ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
+            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+            return Void();
+    }
+
+    if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
+        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+        return Void();
+    }
+
+    IF_ALOGV() {
+        deviceImpl->getInterface()->interfaceChain(
+                [](::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                    ALOGV("Device interface chain:");
+                    for (auto iface : interfaceChain) {
+                        ALOGV("  %s", iface.c_str());
+                    }
+                });
+    }
+
+    _hidl_cb(Status::OK, deviceImpl->getInterface());
+
+    return Void();
+}
+
+void ExternalCameraProviderImpl_2_7::addExternalCamera(const char* devName) {
+    ALOGV("ExtCam: adding %s to External Camera HAL!", devName);
+    Mutex::Autolock _l(mLock);
+    std::string deviceName;
+    std::string cameraId =
+            std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + cameraId;
+    } else if (mPreferredHal3MinorVersion == 5) {
+        deviceName = std::string("device@3.5/external/") + cameraId;
+    } else {
+        deviceName = std::string("device@3.4/external/") + cameraId;
+    }
+    mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
+    if (mCallbacks != nullptr) {
+        mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
+    }
+}
+
+void ExternalCameraProviderImpl_2_7::deviceAdded(const char* devName) {
+    {
+        base::unique_fd fd(::open(devName, O_RDWR));
+        if (fd.get() < 0) {
+            ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
+            return;
+        }
+
+        struct v4l2_capability capability;
+        int ret = ioctl(fd.get(), VIDIOC_QUERYCAP, &capability);
+        if (ret < 0) {
+            ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
+            return;
+        }
+
+        if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+            ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
+            return;
+        }
+    }
+    // See if we can initialize ExternalCameraDevice correctly
+    sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
+            new device::V3_4::implementation::ExternalCameraDevice(devName, mCfg);
+    if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+        ALOGW("%s: Attempt to init camera device %s failed!", __FUNCTION__, devName);
+        return;
+    }
+    deviceImpl.clear();
+
+    addExternalCamera(devName);
+    return;
+}
+
+void ExternalCameraProviderImpl_2_7::deviceRemoved(const char* devName) {
+    Mutex::Autolock _l(mLock);
+    std::string deviceName;
+    std::string cameraId =
+            std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + cameraId;
+    } else if (mPreferredHal3MinorVersion == 5) {
+        deviceName = std::string("device@3.5/external/") + cameraId;
+    } else {
+        deviceName = std::string("device@3.4/external/") + cameraId;
+    }
+    if (mCameraStatusMap.erase(deviceName) != 0) {
+        if (mCallbacks != nullptr) {
+            mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::NOT_PRESENT);
+        }
+    } else {
+        ALOGE("%s: cannot find camera device %s", __FUNCTION__, devName);
+    }
+}
+
+ExternalCameraProviderImpl_2_7::HotplugThread::HotplugThread(ExternalCameraProviderImpl_2_7* parent)
+    : Thread(/*canCallJava*/ false),
+      mParent(parent),
+      mInternalDevices(parent->mCfg.mInternalDevices) {}
+
+ExternalCameraProviderImpl_2_7::HotplugThread::~HotplugThread() {}
+
+bool ExternalCameraProviderImpl_2_7::HotplugThread::threadLoop() {
+    // Update existing cameras
+    mParent->updateAttachedCameras();
+
+    // Watch new video devices
+    mINotifyFD = inotify_init();
+    if (mINotifyFD < 0) {
+        ALOGE("%s: inotify init failed! Exiting threadloop", __FUNCTION__);
+        return true;
+    }
+
+    mWd = inotify_add_watch(mINotifyFD, kDevicePath, IN_CREATE | IN_DELETE);
+    if (mWd < 0) {
+        ALOGE("%s: inotify add watch failed! Exiting threadloop", __FUNCTION__);
+        return true;
+    }
+
+    bool done = false;
+    char eventBuf[512];
+    while (!done) {
+        int offset = 0;
+        int ret = read(mINotifyFD, eventBuf, sizeof(eventBuf));
+        if (ret >= (int)sizeof(struct inotify_event)) {
+            while (offset < ret) {
+                struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
+                if (event->wd == mWd) {
+                    ALOGV("%s inotify_event %s", __FUNCTION__, event->name);
+                    if (!strncmp(kPrefix, event->name, kPrefixLen)) {
+                        std::string deviceId(event->name + kPrefixLen);
+                        if (mInternalDevices.count(deviceId) == 0) {
+                            char v4l2DevicePath[kMaxDevicePathLen];
+                            snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath,
+                                     event->name);
+                            if (event->mask & IN_CREATE) {
+                                mParent->deviceAdded(v4l2DevicePath);
+                            }
+                            if (event->mask & IN_DELETE) {
+                                mParent->deviceRemoved(v4l2DevicePath);
+                            }
+                        }
+                    }
+                }
+                offset += sizeof(struct inotify_event) + event->len;
+            }
+        }
+    }
+
+    return true;
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::notifyDeviceStateChange(
+        hidl_bitfield<DeviceState> /*newState*/) {
+    return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getConcurrentStreamingCameraIds(
+        ICameraProvider::getConcurrentStreamingCameraIds_cb _hidl_cb) {
+    hidl_vec<hidl_vec<hidl_string>> hidl_camera_id_combinations;
+    _hidl_cb(Status::OK, hidl_camera_id_combinations);
+    return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::isConcurrentStreamCombinationSupported(
+        const hidl_vec<::android::hardware::camera::provider::V2_6::
+                               CameraIdAndStreamCombination>& /* configs */,
+        ICameraProvider::isConcurrentStreamCombinationSupported_cb _hidl_cb) {
+    _hidl_cb(Status::OK, false);
+    return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::isConcurrentStreamCombinationSupported_2_7(
+        const hidl_vec<CameraIdAndStreamCombination>& /* configs */,
+        ICameraProvider::isConcurrentStreamCombinationSupported_2_7_cb _hidl_cb) {
+    _hidl_cb(Status::OK, false);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_7
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.h b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.h
new file mode 100644
index 0000000..da9f6b3
--- /dev/null
+++ b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_EXTCAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_EXTCAMERAPROVIDER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include "ExternalCameraUtils.h"
+
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
+#include <android/hardware/camera/provider/2.7/ICameraProvider.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_7 {
+namespace implementation {
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::provider::V2_5::DeviceState;
+using ::android::hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
+using ::android::hardware::camera::provider::V2_7::ICameraProvider;
+using ::android::hidl::base::V1_0::IBase;
+
+/**
+ * The implementation of external webcam CameraProvider 2.7, separated
+ * from the HIDL interface layer to allow for implementation reuse by later
+ * provider versions.
+ *
+ * This camera provider supports standard UVC webcameras via the Linux V4L2
+ * UVC driver.
+ */
+struct ExternalCameraProviderImpl_2_7 {
+    ExternalCameraProviderImpl_2_7();
+    ~ExternalCameraProviderImpl_2_7();
+
+    // Caller must use this method to check if CameraProvider ctor failed
+    bool isInitFailed() { return false; }
+
+    // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+    Return<Status> setCallback(const sp<ICameraProviderCallback>& callback);
+    Return<void> getVendorTags(ICameraProvider::getVendorTags_cb _hidl_cb);
+    Return<void> getCameraIdList(ICameraProvider::getCameraIdList_cb _hidl_cb);
+    Return<void> isSetTorchModeSupported(ICameraProvider::isSetTorchModeSupported_cb _hidl_cb);
+    Return<void> getCameraDeviceInterface_V1_x(const hidl_string&,
+                                               ICameraProvider::getCameraDeviceInterface_V1_x_cb);
+    Return<void> getCameraDeviceInterface_V3_x(const hidl_string&,
+                                               ICameraProvider::getCameraDeviceInterface_V3_x_cb);
+
+    // Methods from ::android::hardware::camera::provider::V2_5::ICameraProvider follow.
+    Return<void> notifyDeviceStateChange(hidl_bitfield<DeviceState> newState);
+
+    // Methods from ::android::hardware::camera::provider::V2_7::ICameraProvider follow.
+    Return<void> getConcurrentStreamingCameraIds(
+            ICameraProvider::getConcurrentStreamingCameraIds_cb _hidl_cb);
+
+    Return<void> isConcurrentStreamCombinationSupported(
+            const hidl_vec<
+                    ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination>&
+                    configs,
+            ICameraProvider::isConcurrentStreamCombinationSupported_cb _hidl_cb);
+
+    Return<void> isConcurrentStreamCombinationSupported_2_7(
+            const hidl_vec<CameraIdAndStreamCombination>& configs,
+            ICameraProvider::isConcurrentStreamCombinationSupported_2_7_cb _hidl_cb);
+
+  private:
+    void addExternalCamera(const char* devName);
+
+    void deviceAdded(const char* devName);
+
+    void deviceRemoved(const char* devName);
+
+    void updateAttachedCameras();
+
+    class HotplugThread : public android::Thread {
+      public:
+        HotplugThread(ExternalCameraProviderImpl_2_7* parent);
+        ~HotplugThread();
+
+        virtual bool threadLoop() override;
+
+      private:
+        ExternalCameraProviderImpl_2_7* mParent = nullptr;
+        const std::unordered_set<std::string> mInternalDevices;
+
+        int mINotifyFD = -1;
+        int mWd = -1;
+    };
+
+    Mutex mLock;
+    sp<ICameraProviderCallback> mCallbacks = nullptr;
+    std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap;  // camera id -> status
+    const ExternalCameraConfig mCfg;
+    sp<HotplugThread> mHotPlugThread;
+    int mPreferredHal3MinorVersion;
+};
+
+}  // namespace implementation
+}  // namespace V2_7
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_EXTCAMERAPROVIDER_H
diff --git a/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service-lazy.rc b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service-lazy.rc
new file mode 100644
index 0000000..9292c4f
--- /dev/null
+++ b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service-lazy.rc
@@ -0,0 +1,13 @@
+service vendor.camera-provider-2-7-ext /vendor/bin/hw/android.hardware.camera.provider@2.7-external-service-lazy
+    interface android.hardware.camera.provider@2.4::ICameraProvider external/0
+    interface android.hardware.camera.provider@2.5::ICameraProvider external/0
+    interface android.hardware.camera.provider@2.6::ICameraProvider external/0
+    interface android.hardware.camera.provider@2.7::ICameraProvider external/0
+    class hal
+    oneshot
+    disabled
+    user cameraserver
+    group audio camera input drmrpc usb
+    ioprio rt 4
+    capabilities SYS_NICE
+    task_profiles CameraServiceCapacity MaxPerformance
\ No newline at end of file
diff --git a/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service.rc b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service.rc
new file mode 100644
index 0000000..2c9b782
--- /dev/null
+++ b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service.rc
@@ -0,0 +1,11 @@
+service vendor.camera-provider-2-7-ext /vendor/bin/hw/android.hardware.camera.provider@2.7-external-service
+    interface android.hardware.camera.provider@2.4::ICameraProvider external/0
+    interface android.hardware.camera.provider@2.5::ICameraProvider external/0
+    interface android.hardware.camera.provider@2.6::ICameraProvider external/0
+    interface android.hardware.camera.provider@2.7::ICameraProvider external/0
+    class hal
+    user cameraserver
+    group audio camera input drmrpc usb
+    ioprio rt 4
+    capabilities SYS_NICE
+    task_profiles CameraServiceCapacity MaxPerformance
diff --git a/camera/provider/2.7/default/external-service.cpp b/camera/provider/2.7/default/external-service.cpp
new file mode 100644
index 0000000..90b8239
--- /dev/null
+++ b/camera/provider/2.7/default/external-service.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.camera.provider@2.7-external-service-lazy"
+#else
+#define LOG_TAG "android.hardware.camera.provider@2.7-external-service"
+#endif
+
+#include <android/hardware/camera/provider/2.7/ICameraProvider.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "CameraProvider_2_7.h"
+#include "ExternalCameraProviderImpl_2_7.h"
+
+using android::status_t;
+using android::hardware::camera::provider::V2_7::ICameraProvider;
+using android::hidl::base::V1_0::IBase;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+    using namespace android::hardware::camera::provider::V2_7::implementation;
+
+    ALOGI("CameraProvider@2.7 external webcam service is starting.");
+
+    ::android::hardware::configureRpcThreadpool(/*threads*/ HWBINDER_THREAD_COUNT,
+                                                /*willJoin*/ true);
+
+    ::android::sp<CameraProvider<ExternalCameraProviderImpl_2_7>> provider =
+            new CameraProvider<ExternalCameraProviderImpl_2_7>();
+
+    status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = ::android::hardware::LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(provider, "external/0");
+    } else {
+        status = provider->registerAsService("external/0");
+    }
+
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering provider service: %d",
+                        status);
+
+    ::android::hardware::joinRpcThreadpool();
+
+    return 0;
+}
\ No newline at end of file
diff --git a/common/support/Android.bp b/common/support/Android.bp
index b24893b..12ab1f7 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -11,7 +11,11 @@
     name: "libaidlcommonsupport",
     vendor_available: true,
     host_supported: true,
-    defaults: ["libbinder_ndk_host_user"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
     srcs: ["NativeHandle.cpp"],
     export_include_dirs: ["include"],
     shared_libs: [
@@ -21,6 +25,7 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.neuralnetworks",
+        "com.android.media.swcodec",
     ],
     min_sdk_version: "29",
 }
@@ -28,7 +33,11 @@
 cc_test {
     name: "libaidlcommonsupport_test",
     host_supported: true,
-    defaults: ["libbinder_ndk_host_user"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
     srcs: ["test.cpp"],
     static_libs: [
         "android.hardware.common-V2-ndk",
diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml
index a75ed25..468735d 100644
--- a/compatibility_matrices/compatibility_matrix.3.xml
+++ b/compatibility_matrices/compatibility_matrix.3.xml
@@ -207,7 +207,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL health HAL must exist on the device.
+         If the HIDL health HAL exists, it must be at least version 2.0.
+         See DeviceManifestTest.HealthHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.health</name>
         <version>2.0</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index 3b8ee21..96f291f 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -213,7 +213,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL health HAL must exist on the device.
+         If the HIDL health HAL exists, it must be at least version 2.0.
+         See DeviceManifestTest.HealthHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.health</name>
         <version>2.0</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index 0fb21a7..3642814 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -238,7 +238,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL health HAL must exist on the device.
+         If the HIDL health HAL exists, it must be at least version 2.1.
+         See DeviceManifestTest.HealthHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.health</name>
         <version>2.1</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml
index aee2c51..9c42cb0 100644
--- a/compatibility_matrices/compatibility_matrix.6.xml
+++ b/compatibility_matrices/compatibility_matrix.6.xml
@@ -268,7 +268,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL health HAL must exist on the device.
+         If the HIDL health HAL exists, it must be at least version 2.1.
+         See DeviceManifestTest.HealthHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.health</name>
         <version>2.1</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 3a5f5ef..e6dd1bf 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -60,6 +60,14 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.automotive.evs</name>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>default</instance>
+            <regex-instance>[a-z]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.automotive.evs</name>
         <version>1.0-1</version>
@@ -77,14 +85,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.sv</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISurroundViewService</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.automotive.vehicle</name>
         <interface>
@@ -110,6 +110,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.biometrics.face</name>
+        <version>2</version>
         <interface>
             <name>IFace</name>
             <instance>default</instance>
@@ -147,6 +148,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.bluetooth.audio</name>
+        <interface>
+            <name>IBluetoothAudioProviderFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.boot</name>
         <version>1.2</version>
@@ -202,12 +210,16 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.contexthub</name>
-        <version>1.2</version>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.drm</name>
+        <version>1</version>
         <interface>
-            <name>IContexthub</name>
-            <instance>default</instance>
+            <name>ICryptoFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>IDrmFactory</name>
+            <regex-instance>.*</regex-instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
@@ -222,9 +234,8 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="aidl" optional="true">
         <name>android.hardware.dumpstate</name>
-        <version>1.1</version>
         <interface>
             <name>IDumpstateDevice</name>
             <instance>default</instance>
@@ -254,6 +265,22 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.gnss.visibility_control</name>
+        <version>1</version>
+        <interface>
+            <name>IGnssVisibilityControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.gnss.measurement_corrections</name>
+        <version>1</version>
+        <interface>
+            <name>IMeasurementCorrectionsInterface</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.allocator</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
@@ -265,6 +292,14 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.graphics.allocator</name>
+        <version>1</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.composer</name>
         <version>2.1-4</version>
@@ -292,16 +327,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.health</name>
-        <version>2.1</version>
-        <interface>
-            <name>IHealth</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <!-- TODO(b/177269435): require health AIDL HAL and deprecate HIDL HAL -->
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="false">
         <name>android.hardware.health</name>
         <version>1</version>
         <interface>
@@ -319,13 +345,20 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.identity</name>
-        <version>1-3</version>
+        <version>1-4</version>
         <interface>
             <name>IIdentityCredentialStore</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.net.nlinterceptor</name>
+        <interface>
+            <name>IInterceptor</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.oemlock</name>
         <version>1</version>
         <interface>
@@ -333,9 +366,9 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="aidl" optional="true">
         <name>android.hardware.ir</name>
-        <version>1.0</version>
+        <version>1</version>
         <interface>
             <name>IConsumerIr</name>
             <instance>default</instance>
@@ -367,9 +400,17 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
-        <name>android.hardware.security.keymint</name>
+        <name>android.hardware.security.dice</name>
         <version>1</version>
         <interface>
+            <name>IDiceDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.security.keymint</name>
+        <version>1-2</version>
+        <interface>
             <name>IKeyMintDevice</name>
             <instance>default</instance>
             <instance>strongbox</instance>
@@ -377,9 +418,11 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.security.keymint</name>
+        <version>1-2</version>
         <interface>
             <name>IRemotelyProvisionedComponent</name>
             <instance>default</instance>
+            <instance>strongbox</instance>
         </interface>
     </hal>
     <hal format="aidl" optional="true">
@@ -429,7 +472,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.neuralnetworks</name>
-        <version>1-3</version>
+        <version>1-4</version>
         <interface>
             <name>IDevice</name>
             <regex-instance>.*</regex-instance>
@@ -443,6 +486,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.nfc</name>
+        <interface>
+            <name>INfc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.oemlock</name>
         <version>1.0</version>
@@ -453,7 +503,7 @@
     </hal>
     <hal format="aidl" optional="false">
         <name>android.hardware.power</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IPower</name>
             <instance>default</instance>
@@ -613,6 +663,13 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.sensors</name>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
@@ -654,7 +711,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl" optional="false">
         <name>android.hardware.thermal</name>
         <version>2.0</version>
         <interface>
@@ -751,7 +808,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi</name>
-        <version>1.3-5</version>
+        <version>1.3-6</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
@@ -789,4 +846,11 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.wifi.supplicant</name>
+        <interface>
+            <name>ISupplicant</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
 </compatibility-matrix>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 2aa4bb2..414c502 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -56,6 +56,7 @@
             "android.hardware.common",
             "android.hardware.common.fmq",
             "android.hardware.graphics.common",
+            "android.hardware.input.common",
             "android.hardware.keymaster",
             "android.hardware.radio",
             "android.hardware.uwb.fira_android",
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HostEndpointInfo.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HostEndpointInfo.aidl
index e7dcbc7..84e8531 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HostEndpointInfo.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HostEndpointInfo.aidl
@@ -40,7 +40,7 @@
   @nullable String attributionTag;
   @Backing(type="int") @VintfStability
   enum Type {
-    TYPE_FRAMEWORK = 1,
-    TYPE_APP = 2,
+    FRAMEWORK = 1,
+    APP = 2,
   }
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index facce4b..f0676be 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -35,14 +35,15 @@
 @VintfStability
 interface IContextHub {
   List<android.hardware.contexthub.ContextHubInfo> getContextHubs();
-  boolean loadNanoapp(in int contextHubId, in android.hardware.contexthub.NanoappBinary appBinary, in int transactionId);
-  boolean unloadNanoapp(in int contextHubId, in long appId, in int transactionId);
-  boolean disableNanoapp(in int contextHubId, in long appId, in int transactionId);
-  boolean enableNanoapp(in int contextHubId, in long appId, in int transactionId);
+  void loadNanoapp(in int contextHubId, in android.hardware.contexthub.NanoappBinary appBinary, in int transactionId);
+  void unloadNanoapp(in int contextHubId, in long appId, in int transactionId);
+  void disableNanoapp(in int contextHubId, in long appId, in int transactionId);
+  void enableNanoapp(in int contextHubId, in long appId, in int transactionId);
   void onSettingChanged(in android.hardware.contexthub.Setting setting, in boolean enabled);
-  boolean queryNanoapps(in int contextHubId);
-  boolean registerCallback(in int contextHubId, in android.hardware.contexthub.IContextHubCallback cb);
-  boolean sendMessageToHub(in int contextHubId, in android.hardware.contexthub.ContextHubMessage message);
+  void queryNanoapps(in int contextHubId);
+  void registerCallback(in int contextHubId, in android.hardware.contexthub.IContextHubCallback cb);
+  void sendMessageToHub(in int contextHubId, in android.hardware.contexthub.ContextHubMessage message);
   void onHostEndpointConnected(in android.hardware.contexthub.HostEndpointInfo hostEndpointInfo);
   void onHostEndpointDisconnected(char hostEndpointId);
+  const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/NanoappInfo.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/NanoappInfo.aidl
index ea7825a..7175d7f 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/NanoappInfo.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/NanoappInfo.aidl
@@ -38,4 +38,5 @@
   int nanoappVersion;
   boolean enabled;
   String[] permissions;
+  android.hardware.contexthub.NanoappRpcService[] rpcServices;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/NanoappRpcService.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/NanoappRpcService.aidl
new file mode 100644
index 0000000..a6a1644
--- /dev/null
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/NanoappRpcService.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.contexthub;
+@VintfStability
+parcelable NanoappRpcService {
+  long id;
+  int version;
+}
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
index 41bc9ae..d998478 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
@@ -39,4 +39,6 @@
   WIFI_SCANNING = 3,
   AIRPLANE_MODE = 4,
   MICROPHONE = 5,
+  BT_MAIN = 6,
+  BT_SCANNING = 7,
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
index 867da2f..95d478e 100644
--- a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
@@ -32,10 +32,14 @@
      */
     char hostEndPoint;
 
-    /** The type of this message */
+    /**
+     * The type of this message payload, defined by the communication endpoints (i.e.
+     * either the nanoapp or the host endpoint). This value can be used to distinguish
+     * the handling of messageBody (e.g. for decoding).
+     */
     int messageType;
 
-    /** The payload containing the message */
+    /** The payload containing the message. */
     byte[] messageBody;
 
     /**
diff --git a/contexthub/aidl/android/hardware/contexthub/HostEndpointInfo.aidl b/contexthub/aidl/android/hardware/contexthub/HostEndpointInfo.aidl
index 40a231d..a9d6657 100644
--- a/contexthub/aidl/android/hardware/contexthub/HostEndpointInfo.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/HostEndpointInfo.aidl
@@ -37,12 +37,12 @@
     @Backing(type="int")
     enum Type {
         /**
-           This endpoint is from the Android framework, where packageName and attributionTag may be
-           empty.
+         * This endpoint is from the Android framework, where packageName and attributionTag may be
+         * empty.
          */
-        TYPE_FRAMEWORK = 1,
+        FRAMEWORK = 1,
 
         /** This endpoint is an Android app. */
-        TYPE_APP = 2,
+        APP = 2,
     }
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 33d241a..2135041 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -52,9 +52,12 @@
      * @param appBinary The nanoapp binary with header
      * @param transactionId The transaction ID associated with this request
      *
-     * @return The return code
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid.
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
      */
-    boolean loadNanoapp(in int contextHubId, in NanoappBinary appBinary, in int transactionId);
+    void loadNanoapp(in int contextHubId, in NanoappBinary appBinary, in int transactionId);
 
     /**
      * Invokes the nanoapp's deinitialization "end()" entrypoint, and unloads the nanoapp.
@@ -69,9 +72,12 @@
      * @param appId The unique ID of the nanoapp
      * @param transactionId The transaction ID associated with this request
      *
-     * @return The return code
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid.
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
      */
-    boolean unloadNanoapp(in int contextHubId, in long appId, in int transactionId);
+    void unloadNanoapp(in int contextHubId, in long appId, in int transactionId);
 
     /**
      * Disables a nanoapp by invoking the nanoapp's "end()" entrypoint, but does not unload the
@@ -87,9 +93,12 @@
      * @param appId The unique ID of the nanoapp
      * @param transactionId The transaction ID associated with this request
      *
-     * @return The return code
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid.
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
      */
-    boolean disableNanoapp(in int contextHubId, in long appId, in int transactionId);
+    void disableNanoapp(in int contextHubId, in long appId, in int transactionId);
 
     /**
      * Enables a nanoapp by invoking the nanoapp's initialization "start()" entrypoint.
@@ -104,9 +113,12 @@
      * @param appId appIdentifier returned by the HAL
      * @param message   message to be sent
      *
-     * @return true on success
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid.
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
      */
-    boolean enableNanoapp(in int contextHubId, in long appId, in int transactionId);
+    void enableNanoapp(in int contextHubId, in long appId, in int transactionId);
 
     /**
      * Notification sent by the framework to indicate that the user has changed a setting.
@@ -124,9 +136,12 @@
      *
      * @param contextHubId The identifier of the Context Hub
      *
-     * @return true on success
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid.
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
      */
-    boolean queryNanoapps(in int contextHubId);
+    void queryNanoapps(in int contextHubId);
 
     /**
      * Register a callback for the HAL implementation to send asynchronous messages to the service
@@ -138,10 +153,11 @@
      * @param contextHubId The identifier of the Context Hub
      * @param callback an implementation of the IContextHubCallbacks
      *
-     * @return true on success
-     *
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
      */
-    boolean registerCallback(in int contextHubId, in IContextHubCallback cb);
+    void registerCallback(in int contextHubId, in IContextHubCallback cb);
 
     /**
      * Sends a message targeted to a nanoapp to the Context Hub.
@@ -149,9 +165,11 @@
      * @param contextHubId The identifier of the Context Hub
      * @param message The message to be sent
      *
-     * @return true on success
+     * @throws EX_ILLEGAL_ARGUMENT if any of the arguments are invalid.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - EX_CONTEXT_HUB_UNSPECIFIED if the request failed for other reasons.
      */
-    boolean sendMessageToHub(in int contextHubId, in ContextHubMessage message);
+    void sendMessageToHub(in int contextHubId, in ContextHubMessage message);
 
     /**
      * Invoked when a host endpoint has connected with the ContextHubService.
@@ -173,8 +191,13 @@
      *
      * @param hostEndPointId The ID of the host that has disconnected.
      *
-     * @return Status::ok on success
-     *         EX_ILLEGAL_ARGUMENT if hostEndpointId is not associated with a connected host.
+     * @throws EX_ILLEGAL_ARGUMENT if hostEndpointId is not associated with a connected host.
      */
     void onHostEndpointDisconnected(char hostEndpointId);
+
+    /**
+     * Error codes that are used as service specific errors with the AIDL return
+     * value EX_SERVICE_SPECIFIC.
+     */
+    const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/NanoappInfo.aidl b/contexthub/aidl/android/hardware/contexthub/NanoappInfo.aidl
index 9991dc8..77ac026 100644
--- a/contexthub/aidl/android/hardware/contexthub/NanoappInfo.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/NanoappInfo.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.contexthub;
 
+import android.hardware.contexthub.NanoappRpcService;
+
 @VintfStability
 parcelable NanoappInfo {
     /** The unique identifier of the nanoapp. */
@@ -39,4 +41,9 @@
      * this list.
      */
     String[] permissions;
+
+    /**
+     * The list of RPC services supported by this nanoapp.
+     */
+    NanoappRpcService[] rpcServices;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/NanoappRpcService.aidl b/contexthub/aidl/android/hardware/contexthub/NanoappRpcService.aidl
new file mode 100644
index 0000000..6dc5e95
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/NanoappRpcService.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+/**
+ * An RPC service exposed by a nanoapp.
+ *
+ * The implementation of the RPC interface is not defined by the HAL, and is written
+ * at the messaging endpoint layers (Android app and/or CHRE nanoapp). NanoappRpcService
+ * contains the informational metadata to be consumed by the RPC interface layer.
+ */
+@VintfStability
+parcelable NanoappRpcService {
+    /**
+     * The unique 64-bit ID of an RPC service exposed by a nanoapp. Note that
+     * the uniqueness is only required within the nanoapp's domain (i.e. the
+     * combination of the nanoapp ID and service id must be unique).
+     */
+    long id;
+
+    /**
+     * The software version of this service, which follows the semantic
+     * versioning scheme (see semver.org). It follows the format
+     * major.minor.patch, where major and minor versions take up one byte
+     * each, and the patch version takes up the final 2 bytes.
+     */
+    int version;
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/Setting.aidl b/contexthub/aidl/android/hardware/contexthub/Setting.aidl
index f2e55db..91d4c3f 100644
--- a/contexthub/aidl/android/hardware/contexthub/Setting.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/Setting.aidl
@@ -39,4 +39,12 @@
      * by CHRE.
      */
     MICROPHONE,
+    /**
+     * The main BT toggle in the Android settings for BT connectivity.
+     */
+    BT_MAIN,
+    /**
+     * The "BT scanning" setting for location scans.
+     */
+    BT_SCANNING,
 }
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 6da690d..4c23cbc 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -21,7 +21,9 @@
 namespace hardware {
 namespace contexthub {
 
-::ndk::ScopedAStatus ContextHub::getContextHubs(std::vector<ContextHubInfo>* out_contextHubInfos) {
+using ::ndk::ScopedAStatus;
+
+ScopedAStatus ContextHub::getContextHubs(std::vector<ContextHubInfo>* out_contextHubInfos) {
     ContextHubInfo hub = {};
     hub.name = "Mock Context Hub";
     hub.vendor = "AOSP";
@@ -39,85 +41,70 @@
 }
 
 // We don't expose any nanoapps for the default impl, therefore all nanoapp-related APIs fail.
-::ndk::ScopedAStatus ContextHub::loadNanoapp(int32_t /* in_contextHubId */,
-                                             const NanoappBinary& /* in_appBinary */,
-                                             int32_t /* in_transactionId */, bool* _aidl_return) {
-    *_aidl_return = false;
+ScopedAStatus ContextHub::loadNanoapp(int32_t /* in_contextHubId */,
+                                      const NanoappBinary& /* in_appBinary */,
+                                      int32_t /* in_transactionId */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus ContextHub::unloadNanoapp(int32_t /* in_contextHubId */, int64_t /* in_appId */,
+                                        int32_t /* in_transactionId */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus ContextHub::disableNanoapp(int32_t /* in_contextHubId */, int64_t /* in_appId */,
+                                         int32_t /* in_transactionId */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus ContextHub::enableNanoapp(int32_t /* in_contextHubId */, int64_t /* in_appId */,
+                                        int32_t /* in_transactionId */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus ContextHub::onSettingChanged(Setting /* in_setting */, bool /*in_enabled */) {
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus ContextHub::unloadNanoapp(int32_t /* in_contextHubId */,
-                                               int64_t /* in_appId */,
-                                               int32_t /* in_transactionId */, bool* _aidl_return) {
-    *_aidl_return = false;
-    return ndk::ScopedAStatus::ok();
-}
-
-::ndk::ScopedAStatus ContextHub::disableNanoapp(int32_t /* in_contextHubId */,
-                                                int64_t /* in_appId */,
-                                                int32_t /* in_transactionId */,
-                                                bool* _aidl_return) {
-    *_aidl_return = false;
-    return ndk::ScopedAStatus::ok();
-}
-
-::ndk::ScopedAStatus ContextHub::enableNanoapp(int32_t /* in_contextHubId */,
-                                               int64_t /* in_appId */,
-                                               int32_t /* in_transactionId */, bool* _aidl_return) {
-    *_aidl_return = false;
-    return ndk::ScopedAStatus::ok();
-}
-
-::ndk::ScopedAStatus ContextHub::onSettingChanged(Setting /* in_setting */, bool /*in_enabled */) {
-    return ndk::ScopedAStatus::ok();
-}
-
-::ndk::ScopedAStatus ContextHub::queryNanoapps(int32_t in_contextHubId, bool* _aidl_return) {
+ScopedAStatus ContextHub::queryNanoapps(int32_t in_contextHubId) {
     if (in_contextHubId == kMockHubId && mCallback != nullptr) {
         std::vector<NanoappInfo> nanoapps;
         mCallback->handleNanoappInfo(nanoapps);
-        *_aidl_return = true;
+        return ndk::ScopedAStatus::ok();
     } else {
-        *_aidl_return = false;
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-
-    return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
-                                                  const std::shared_ptr<IContextHubCallback>& in_cb,
-                                                  bool* _aidl_return) {
+ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
+                                           const std::shared_ptr<IContextHubCallback>& in_cb) {
     if (in_contextHubId == kMockHubId) {
         mCallback = in_cb;
-        *_aidl_return = true;
+        return ndk::ScopedAStatus::ok();
     } else {
-        *_aidl_return = false;
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus ContextHub::sendMessageToHub(int32_t in_contextHubId,
-                                                  const ContextHubMessage& /* in_message */,
-                                                  bool* _aidl_return) {
+ScopedAStatus ContextHub::sendMessageToHub(int32_t in_contextHubId,
+                                           const ContextHubMessage& /* in_message */) {
     if (in_contextHubId == kMockHubId) {
         // Return true here to indicate that the HAL has accepted the message.
         // Successful delivery of the message to a nanoapp should be handled at
         // a higher level protocol.
-        *_aidl_return = true;
+        return ndk::ScopedAStatus::ok();
     } else {
-        *_aidl_return = false;
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-
-    return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus ContextHub::onHostEndpointConnected(const HostEndpointInfo& in_info) {
+ScopedAStatus ContextHub::onHostEndpointConnected(const HostEndpointInfo& in_info) {
     mConnectedHostEndpoints.insert(in_info.hostEndpointId);
 
     return ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) {
+ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) {
     if (mConnectedHostEndpoints.count(in_hostEndpointId) > 0) {
         mConnectedHostEndpoints.erase(in_hostEndpointId);
         return ndk::ScopedAStatus::ok();
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index dd739e6..03d8432 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -28,21 +28,19 @@
 class ContextHub : public BnContextHub {
     ::ndk::ScopedAStatus getContextHubs(std::vector<ContextHubInfo>* out_contextHubInfos) override;
     ::ndk::ScopedAStatus loadNanoapp(int32_t in_contextHubId, const NanoappBinary& in_appBinary,
-                                     int32_t in_transactionId, bool* _aidl_return) override;
+                                     int32_t in_transactionId) override;
     ::ndk::ScopedAStatus unloadNanoapp(int32_t in_contextHubId, int64_t in_appId,
-                                       int32_t in_transactionId, bool* _aidl_return) override;
+                                       int32_t in_transactionId) override;
     ::ndk::ScopedAStatus disableNanoapp(int32_t in_contextHubId, int64_t in_appId,
-                                        int32_t in_transactionId, bool* _aidl_return) override;
+                                        int32_t in_transactionId) override;
     ::ndk::ScopedAStatus enableNanoapp(int32_t in_contextHubId, int64_t in_appId,
-                                       int32_t in_transactionId, bool* _aidl_return) override;
+                                       int32_t in_transactionId) override;
     ::ndk::ScopedAStatus onSettingChanged(Setting in_setting, bool in_enabled) override;
-    ::ndk::ScopedAStatus queryNanoapps(int32_t in_contextHubId, bool* _aidl_return) override;
-    ::ndk::ScopedAStatus registerCallback(int32_t in_contextHubId,
-                                          const std::shared_ptr<IContextHubCallback>& in_cb,
-                                          bool* _aidl_return) override;
+    ::ndk::ScopedAStatus queryNanoapps(int32_t in_contextHubId) override;
+    ::ndk::ScopedAStatus registerCallback(
+            int32_t in_contextHubId, const std::shared_ptr<IContextHubCallback>& in_cb) override;
     ::ndk::ScopedAStatus sendMessageToHub(int32_t in_contextHubId,
-                                          const ContextHubMessage& in_message,
-                                          bool* _aidl_return) override;
+                                          const ContextHubMessage& in_message) override;
     ::ndk::ScopedAStatus onHostEndpointConnected(const HostEndpointInfo& in_info) override;
 
     ::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override;
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 1b2dc29..f0583be 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -41,6 +41,7 @@
 using ::android::hardware::contexthub::IContextHubCallbackDefault;
 using ::android::hardware::contexthub::NanoappBinary;
 using ::android::hardware::contexthub::NanoappInfo;
+using ::android::hardware::contexthub::NanoappRpcService;
 using ::android::hardware::contexthub::Setting;
 using ::android::hardware::contexthub::vts_utils::kNonExistentAppId;
 using ::android::hardware::contexthub::vts_utils::waitForCallback;
@@ -102,15 +103,12 @@
 };
 
 TEST_P(ContextHubAidl, TestRegisterCallback) {
-    bool success;
     sp<EmptyContextHubCallback> cb = sp<EmptyContextHubCallback>::make();
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb, &success).isOk());
-    ASSERT_TRUE(success);
+    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
 }
 
 TEST_P(ContextHubAidl, TestRegisterNullCallback) {
-    bool success;
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), nullptr, &success).isOk());
+    ASSERT_TRUE(contextHub->registerCallback(getHubId(), nullptr).isOk());
 }
 
 // Helper callback that puts the async appInfo callback data into a promise
@@ -139,18 +137,22 @@
 // Calls queryApps() and checks the returned metadata
 TEST_P(ContextHubAidl, TestQueryApps) {
     sp<QueryAppsCallback> cb = sp<QueryAppsCallback>::make();
-    bool success;
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb, &success).isOk());
-    ASSERT_TRUE(success);
-
-    ASSERT_TRUE(contextHub->queryNanoapps(getHubId(), &success).isOk());
-    ASSERT_TRUE(success);
+    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
+    ASSERT_TRUE(contextHub->queryNanoapps(getHubId()).isOk());
 
     std::vector<NanoappInfo> appInfoList;
     ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appInfoList));
     for (const NanoappInfo& appInfo : appInfoList) {
         EXPECT_NE(appInfo.nanoappId, UINT64_C(0));
         EXPECT_NE(appInfo.nanoappId, kNonExistentAppId);
+
+        // Verify services are unique.
+        std::set<uint64_t> existingServiceIds;
+        for (const NanoappRpcService& rpcService : appInfo.rpcServices) {
+            EXPECT_NE(rpcService.id, UINT64_C(0));
+            EXPECT_EQ(existingServiceIds.count(rpcService.id), 0);
+            existingServiceIds.insert(rpcService.id);
+        }
     }
 }
 
@@ -188,9 +190,7 @@
   public:
     virtual void SetUp() override {
         ContextHubAidl::SetUp();
-        bool success;
-        ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb, &success).isOk());
-        ASSERT_TRUE(success);
+        ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
     }
 
     sp<TransactionResultCallback> cb = sp<TransactionResultCallback>::make();
@@ -204,9 +204,7 @@
     std::fill(message.messageBody.begin(), message.messageBody.end(), 0);
 
     ALOGD("Sending message to non-existent nanoapp");
-    bool success;
-    ASSERT_TRUE(contextHub->sendMessageToHub(getHubId(), message, &success).isOk());
-    ASSERT_TRUE(success);
+    ASSERT_TRUE(contextHub->sendMessageToHub(getHubId(), message).isOk());
 }
 
 TEST_P(ContextHubTransactionTest, TestLoadEmptyNanoapp) {
@@ -220,9 +218,7 @@
     emptyApp.targetChreApiMinorVersion = 0;
 
     ALOGD("Loading empty nanoapp");
-    bool success;
-    ASSERT_TRUE(contextHub->loadNanoapp(getHubId(), emptyApp, cb->expectedTransactionId, &success)
-                        .isOk());
+    bool success = contextHub->loadNanoapp(getHubId(), emptyApp, cb->expectedTransactionId).isOk();
     if (success) {
         bool transactionSuccess;
         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
@@ -234,11 +230,9 @@
     cb->expectedTransactionId = 1234;
 
     ALOGD("Unloading nonexistent nanoapp");
-    bool success;
-    ASSERT_TRUE(contextHub
-                        ->unloadNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId,
-                                        &success)
-                        .isOk());
+    bool success =
+            contextHub->unloadNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
+                    .isOk();
     if (success) {
         bool transactionSuccess;
         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
@@ -250,11 +244,9 @@
     cb->expectedTransactionId = 2345;
 
     ALOGD("Enabling nonexistent nanoapp");
-    bool success;
-    ASSERT_TRUE(contextHub
-                        ->enableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId,
-                                        &success)
-                        .isOk());
+    bool success =
+            contextHub->enableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
+                    .isOk();
     if (success) {
         bool transactionSuccess;
         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
@@ -266,11 +258,9 @@
     cb->expectedTransactionId = 3456;
 
     ALOGD("Disabling nonexistent nanoapp");
-    bool success;
-    ASSERT_TRUE(contextHub
-                        ->disableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId,
-                                         &success)
-                        .isOk());
+    bool success =
+            contextHub->disableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
+                    .isOk();
     if (success) {
         bool transactionSuccess;
         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
@@ -281,16 +271,13 @@
 void ContextHubAidl::testSettingChanged(Setting setting) {
     // In VTS, we only test that sending the values doesn't cause things to blow up - GTS tests
     // verify the expected E2E behavior in CHRE
-    bool success;
     sp<EmptyContextHubCallback> cb = sp<EmptyContextHubCallback>::make();
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb, &success).isOk());
-    ASSERT_TRUE(success);
+    ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
 
     ASSERT_TRUE(contextHub->onSettingChanged(setting, true /* enabled */).isOk());
     ASSERT_TRUE(contextHub->onSettingChanged(setting, false /* enabled */).isOk());
 
-    ASSERT_TRUE(contextHub->registerCallback(getHubId(), nullptr, &success).isOk());
-    ASSERT_TRUE(success);
+    ASSERT_TRUE(contextHub->registerCallback(getHubId(), nullptr).isOk());
 }
 
 TEST_P(ContextHubAidl, TestOnLocationSettingChanged) {
@@ -313,6 +300,14 @@
     testSettingChanged(Setting::MICROPHONE);
 }
 
+TEST_P(ContextHubAidl, TestOnBtMainSettingChanged) {
+    testSettingChanged(Setting::BT_MAIN);
+}
+
+TEST_P(ContextHubAidl, TestOnBtScanningSettingChanged) {
+    testSettingChanged(Setting::BT_SCANNING);
+}
+
 std::vector<std::tuple<std::string, int32_t>> generateContextHubMapping() {
     std::vector<std::tuple<std::string, int32_t>> tuples;
     auto contextHubAidlNames = android::getAidlHalInstanceNames(IContextHub::descriptor);
diff --git a/current.txt b/current.txt
index 1dbf5ab..1fedaa0 100644
--- a/current.txt
+++ b/current.txt
@@ -907,6 +907,7 @@
 # ABI preserving changes to HALs during Android T
 62ace52d9c3ff1f60f94118557a2aaf0b953513e59dcd34d5f94ae28d4c7e780 android.hardware.fastboot@1.0::IFastboot
 f767a132ef28275294db15353f14f3876a4048770751931a77d038d4228f2cb7 android.hardware.graphics.composer@2.4::IComposerClient
+d0fb32f3ddeb9af7115ab32905225ea69b930d2472be8e9610f0cf136c15aefb android.hardware.keymaster@4.0::IKeymasterDevice # b/210424594
 ca62a2a95d173ed323309e5e00f653ad3cceec82a6e5e4976a249cb5aafe2515 android.hardware.neuralnetworks@1.2::types
 fa76bced6b1b71c40fc706c508a9011284c57f57831cd0cf5f45653ed4ea463e android.hardware.neuralnetworks@1.3::types
 
diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp
new file mode 100644
index 0000000..d8500ec
--- /dev/null
+++ b/drm/aidl/Android.bp
@@ -0,0 +1,32 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.drm",
+    vendor_available: true,
+    srcs: ["android/hardware/drm/*.aidl"],
+    stability: "vintf",
+    imports: [
+        "android.hardware.common-V2",
+    ],
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+            min_sdk_version: "current",
+        },
+    },
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl
new file mode 100644
index 0000000..b6ec34d
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@Backing(type="int") @VintfStability
+enum BufferType {
+  SHARED_MEMORY = 0,
+  NATIVE_HANDLE = 1,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
new file mode 100644
index 0000000..d2b48d2
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable DecryptResult {
+  int bytesWritten;
+  String detailedError;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DestinationBuffer.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DestinationBuffer.aidl
new file mode 100644
index 0000000..4f2d133
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DestinationBuffer.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable DestinationBuffer {
+  android.hardware.drm.BufferType type;
+  android.hardware.drm.SharedBuffer nonsecureMemory;
+  android.hardware.common.NativeHandle secureMemory;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetric.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetric.aidl
new file mode 100644
index 0000000..c78dff0
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetric.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable DrmMetric {
+  String name;
+  List<android.hardware.drm.DrmMetricNamedValue> attributes;
+  List<android.hardware.drm.DrmMetricNamedValue> values;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricGroup.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricGroup.aidl
new file mode 100644
index 0000000..4128eaa
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricGroup.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable DrmMetricGroup {
+  List<android.hardware.drm.DrmMetric> metrics;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricNamedValue.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricNamedValue.aidl
new file mode 100644
index 0000000..76ec35c
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricNamedValue.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable DrmMetricNamedValue {
+  String name;
+  android.hardware.drm.DrmMetricValue value;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricValue.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricValue.aidl
new file mode 100644
index 0000000..8064913
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DrmMetricValue.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+union DrmMetricValue {
+  long int64Value;
+  double doubleValue;
+  String stringValue;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
new file mode 100644
index 0000000..80ebb28
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@Backing(type="int") @VintfStability
+enum EventType {
+  PROVISION_REQUIRED = 0,
+  KEY_NEEDED = 1,
+  KEY_EXPIRED = 2,
+  VENDOR_DEFINED = 3,
+  SESSION_RECLAIMED = 4,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl
new file mode 100644
index 0000000..5704fb0
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@Backing(type="int") @VintfStability
+enum HdcpLevel {
+  HDCP_UNKNOWN = 0,
+  HDCP_NONE = 1,
+  HDCP_V1 = 2,
+  HDCP_V2 = 3,
+  HDCP_V2_1 = 4,
+  HDCP_V2_2 = 5,
+  HDCP_NO_OUTPUT = 6,
+  HDCP_V2_3 = 7,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl
new file mode 100644
index 0000000..a6f86ac
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable HdcpLevels {
+  android.hardware.drm.HdcpLevel connectedLevel;
+  android.hardware.drm.HdcpLevel maxLevel;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoFactory.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoFactory.aidl
new file mode 100644
index 0000000..0d4296e
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoFactory.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+interface ICryptoFactory {
+  @nullable android.hardware.drm.ICryptoPlugin createPlugin(in android.hardware.drm.Uuid uuid, in byte[] initData);
+  boolean isCryptoSchemeSupported(in android.hardware.drm.Uuid uuid);
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoPlugin.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoPlugin.aidl
new file mode 100644
index 0000000..2224795
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoPlugin.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+interface ICryptoPlugin {
+  android.hardware.drm.DecryptResult decrypt(in boolean secure, in byte[] keyId, in byte[] iv, in android.hardware.drm.Mode mode, in android.hardware.drm.Pattern pattern, in android.hardware.drm.SubSample[] subSamples, in android.hardware.drm.SharedBuffer source, in long offset, in android.hardware.drm.DestinationBuffer destination);
+  List<android.hardware.drm.LogMessage> getLogMessages();
+  void notifyResolution(in int width, in int height);
+  boolean requiresSecureDecoderComponent(in String mime);
+  void setMediaDrmSession(in byte[] sessionId);
+  void setSharedBufferBase(in android.hardware.common.Ashmem base, in int bufferId);
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmFactory.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmFactory.aidl
new file mode 100644
index 0000000..af48737
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmFactory.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+interface IDrmFactory {
+  @nullable android.hardware.drm.IDrmPlugin createPlugin(in android.hardware.drm.Uuid uuid, in String appPackageName);
+  List<android.hardware.drm.Uuid> getSupportedCryptoSchemes();
+  boolean isContentTypeSupported(in String mimeType);
+  boolean isCryptoSchemeSupported(in android.hardware.drm.Uuid uuid, in String mimeType, in android.hardware.drm.SecurityLevel securityLevel);
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPlugin.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPlugin.aidl
new file mode 100644
index 0000000..5f839d7
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPlugin.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+interface IDrmPlugin {
+  void closeSession(in byte[] sessionId);
+  byte[] decrypt(in byte[] sessionId, in byte[] keyId, in byte[] input, in byte[] iv);
+  byte[] encrypt(in byte[] sessionId, in byte[] keyId, in byte[] input, in byte[] iv);
+  android.hardware.drm.HdcpLevels getHdcpLevels();
+  android.hardware.drm.KeyRequest getKeyRequest(in byte[] scope, in byte[] initData, in String mimeType, in android.hardware.drm.KeyType keyType, in android.hardware.drm.KeyValue[] optionalParameters);
+  List<android.hardware.drm.LogMessage> getLogMessages();
+  List<android.hardware.drm.DrmMetricGroup> getMetrics();
+  android.hardware.drm.NumberOfSessions getNumberOfSessions();
+  List<android.hardware.drm.KeySetId> getOfflineLicenseKeySetIds();
+  android.hardware.drm.OfflineLicenseState getOfflineLicenseState(in android.hardware.drm.KeySetId keySetId);
+  byte[] getPropertyByteArray(in String propertyName);
+  String getPropertyString(in String propertyName);
+  android.hardware.drm.ProvisionRequest getProvisionRequest(in String certificateType, in String certificateAuthority);
+  android.hardware.drm.SecureStop getSecureStop(in android.hardware.drm.SecureStopId secureStopId);
+  List<android.hardware.drm.SecureStopId> getSecureStopIds();
+  List<android.hardware.drm.SecureStop> getSecureStops();
+  android.hardware.drm.SecurityLevel getSecurityLevel(in byte[] sessionId);
+  byte[] openSession(in android.hardware.drm.SecurityLevel securityLevel);
+  android.hardware.drm.KeySetId provideKeyResponse(in byte[] scope, in byte[] response);
+  android.hardware.drm.ProvideProvisionResponseResult provideProvisionResponse(in byte[] response);
+  List<android.hardware.drm.KeyValue> queryKeyStatus(in byte[] sessionId);
+  void releaseAllSecureStops();
+  void releaseSecureStop(in android.hardware.drm.SecureStopId secureStopId);
+  void releaseSecureStops(in android.hardware.drm.OpaqueData ssRelease);
+  void removeAllSecureStops();
+  void removeKeys(in byte[] sessionId);
+  void removeOfflineLicense(in android.hardware.drm.KeySetId keySetId);
+  void removeSecureStop(in android.hardware.drm.SecureStopId secureStopId);
+  boolean requiresSecureDecoder(in String mime, in android.hardware.drm.SecurityLevel level);
+  boolean requiresSecureDecoderDefault(in String mime);
+  void restoreKeys(in byte[] sessionId, in android.hardware.drm.KeySetId keySetId);
+  void setCipherAlgorithm(in byte[] sessionId, in String algorithm);
+  void setListener(in android.hardware.drm.IDrmPluginListener listener);
+  void setMacAlgorithm(in byte[] sessionId, in String algorithm);
+  void setPlaybackId(in byte[] sessionId, in String playbackId);
+  void setPropertyByteArray(in String propertyName, in byte[] value);
+  void setPropertyString(in String propertyName, in String value);
+  byte[] sign(in byte[] sessionId, in byte[] keyId, in byte[] message);
+  byte[] signRSA(in byte[] sessionId, in String algorithm, in byte[] message, in byte[] wrappedkey);
+  boolean verify(in byte[] sessionId, in byte[] keyId, in byte[] message, in byte[] signature);
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPluginListener.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPluginListener.aidl
new file mode 100644
index 0000000..0a4b4b7
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPluginListener.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+interface IDrmPluginListener {
+  oneway void onEvent(in android.hardware.drm.EventType eventType, in byte[] sessionId, in byte[] data);
+  oneway void onExpirationUpdate(in byte[] sessionId, in long expiryTimeInMS);
+  oneway void onKeysChange(in byte[] sessionId, in android.hardware.drm.KeyStatus[] keyStatusList, in boolean hasNewUsableKey);
+  oneway void onSessionLostState(in byte[] sessionId);
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequest.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequest.aidl
new file mode 100644
index 0000000..267f532
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequest.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable KeyRequest {
+  byte[] request;
+  android.hardware.drm.KeyRequestType requestType;
+  String defaultUrl;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
new file mode 100644
index 0000000..34b9615
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@Backing(type="int") @VintfStability
+enum KeyRequestType {
+  INITIAL = 0,
+  RENEWAL = 1,
+  RELEASE = 2,
+  UNKNOWN = 3,
+  NONE = 4,
+  UPDATE = 5,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeySetId.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeySetId.aidl
new file mode 100644
index 0000000..58dfe1a
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeySetId.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable KeySetId {
+  byte[] keySetId;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatus.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatus.aidl
new file mode 100644
index 0000000..53ab70f
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatus.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable KeyStatus {
+  byte[] keyId;
+  android.hardware.drm.KeyStatusType type;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
new file mode 100644
index 0000000..e88d388
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@Backing(type="int") @VintfStability
+enum KeyStatusType {
+  USABLE = 0,
+  EXPIRED = 1,
+  OUTPUTNOTALLOWED = 2,
+  STATUSPENDING = 3,
+  INTERNALERROR = 4,
+  USABLEINFUTURE = 5,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
new file mode 100644
index 0000000..7a9d633
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@Backing(type="int") @VintfStability
+enum KeyType {
+  OFFLINE = 0,
+  STREAMING = 1,
+  RELEASE = 2,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyValue.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyValue.aidl
new file mode 100644
index 0000000..35d7b77
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyValue.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable KeyValue {
+  String key;
+  String value;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogMessage.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogMessage.aidl
new file mode 100644
index 0000000..93f76e1
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogMessage.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable LogMessage {
+  long timeMs;
+  android.hardware.drm.LogPriority priority;
+  String message;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
new file mode 100644
index 0000000..83362c3
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@Backing(type="int") @VintfStability
+enum LogPriority {
+  UNKNOWN = 0,
+  DEFAULT = 1,
+  VERBOSE = 2,
+  DEBUG = 3,
+  INFO = 4,
+  WARN = 5,
+  ERROR = 6,
+  FATAL = 7,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Mode.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Mode.aidl
new file mode 100644
index 0000000..7379774
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Mode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@Backing(type="int") @VintfStability
+enum Mode {
+  UNENCRYPTED = 0,
+  AES_CTR = 1,
+  AES_CBC_CTS = 2,
+  AES_CBC = 3,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/NumberOfSessions.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/NumberOfSessions.aidl
new file mode 100644
index 0000000..a421125
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/NumberOfSessions.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable NumberOfSessions {
+  int currentSessions;
+  int maxSessions;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
new file mode 100644
index 0000000..629564d
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@Backing(type="int") @VintfStability
+enum OfflineLicenseState {
+  UNKNOWN = 0,
+  USABLE = 1,
+  INACTIVE = 2,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OpaqueData.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OpaqueData.aidl
new file mode 100644
index 0000000..3085889
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OpaqueData.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable OpaqueData {
+  byte[] opaqueData;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Pattern.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Pattern.aidl
new file mode 100644
index 0000000..b01562e
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Pattern.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable Pattern {
+  int encryptBlocks;
+  int skipBlocks;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ProvideProvisionResponseResult.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ProvideProvisionResponseResult.aidl
new file mode 100644
index 0000000..827de59
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ProvideProvisionResponseResult.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable ProvideProvisionResponseResult {
+  byte[] certificate;
+  byte[] wrappedKey;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ProvisionRequest.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ProvisionRequest.aidl
new file mode 100644
index 0000000..84c5662
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ProvisionRequest.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable ProvisionRequest {
+  byte[] request;
+  String defaultUrl;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecureStop.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecureStop.aidl
new file mode 100644
index 0000000..81d2dfe
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecureStop.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable SecureStop {
+  byte[] opaqueData;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecureStopId.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecureStopId.aidl
new file mode 100644
index 0000000..2b904c8
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecureStopId.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable SecureStopId {
+  byte[] secureStopId;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
new file mode 100644
index 0000000..65b2b9d
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@Backing(type="int") @VintfStability
+enum SecurityLevel {
+  UNKNOWN = 0,
+  SW_SECURE_CRYPTO = 1,
+  SW_SECURE_DECODE = 2,
+  HW_SECURE_CRYPTO = 3,
+  HW_SECURE_DECODE = 4,
+  HW_SECURE_ALL = 5,
+  DEFAULT = 6,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SharedBuffer.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SharedBuffer.aidl
new file mode 100644
index 0000000..973ef0d
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SharedBuffer.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable SharedBuffer {
+  int bufferId;
+  long offset;
+  long size;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
new file mode 100644
index 0000000..c640689
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@Backing(type="int") @VintfStability
+enum Status {
+  OK = 0,
+  ERROR_DRM_NO_LICENSE = 1,
+  ERROR_DRM_LICENSE_EXPIRED = 2,
+  ERROR_DRM_SESSION_NOT_OPENED = 3,
+  ERROR_DRM_CANNOT_HANDLE = 4,
+  ERROR_DRM_INVALID_STATE = 5,
+  BAD_VALUE = 6,
+  ERROR_DRM_NOT_PROVISIONED = 7,
+  ERROR_DRM_RESOURCE_BUSY = 8,
+  ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 9,
+  ERROR_DRM_DEVICE_REVOKED = 10,
+  ERROR_DRM_DECRYPT = 11,
+  ERROR_DRM_UNKNOWN = 12,
+  ERROR_DRM_INSUFFICIENT_SECURITY = 13,
+  ERROR_DRM_FRAME_TOO_LARGE = 14,
+  ERROR_DRM_SESSION_LOST_STATE = 15,
+  ERROR_DRM_RESOURCE_CONTENTION = 16,
+  CANNOT_DECRYPT_ZERO_SUBSAMPLES = 17,
+  CRYPTO_LIBRARY_ERROR = 18,
+  GENERAL_OEM_ERROR = 19,
+  GENERAL_PLUGIN_ERROR = 20,
+  INIT_DATA_INVALID = 21,
+  KEY_NOT_LOADED = 22,
+  LICENSE_PARSE_ERROR = 23,
+  LICENSE_POLICY_ERROR = 24,
+  LICENSE_RELEASE_ERROR = 25,
+  LICENSE_REQUEST_REJECTED = 26,
+  LICENSE_RESTORE_ERROR = 27,
+  LICENSE_STATE_ERROR = 28,
+  MALFORMED_CERTIFICATE = 29,
+  MEDIA_FRAMEWORK_ERROR = 30,
+  MISSING_CERTIFICATE = 31,
+  PROVISIONING_CERTIFICATE_ERROR = 32,
+  PROVISIONING_CONFIGURATION_ERROR = 33,
+  PROVISIONING_PARSE_ERROR = 34,
+  PROVISIONING_REQUEST_REJECTED = 35,
+  RETRYABLE_PROVISIONING_ERROR = 36,
+  SECURE_STOP_RELEASE_ERROR = 37,
+  STORAGE_READ_FAILURE = 38,
+  STORAGE_WRITE_FAILURE = 39,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SubSample.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SubSample.aidl
new file mode 100644
index 0000000..57d815e
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SubSample.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.drm;
+@VintfStability
+parcelable SubSample {
+  int numBytesOfClearData;
+  int numBytesOfEncryptedData;
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Uuid.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Uuid.aidl
new file mode 100644
index 0000000..ec2eb16
--- /dev/null
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Uuid.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.drm;
+@VintfStability
+parcelable Uuid {
+  byte[] uuid;
+}
diff --git a/drm/aidl/android/hardware/drm/BufferType.aidl b/drm/aidl/android/hardware/drm/BufferType.aidl
new file mode 100644
index 0000000..089c950
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/BufferType.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+@Backing(type="int")
+enum BufferType {
+    SHARED_MEMORY = 0,
+    NATIVE_HANDLE = 1,
+}
diff --git a/drm/aidl/android/hardware/drm/DecryptResult.aidl b/drm/aidl/android/hardware/drm/DecryptResult.aidl
new file mode 100644
index 0000000..17e939b
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/DecryptResult.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * The DecryptResult parcelable contains the result of
+ * ICryptoPlugin decrypt method.
+ */
+@VintfStability
+parcelable DecryptResult {
+    /** The number of decrypted bytes. */
+    int bytesWritten;
+
+    /**
+     * Vendor-specific error message if provided by the vendor's
+     * crypto HAL.
+     */
+    String detailedError;
+}
diff --git a/drm/aidl/android/hardware/drm/DestinationBuffer.aidl b/drm/aidl/android/hardware/drm/DestinationBuffer.aidl
new file mode 100644
index 0000000..0f1e3f5
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/DestinationBuffer.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.drm.BufferType;
+import android.hardware.drm.SharedBuffer;
+
+/**
+ * A decrypt destination buffer can be either normal user-space shared
+ * memory for the non-secure decrypt case, or it can be a secure buffer
+ * which is referenced by a native-handle. The native handle is allocated
+ * by the vendor's buffer allocator.
+ */
+@VintfStability
+parcelable DestinationBuffer {
+    /**
+     * The type of the buffer
+     */
+    BufferType type;
+    /**
+     * If type == SHARED_MEMORY, the decrypted data must be written
+     * to user-space non-secure shared memory.
+     */
+    SharedBuffer nonsecureMemory;
+    /**
+     * If type == NATIVE_HANDLE, the decrypted data must be written
+     * to secure memory referenced by the vendor's buffer allocator.
+     */
+    NativeHandle secureMemory;
+}
diff --git a/drm/aidl/android/hardware/drm/DrmMetric.aidl b/drm/aidl/android/hardware/drm/DrmMetric.aidl
new file mode 100644
index 0000000..6199af6
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/DrmMetric.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.DrmMetricNamedValue;
+
+/**
+ * The metric being captured.
+ *
+ * A metric must have a name and at least one value. A metric may have 0 or
+ * more attributes. The fields of a Metric are opaque to the framework.
+ */
+@VintfStability
+parcelable DrmMetric {
+    String name;
+
+    /**
+     * Detail(s) about the metric being captured.
+     *
+     * The fields of an Attribute are opaque to the framework.
+     */
+    List<DrmMetricNamedValue> attributes;
+
+    /**
+     * Value(s) of the metric.
+     *
+     * A metric may have multiple values. The component name may be left empty
+     * if there is only supposed to be one value for the given metric. The
+     * fields of the Value are opaque to the framework.
+     */
+    List<DrmMetricNamedValue> values;
+}
diff --git a/drm/aidl/android/hardware/drm/DrmMetricGroup.aidl b/drm/aidl/android/hardware/drm/DrmMetricGroup.aidl
new file mode 100644
index 0000000..3b1f3c9
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/DrmMetricGroup.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.DrmMetric;
+
+/**
+ * This message contains plugin-specific metrics made available to the client.
+ * The message is used for making vendor-specific metrics available to an
+ * application. The framework is not consuming any of the information.
+ *
+ * Metrics are grouped in instances of DrmMetricGroup. Each group contains
+ * multiple instances of Metric.
+ *
+ * Example:
+ *
+ * Capture the timing information of a buffer copy event, "buf_copy", broken
+ * out by the "size" of the buffer.
+ *
+ * DrmMetricGroup {
+ *   metrics[0] {
+ *     name: "buf_copy"
+ *     attributes[0] {
+ *       name: "size"
+ *       type: INT64_TYPE
+ *       int64Value: 1024
+ *     }
+ *     values[0] {
+ *       componentName: "operation_count"
+ *       type: INT64_TYPE
+ *       int64Value: 75
+ *     }
+ *     values[1] {
+ *       component_name: "average_time_seconds"
+ *       type: DOUBLE_TYPE
+ *       doubleValue: 0.00000042
+ *     }
+ *   }
+ * }
+ */
+@VintfStability
+parcelable DrmMetricGroup {
+    /**
+     * The list of metrics to be captured.
+     */
+    List<DrmMetric> metrics;
+}
diff --git a/drm/aidl/android/hardware/drm/DrmMetricNamedValue.aidl b/drm/aidl/android/hardware/drm/DrmMetricNamedValue.aidl
new file mode 100644
index 0000000..5bb17a6
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/DrmMetricNamedValue.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.DrmMetricValue;
+
+/**
+ * A name-value pair used in drm metrics.
+ */
+@VintfStability
+parcelable DrmMetricNamedValue {
+    String name;
+    DrmMetricValue value;
+}
diff --git a/drm/aidl/android/hardware/drm/DrmMetricValue.aidl b/drm/aidl/android/hardware/drm/DrmMetricValue.aidl
new file mode 100644
index 0000000..0203f3f
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/DrmMetricValue.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * The value of a metric or a metric's attribute.
+ */
+@VintfStability
+union DrmMetricValue {
+    long int64Value;
+    double doubleValue;
+    String stringValue;
+}
diff --git a/drm/aidl/android/hardware/drm/EventType.aidl b/drm/aidl/android/hardware/drm/EventType.aidl
new file mode 100644
index 0000000..7a06eb0
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/EventType.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * EventType enumerates the events that can be delivered by sendEvent
+ */
+@VintfStability
+@Backing(type="int")
+enum EventType {
+    /**
+     * This event type indicates that the app needs to request a certificate
+     * from the provisioning server. The request message data is obtained using
+     * getProvisionRequest().
+     */
+    PROVISION_REQUIRED,
+    /**
+     * This event type indicates that the app needs to request keys from a
+     * license server. The request message data is obtained using getKeyRequest.
+     */
+    KEY_NEEDED,
+    /**
+     * This event type indicates that the licensed usage duration for keys in a
+     * session has expired. The keys are no longer valid.
+     */
+    KEY_EXPIRED,
+    /**
+     * This event may indicate some specific vendor-defined condition, see your
+     * DRM provider documentation for details.
+     */
+    VENDOR_DEFINED,
+    /**
+     * This event indicates that a session opened by the app has been reclaimed
+     * by the resource manager.
+     */
+    SESSION_RECLAIMED,
+}
diff --git a/drm/aidl/android/hardware/drm/HdcpLevel.aidl b/drm/aidl/android/hardware/drm/HdcpLevel.aidl
new file mode 100644
index 0000000..3497b78
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/HdcpLevel.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * HDCP specifications are defined by Digital Content Protection LLC (DCP).
+ *   "HDCP Specification Rev. 2.3 Interface Independent Adaptation"
+ *   "HDCP 2.3 on HDMI Specification"
+ */
+@VintfStability
+@Backing(type="int")
+enum HdcpLevel {
+    /**
+     * Unable to determine the HDCP level
+     */
+    HDCP_UNKNOWN,
+    /**
+     * No HDCP, output is unprotected
+     */
+    HDCP_NONE,
+    /**
+     * HDCP version 1.0
+     */
+    HDCP_V1,
+    /**
+     * HDCP version 2.0 Type 1.
+     */
+    HDCP_V2,
+    /**
+     * HDCP version 2.1 Type 1.
+     */
+    HDCP_V2_1,
+    /**
+     *  HDCP version 2.2 Type 1.
+     */
+    HDCP_V2_2,
+    /**
+     * No digital output, implicitly secure
+     */
+    HDCP_NO_OUTPUT,
+    /**
+     * HDCP version 2.3 Type 1.
+     */
+    HDCP_V2_3,
+}
diff --git a/drm/aidl/android/hardware/drm/HdcpLevels.aidl b/drm/aidl/android/hardware/drm/HdcpLevels.aidl
new file mode 100644
index 0000000..cd4642b
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/HdcpLevels.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.HdcpLevel;
+
+@VintfStability
+parcelable HdcpLevels {
+    /** The lowest HDCP level for any connected displays. */
+    HdcpLevel connectedLevel;
+
+    /** The highest HDCP level that can be supported by the device. */
+    HdcpLevel maxLevel;
+}
diff --git a/drm/aidl/android/hardware/drm/ICryptoFactory.aidl b/drm/aidl/android/hardware/drm/ICryptoFactory.aidl
new file mode 100644
index 0000000..202bd3d
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/ICryptoFactory.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.Uuid;
+
+/**
+ * ICryptoFactory is the main entry point for interacting with a vendor's
+ * crypto HAL to create crypto plugins.
+
+ * Crypto plugins create crypto sessions which are used by a codec to decrypt
+ * protected video content.
+ */
+@VintfStability
+interface ICryptoFactory {
+    /**
+     * Create a crypto plugin for the specified uuid and scheme-specific
+     * initialization data.
+     *
+     * @param uuid uniquely identifies the drm scheme. See
+     *     http://dashif.org/identifiers/protection for uuid assignments
+     *
+     * @param initData scheme-specific init data.
+     *
+     * @return A crypto plugin instance if successful, or null if not created.
+     */
+    @nullable android.hardware.drm.ICryptoPlugin createPlugin(
+            in Uuid uuid, in byte[] initData);
+
+    /**
+     * Determine if a crypto scheme is supported by this HAL.
+     *
+     * @param uuid identifies the crypto scheme in question
+     * @return must be true only if the scheme is supported
+     */
+    boolean isCryptoSchemeSupported(in Uuid uuid);
+}
diff --git a/drm/aidl/android/hardware/drm/ICryptoPlugin.aidl b/drm/aidl/android/hardware/drm/ICryptoPlugin.aidl
new file mode 100644
index 0000000..80a63df
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/ICryptoPlugin.aidl
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.common.Ashmem;
+import android.hardware.drm.DecryptResult;
+import android.hardware.drm.DestinationBuffer;
+import android.hardware.drm.LogMessage;
+import android.hardware.drm.Mode;
+import android.hardware.drm.Pattern;
+import android.hardware.drm.SharedBuffer;
+import android.hardware.drm.Status;
+import android.hardware.drm.SubSample;
+
+/**
+ * ICryptoPlugin is the HAL for vendor-provided crypto plugins.
+ *
+ * It allows crypto sessions to be opened and operated on, to
+ * load crypto keys for a codec to decrypt protected video content.
+ */
+@VintfStability
+interface ICryptoPlugin {
+    /**
+     * Decrypt an array of subsamples from the source memory buffer to the
+     * destination memory buffer.
+     *
+     * @param secure a flag to indicate if a secure decoder is being used.
+     *     This enables the plugin to configure buffer modes to work
+     *     consistently with a secure decoder.
+     * @param the keyId for the key that is used to do the decryption. The
+     *     keyId refers to a key in the associated MediaDrm instance.
+     * @param iv the initialization vector to use
+     * @param mode the crypto mode to use
+     * @param pattern the crypto pattern to use
+     * @param subSamples a vector of subsamples indicating the number
+     *     of clear and encrypted bytes to process. This allows the decrypt
+     *     call to operate on a range of subsamples in a single call
+     * @param source the input buffer for the decryption
+     * @param offset the offset of the first byte of encrypted data from
+     *     the base of the source buffer
+     * @param destination the output buffer for the decryption
+     *
+     * @return DecryptResult parcelable
+     *     Implicit error codes:
+     *       + ERROR_DRM_CANNOT_HANDLE in other failure cases
+     *       + ERROR_DRM_DECRYPT if the decrypt operation fails
+     *       + ERROR_DRM_FRAME_TOO_LARGE if the frame being decrypted into
+     *             the secure output buffer exceeds the size of the buffer
+     *       + ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION if required output
+     *             protections are not active
+     *       + ERROR_DRM_INSUFFICIENT_SECURITY if the security level of the
+     *             device is not sufficient to meet the requirements in
+     *             the license policy
+     *       + ERROR_DRM_INVALID_STATE if the device is in a state where it
+     *             is not able to perform decryption
+     *       + ERROR_DRM_LICENSE_EXPIRED if the license keys have expired
+     *       + ERROR_DRM_NO_LICENSE if no license keys have been loaded
+     *       + ERROR_DRM_RESOURCE_BUSY if the resources required to perform
+     *             the decryption are not available
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not
+     *             opened
+     */
+    DecryptResult decrypt(in boolean secure, in byte[] keyId, in byte[] iv, in Mode mode,
+            in Pattern pattern, in SubSample[] subSamples, in SharedBuffer source, in long offset,
+            in DestinationBuffer destination);
+
+    /**
+     * Get OEMCrypto or plugin error messages.
+     *
+     * @return LogMessages
+     *     Implicit error codes:
+     *       + GENERAL_OEM_ERROR on OEM-provided, low-level component failures;
+     *       + GENERAL_PLUGIN_ERROR on unexpected plugin-level errors.
+     */
+    List<LogMessage> getLogMessages();
+
+    /**
+     * Notify a plugin of the currently configured resolution.
+     *
+     * @param width - the display resolutions's width
+     * @param height - the display resolution's height
+     */
+    void notifyResolution(in int width, in int height);
+
+    /**
+     * Check if the specified mime-type requires a secure decoder
+     * component.
+     *
+     * @param mime The content mime-type
+     * @return must be true only if a secure decoder is required
+     * for the specified mime-type
+     */
+    boolean requiresSecureDecoderComponent(in String mime);
+
+    /**
+     * Associate a mediadrm session with this crypto session.
+     *
+     * @param sessionId the MediaDrm session ID to associate with
+     *     this crypto session
+     * @return (implicit) the status of the call, status can be:
+     *     ERROR_DRM_SESSION_NOT_OPENED if the session is not opened, or
+     *     ERROR_DRM_CANNOT_HANDLE if the operation is not supported by
+     *         the drm scheme
+     */
+    void setMediaDrmSession(in byte[] sessionId);
+
+    /**
+     * Set a shared memory base for subsequent decrypt operations.
+     * The buffer base is mmaped from a ParcelFileDesciptor in Ashmem
+     * which maps shared memory in the HAL module.
+     * After the shared buffer base is established, the decrypt() method
+     * receives SharedBuffer instances which specify the buffer address range
+     * for decrypt source and destination addresses.
+     *
+     * There can be multiple shared buffers per crypto plugin. The buffers
+     * are distinguished by the bufferId.
+     *
+     * @param base the base of the memory buffer identified by
+     *     bufferId
+     * @param bufferId identifies the specific shared buffer for which
+     *     the base is being set.
+     */
+    void setSharedBufferBase(in Ashmem base, in int bufferId);
+}
diff --git a/drm/aidl/android/hardware/drm/IDrmFactory.aidl b/drm/aidl/android/hardware/drm/IDrmFactory.aidl
new file mode 100644
index 0000000..b9622a4
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/IDrmFactory.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.SecurityLevel;
+import android.hardware.drm.Uuid;
+
+/**
+ * IDrmFactory is the main entry point for interacting with a vendor's
+ * drm HAL to create drm plugin instances. A drm plugin instance
+ * creates drm sessions which are used to obtain keys for a crypto
+ * session so it can decrypt protected video content.
+ */
+@VintfStability
+interface IDrmFactory {
+    /**
+     * Create a drm plugin instance for the specified uuid and
+     * scheme-specific initialization data.
+     *
+     * @param uuid uniquely identifies the drm scheme. See
+     *     http://dashif.org/identifiers/protection for uuid assignments
+     * @param appPackageName identifies the package name of the calling
+     *     application.
+     *
+     * @return A DRM plugin instance if successful, or null if not created.
+     *     Implicit error codes:
+     *       + ERROR_DRM_CANNOT_HANDLE if the plugin cannot be created.
+     */
+    @nullable android.hardware.drm.IDrmPlugin createPlugin(
+            in Uuid uuid, in String appPackageName);
+
+    /**
+     * Return vector of uuids identifying crypto schemes supported by
+     * this HAL.
+     *
+     * @return List of uuids for which isCryptoSchemeSupported is true;
+     *      each uuid can be used as input to createPlugin.
+     */
+    List<Uuid> getSupportedCryptoSchemes();
+
+    /**
+     * Determine if the HAL factory is able to construct plugins that
+     * support a given media container format specified by mimeType
+     *
+     * @param mimeType identifies the mime type in question
+     *
+     * @return must be true only if the scheme is supported
+     */
+    boolean isContentTypeSupported(in String mimeType);
+
+    /**
+     * Determine if a specific security level is supported by the device.
+     *
+     * @param uuid identifies the crypto scheme in question
+     * @param mimeType identifies the mime type in question
+     * @param securityLevel specifies the security level required
+     *
+     * @return must be true only if the scheme is supported
+     */
+    boolean isCryptoSchemeSupported(
+            in Uuid uuid, in String mimeType, in SecurityLevel securityLevel);
+}
diff --git a/drm/aidl/android/hardware/drm/IDrmPlugin.aidl b/drm/aidl/android/hardware/drm/IDrmPlugin.aidl
new file mode 100644
index 0000000..e649f26
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/IDrmPlugin.aidl
@@ -0,0 +1,755 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.DrmMetricGroup;
+import android.hardware.drm.HdcpLevels;
+import android.hardware.drm.IDrmPluginListener;
+import android.hardware.drm.KeySetId;
+import android.hardware.drm.KeyRequest;
+import android.hardware.drm.KeyStatus;
+import android.hardware.drm.KeyType;
+import android.hardware.drm.KeyValue;
+import android.hardware.drm.LogMessage;
+import android.hardware.drm.NumberOfSessions;
+import android.hardware.drm.OfflineLicenseState;
+import android.hardware.drm.OpaqueData;
+import android.hardware.drm.ProvideProvisionResponseResult;
+import android.hardware.drm.ProvisionRequest;
+import android.hardware.drm.SecureStop;
+import android.hardware.drm.SecureStopId;
+import android.hardware.drm.SecurityLevel;
+
+/**
+ * IDrmPlugin is used to interact with a specific drm plugin that was
+ * created by IDrmFactory::createPlugin.
+ *
+ * A drm plugin provides methods for obtaining drm keys to be used by a codec
+ * to decrypt protected video content.
+ */
+@VintfStability
+interface IDrmPlugin {
+    /**
+     * Close a session on the DrmPlugin object
+     *
+     * @param sessionId the session id the call applies to
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if the sessionId is invalid
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the session cannot be closed.
+     *     ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    void closeSession(in byte[] sessionId);
+
+    /**
+     * Decrypt the provided input buffer with the cipher algorithm
+     * specified by setCipherAlgorithm and the key selected by keyId,
+     * and return the decrypted data.
+     *
+     * @param sessionId the session id the call applies to
+     * @param keyId the ID of the key to use for decryption
+     * @param input the input data to decrypt
+     * @param iv the initialization vector to use for decryption
+     *
+     * @return decrypted output buffer
+     *     Implicit error codes:
+     *       + BAD_VALUE if the sessionId is invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the decrypt operation cannot be performed.
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    byte[] decrypt(in byte[] sessionId, in byte[] keyId, in byte[] input, in byte[] iv);
+
+    /**
+     * Encrypt the provided input buffer with the cipher algorithm specified by
+     * setCipherAlgorithm and the key selected by keyId, and return the
+     * encrypted data.
+     *
+     * @param sessionId the session id the call applies to
+     * @param keyId the ID of the key to use for encryption
+     * @param input the input data to encrypt
+     * @param iv the initialization vector to use for encryption
+     *
+     * @return encrypted output buffer
+     *     Implicit error codes:
+     *       + BAD_VALUE if the sessionId is invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the encrypt operation cannot be performed.
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    byte[] encrypt(in byte[] sessionId, in byte[] keyId, in byte[] input, in byte[] iv);
+
+    /**
+     * Return the currently negotiated and max supported HDCP levels.
+     *
+     * The current level is based on the display(s) the device is connected to.
+     * If multiple HDCP-capable displays are simultaneously connected to
+     * separate interfaces, this method returns the lowest negotiated HDCP level
+     * of all interfaces.
+     *
+     * The maximum HDCP level is the highest level that can potentially be
+     * negotiated. It is a constant for any device, i.e. it does not depend on
+     * downstream receiving devices that could be connected. For example, if
+     * the device has HDCP 1.x keys and is capable of negotiating HDCP 1.x, but
+     * does not have HDCP 2.x keys, then the maximum HDCP capability would be
+     * reported as 1.x. If multiple HDCP-capable interfaces are present, it
+     * indicates the highest of the maximum HDCP levels of all interfaces.
+     *
+     * This method should only be used for informational purposes, not for
+     * enforcing compliance with HDCP requirements. Trusted enforcement of HDCP
+     * policies must be handled by the DRM system.
+     *
+     * @return HdcpLevels parcelable
+     *     Implicit error codes:
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the HDCP level cannot be queried
+     */
+    HdcpLevels getHdcpLevels();
+
+    /**
+     * A key request/response exchange occurs between the app and a License
+     * Server to obtain the keys required to decrypt the content.
+     * getKeyRequest() is used to obtain an opaque key request blob that is
+     * delivered to the license server.
+     *
+     * @param scope either a sessionId or a keySetId, depending on the
+     *     specified keyType. When the keyType is OFFLINE or STREAMING, scope
+     *     must be set to the sessionId the keys will be provided to. When the
+     *     keyType is RELEASE, scope must be set to the keySetId of the keys
+     *     being released.
+     * @param initData container-specific data, its meaning is interpreted
+     *     based on the mime type provided in the mimeType parameter. It could
+     *     contain, for example, the content ID, key ID or other data obtained
+     *     from the content metadata that is required to generate the key
+     *     request. initData must be empty when keyType is RELEASE.
+     * @param mimeType identifies the mime type of the content
+     * @param keyType specifies if the keys are to be used for streaming,
+     *     offline or a release
+     * @param optionalParameters included in the key request message to
+     *     allow a client application to provide additional message parameters
+     *     to the server.
+     *
+     * @return KeyRequest parcelable
+     *     Implicit error codes:
+     *       + BAD_VALUE if any parameters are invalid
+     *       + ERROR_DRM_CANNOT_HANDLE if getKeyRequest is not supported at
+     *             the time of the call
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             a key request cannot be generated
+     *       + ERROR_DRM_NOT_PROVISIONED if the device requires provisioning
+     *             before it is able to generate a key request
+     *       + ERROR_DRM_RESOURCE_CONTENTION if client applications using the
+     *             hal are temporarily exceeding the available crypto resources
+     *             such that a retry of the operation is likely to succeed
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    KeyRequest getKeyRequest(in byte[] scope, in byte[] initData, in String mimeType,
+            in KeyType keyType, in KeyValue[] optionalParameters);
+
+    /**
+     * Get Plugin error messages.
+     *
+     * @return LogMessages
+     *     Implicit error codes:
+     *       + GENERAL_OEM_ERROR on OEM-provided, low-level component failures;
+     *       + GENERAL_PLUGIN_ERROR on unexpected plugin-level errors.
+     */
+    List<LogMessage> getLogMessages();
+
+    /**
+     * Returns the plugin-specific metrics. Multiple metric groups may be
+     * returned in one call to getMetrics(). The scope and definition of the
+     * metrics is defined by the plugin.
+     *
+     * @return collection of metric groups provided by the plugin
+     *     Implicit error codes:
+     *       + ERROR_DRM_INVALID_STATE if the metrics are not available to be
+     *             returned.
+     */
+    List<DrmMetricGroup> getMetrics();
+
+    /**
+     * Return the current number of open sessions and the maximum number of
+     * sessions that may be opened simultaneously among all DRM instances
+     * for the active DRM scheme.
+     *
+     * @return NumberOfSessions parcelable
+     *     Implicit error codes:
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             number of sessions cannot be queried
+     */
+    NumberOfSessions getNumberOfSessions();
+
+    /**
+     * The keys in an offline license allow protected content to be
+     * played even if the device is not connected to a network.
+     * Offline licenses are stored on the device after a key
+     * request/response exchange when the key request KeyType is
+     * OFFLINE. Normally each app is responsible for keeping track of
+     * the KeySetIds it has created. In some situations however, it
+     * will be necessary to request the list of stored offline license
+     * KeySetIds. If an app loses the KeySetId for any stored licenses
+     * that it created, for example, it must be able to recover the
+     * stored KeySetIds so those licenses will be removed when they
+     * expire or when the app is uninstalled.
+     *
+     * This method returns a list of the KeySetIds for all offline
+     * licenses. The offline license KeySetId allows an app to query
+     * the status of an offline license or remove it.
+     *
+     * @return list of keySetIds
+     *     Implicit error codes:
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             KeySetIds can't be returned
+     */
+    List<KeySetId> getOfflineLicenseKeySetIds();
+
+    /**
+     * Request the state of an offline license. An offline license must
+     * be usable or inactive. The keys in a usable offline license are
+     * available for decryption. When the offline license state is
+     * inactive, the keys have been marked for release using
+     * getKeyRequest with KeyType RELEASE but the key response has not
+     * been received. The keys in an inactive offline license are not
+     * usable for decryption.
+     *
+     * @param keySetId the id of the offline license
+     *
+     * @return The offline license state, UNKNOWN, USABLE or INACTIVE.
+     *     Implicit error codes:
+     *       + BAD_VALUE if the license is not found
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             offline license state can't be queried
+     */
+    OfflineLicenseState getOfflineLicenseState(in KeySetId keySetId);
+
+    /**
+     * Read a byte array property value given the property name.
+     * See getPropertyString.
+     *
+     * @param propertyName the name of the property
+     *
+     * @return property value bye array
+     *     Implicit error codes:
+     *       + BAD_VALUE if the property name is invalid
+     *       + ERROR_DRM_CANNOT_HANDLE if the property is not supported
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             property cannot be obtained
+     */
+    byte[] getPropertyByteArray(in String propertyName);
+
+    /**
+     * A drm scheme can have properties that are settable and readable
+     * by an app. There are a few forms of property access methods,
+     * depending on the data type of the property.
+     *
+     * Property values defined by the public API are:
+     *   "vendor" [string] identifies the maker of the drm scheme
+     *   "version" [string] identifies the version of the drm scheme
+     *   "description" [string] describes the drm scheme
+     *   'deviceUniqueId' [byte array] The device unique identifier is
+     *   established during device provisioning and provides a means of
+     *   uniquely identifying each device.
+     *
+     * Since drm scheme properties may vary, additional field names may be
+     * defined by each DRM vendor. Refer to your DRM provider documentation
+     * for definitions of its additional field names.
+     *
+     * Read a string property value given the property name.
+     *
+     * @param propertyName the name of the property
+     *
+     * @return the property value string.
+     *     Implicit error codes:
+     *       + BAD_VALUE if the property name is invalid
+     *       + ERROR_DRM_CANNOT_HANDLE if the property is not supported
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             property cannot be obtained
+     */
+    String getPropertyString(in String propertyName);
+
+    /**
+     * A provision request/response exchange occurs between the app
+     * and a provisioning server to retrieve a device certificate.
+     * getProvisionRequest is used to obtain an opaque provisioning
+     * request blob that is delivered to the provisioning server.
+     *
+     * @param certificateType the type of certificate requested, e.g. "X.509"
+     * @param certificateAuthority identifies the certificate authority.
+     *     A certificate authority (CA) is an entity which issues digital
+     *     certificates for use by other parties. It is an example of a
+     *     trusted third party.
+     *
+     * @return ProvisionRequest parcelable
+     *     Implicit error codes:
+     *       + ERROR_DRM_CANNOT_HANDLE if the drm scheme does not require
+     *             provisioning
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the provision request cannot be generated
+     *       + ERROR_DRM_RESOURCE_CONTENTION if client applications using
+     *             the hal are temporarily exceeding the available crypto
+     *             resources such that a retry of the operation is likely
+     *             to succeed
+     */
+    ProvisionRequest getProvisionRequest(
+            in String certificateType, in String certificateAuthority);
+
+    /**
+     * Get all secure stops by secure stop ID
+     *
+     * @param secureStopId the ID of the secure stop to return.
+     *     The secure stop ID is delivered by the key server
+     *     as part of the key response and must also be known by the app.
+     *
+     * @return secure stop opaque object.
+     *     Implicit error codes:
+     *       + BAD_VALUE if the secureStopId is invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the secure stop cannot be returned
+     */
+    SecureStop getSecureStop(in SecureStopId secureStopId);
+
+    /**
+     * Get the IDs of all secure stops on the device
+     *
+     * @return list of secure stops IDs.
+     *     Implicit error codes:
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the secure stop IDs list cannot be returned
+     */
+    List<SecureStopId> getSecureStopIds();
+
+    /**
+     * SecureStop is a way of enforcing the concurrent stream limit per
+     * subscriber.
+     *
+     * It can securely monitor the lifetime of sessions across device reboots
+     * by periodically persisting the session lifetime status in secure
+     * storage.
+     *
+     * A signed version of the sessionID is written to persistent storage on the
+     * device when each MediaCrypto object is created and periodically during
+     * playback. The sessionID is signed by the device private key to prevent
+     * tampering.
+     *
+     * When playback is completed the session is destroyed, and the secure
+     * stops are queried by the app. The app then delivers the secure stop
+     * message to a server which verifies the signature to confirm that the
+     * session and its keys have been removed from the device. The persisted
+     * record on the device is removed after receiving and verifying the
+     * signed response from the server.
+     *
+     * Get all secure stops on the device
+     *
+     * @return list of the opaque secure stop objects.
+     *     Implicit error codes:
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the secure stops cannot be returned
+     */
+    List<SecureStop> getSecureStops();
+
+    /**
+     * Return the current security level of a session. A session has an initial
+     * security level determined by the robustness of the DRM system's
+     * implementation on the device.
+     *
+     * @param sessionId the session id the call applies to
+     *
+     * @return the current security level for the session.
+     *     Implicit error codes:
+     *       + BAD_VALUE if the sessionId is invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             the security level cannot be queried
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    SecurityLevel getSecurityLevel(in byte[] sessionId);
+
+    /**
+     * Open a new session at a requested security level. The security level
+     * represents the robustness of the device's DRM implementation. By default,
+     * sessions are opened at the native security level of the device which is
+     * the maximum level that can be supported. Overriding the security level is
+     * necessary when the decrypted frames need to be manipulated, such as for
+     * image compositing. The security level parameter must be equal to or lower
+     * than the native level. If the requested level is not supported, the next
+     * lower supported security level must be set. The level can be queried
+     * using {@link #getSecurityLevel}. A session ID is returned.
+     *
+     * @param level the requested security level
+     *
+     * @return sessionId
+     */
+    byte[] openSession(in SecurityLevel securityLevel);
+
+    /**
+     * After a key response is received by the app, it is provided to the
+     * Drm plugin using provideKeyResponse.
+     *
+     * @param scope may be a sessionId or a keySetId depending on the
+     *     type of the response. Scope should be set to the sessionId
+     *     when the response is for either streaming or offline key requests.
+     *     Scope should be set to the keySetId when the response is for
+     *     a release request.
+     * @param response the response from the key server that is being
+     *     provided to the drm HAL.
+     *
+     * @return a keySetId that can be used to later restore the keys to a new
+     *     session with the method restoreKeys when the response is for an
+     *     offline key request.
+     *     Implicit error codes:
+     *       + BAD_VALUE if any parameters are invalid
+     *       + ERROR_DRM_CANNOT_HANDLE if provideKeyResponse is not supported
+     *             at the time of the call
+     *       + ERROR_DRM_DEVICE_REVOKED if the device has been disabled by
+     *             the license policy
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *             a key response cannot be handled.
+     *       + ERROR_DRM_NOT_PROVISIONED if the device requires provisioning
+     *             before it can handle the key response
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    KeySetId provideKeyResponse(in byte[] scope, in byte[] response);
+
+    /**
+     * After a provision response is received by the app from a provisioning
+     * server, it is provided to the Drm HAL using provideProvisionResponse.
+     * The HAL implementation must receive the provision request and
+     * store the provisioned credentials.
+     *
+     * @param response the opaque provisioning response received by the
+     * app from a provisioning server.
+     *
+     * @return ProvideProvisionResponseResult parcelable, which contains
+     *     the public certificate and encrypted private key that can be
+     *     used by signRSA to compute an RSA signature on a message.
+     *     Implicit error codes:
+     *       + BAD_VALUE if any parameters are invalid
+     *       + ERROR_DRM_DEVICE_REVOKED if the device has been disabled by
+     *             the license policy
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             provision response cannot be handled
+     */
+    ProvideProvisionResponseResult provideProvisionResponse(in byte[] response);
+
+    /**
+     * Request an informative description of the license for the session.
+     * The status is in the form of {name, value} pairs. Since DRM license
+     * policies vary by vendor, the specific status field names are
+     * determined by each DRM vendor. Refer to your DRM provider
+     * documentation for definitions of the field names for a particular
+     * drm scheme.
+     *
+     * @param sessionId the session id the call applies to
+     *
+     * @return a list of name value pairs describing the license.
+     *     Implicit error codes:
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     *       + BAD_VALUE if any parameters are invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             key status cannot be queried.
+     */
+    List<KeyValue> queryKeyStatus(in byte[] sessionId);
+
+    /**
+     * Release all secure stops on the device
+     *
+     * @return (implicit) the status of the call:
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the secure stops cannot be released.
+     */
+    void releaseAllSecureStops();
+
+    /**
+     * Release a secure stop by secure stop ID
+     *
+     * @param secureStopId the ID of the secure stop to release.
+     *     The secure stop ID is delivered by the key server as
+     *     part of the key response and must also be known by the app.
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if the secureStopId is invalid
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the secure stop cannot be released.
+     */
+    void releaseSecureStop(in SecureStopId secureStopId);
+
+    /**
+     * Release secure stops given a release message from the key server
+     *
+     * @param ssRelease the secure stop release message identifying
+     *     one or more secure stops to release. ssRelease is opaque,
+     *     it is passed directly from a DRM license server through
+     *     the app and media framework to the vendor HAL module.
+     *     The format and content of ssRelease must be defined by the
+     *     DRM scheme being implemented according to this HAL.
+     *     The DRM scheme can be identified by its UUID which
+     *     can be queried using IDrmFactory::isCryptoSchemeSupported.
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if ssRelease is invalid
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state wherei
+     *         the secure stop cannot be released.
+     */
+    void releaseSecureStops(in OpaqueData ssRelease);
+
+    /**
+     * Remove all secure stops on the device without requiring a secure
+     * stop release response message from the key server.
+     *
+     * @return (implicit) the status of the call:
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the secure stops cannot be removed.
+     */
+    void removeAllSecureStops();
+
+    /**
+     * Remove the current keys from a session
+     *
+     * @param sessionId the session id the call applies to
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if the sessionId is invalid
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the keys cannot be removed.
+     *     ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    void removeKeys(in byte[] sessionId);
+
+    /**
+     * Normally offline licenses are released using a key
+     * request/response exchange using getKeyRequest where the KeyType
+     * is RELEASE, followed by provideKeyResponse. This allows the
+     * server to cryptographically confirm that the license has been
+     * removed and then adjust the count of offline licenses allocated
+     * to the device.
+     * <p>
+     * In some exceptional situations it will be necessary to directly
+     * remove offline licenses without notifying the server, which is
+     * performed by this method.
+     *
+     * @param keySetId the id of the offline license to remove
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if the license is not found
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the KeySetIds can't be removed.
+     */
+    void removeOfflineLicense(in KeySetId keySetId);
+
+    /**
+     * Remove a secure stop given its secure stop ID, without requiring
+     * a secure stop release response message from the key server.
+     *
+     * @param secureStopId the ID of the secure stop to release.
+     *
+     * @return the status of the call:
+     *     BAD_VALUE if the secureStopId is invalid
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the secure stop cannot be removed.
+     */
+    void removeSecureStop(in SecureStopId secureStopId);
+
+    /**
+     * Check if the specified mime-type & security level require a secure decoder
+     * component.
+     *
+     * @param mime The content mime-type
+     * @param level the requested security level
+     *
+     * @return must be true if and only if a secure decoder is
+     *     required for the specified mime-type & security level
+     */
+    boolean requiresSecureDecoder(in String mime, in SecurityLevel level);
+
+    /**
+     * Check if the specified mime-type requires a secure decoder component
+     * at the highest security level supported on the device.
+     *
+     * @param mime The content mime-type
+     *
+     * @return must be true if and only if a secure decoder is required
+     *     for the specified mime-type
+     */
+    boolean requiresSecureDecoderDefault(in String mime);
+
+    /**
+     * Restore persisted offline keys into a new session
+     *
+     * @param sessionId the session id the call applies to
+     * @param keySetId identifies the keys to load, obtained from
+     *     a prior call to provideKeyResponse().
+     *
+     * @return (implicit) the status of the call:
+     *     ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     *     BAD_VALUE if any parameters are invalid
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         keys cannot be restored.
+     */
+    void restoreKeys(in byte[] sessionId, in KeySetId keySetId);
+
+    /**
+     * The following methods implement operations on a CryptoSession to support
+     * encrypt, decrypt, sign verify operations on operator-provided
+     * session keys.
+     *
+     *
+     * Set the cipher algorithm to be used for the specified session.
+     *
+     * @param sessionId the session id the call applies to
+     * @param algorithm the algorithm to use. The string conforms to JCA
+     *     Standard Names for Cipher Transforms and is case insensitive. An
+     *     example algorithm is "AES/CBC/PKCS5Padding".
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if any parameters are invalid
+     *     ERROR_DRM_INVALID_STATE  if the HAL is in a state where
+     *         the algorithm cannot be set.
+     *     ERROR_DRM_SESSION_NOT_OPENED if the session is not opened`
+     */
+    void setCipherAlgorithm(in byte[] sessionId, in String algorithm);
+
+    /**
+     * Plugins call the following methods to deliver events to the
+     * java app.
+     *
+     *
+     * Set a listener for a drm session. This allows the drm HAL to
+     * make asynchronous calls back to the client of IDrm.
+     *
+     * @param listener instance of IDrmPluginListener to receive the events
+     */
+    void setListener(in IDrmPluginListener listener);
+
+    /**
+     * Set the MAC algorithm to be used for computing hashes in a session.
+     *
+     * @param sessionId the session id the call applies to
+     * @param algorithm the algorithm to use. The string conforms to JCA
+     *     Standard Names for Mac Algorithms and is case insensitive. An example MAC
+     *     algorithm string is "HmacSHA256".
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if any parameters are invalid
+     *     ERROR_DRM_INVALID_STATE  if the HAL is in a state where
+     *         the algorithm cannot be set.
+     *     ERROR_DRM_SESSION_NOT_OPENED if the session is not opened`
+     */
+    void setMacAlgorithm(in byte[] sessionId, in String algorithm);
+
+    /**
+     * Set playback id of a drm session. The playback id can be used to join drm session metrics
+     * with metrics from other low level media components, e.g. codecs, or metrics from the high
+     * level player.
+     *
+     * @param sessionId drm session id
+     * @param playbackId high level playback id
+     *
+     * @return (implicit) the status of the call:
+     *    ERROR_DRM_SESSION_NOT_OPENED if the drm session cannot be found
+     */
+    void setPlaybackId(in byte[] sessionId, in String playbackId);
+
+    /**
+     * Write a property byte array value given the property name
+     *
+     * @param propertyName the name of the property
+     * @param value the value to write
+     *
+     * @return (implicit) the status of the call:
+     *     BAD_VALUE if the property name is invalid
+     *     ERROR_DRM_CANNOT_HANDLE if the property is not supported
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *         property cannot be set
+     */
+    void setPropertyByteArray(in String propertyName, in byte[] value);
+
+    /**
+     * Write a property string value given the property name
+     *
+     * @param propertyName the name of the property
+     * @param value the value to write
+     *
+     * @return (implicit) status of the call:
+     *     BAD_VALUE if the property name is invalid
+     *     ERROR_DRM_CANNOT_HANDLE if the property is not supported
+     *     ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *         property cannot be set
+     */
+    void setPropertyString(in String propertyName, in String value);
+
+    /**
+     * Compute a signature over the provided message using the mac algorithm
+     * specified by setMacAlgorithm and the key selected by keyId and return
+     * the signature.
+     *
+     * @param sessionId the session id the call applies to
+     * @param keyId the ID of the key to use for decryption
+     * @param message the message to compute a signature over
+     *
+     * @return signature computed over the message
+     *     Implicit error codes:
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     *       + BAD_VALUE if any parameters are invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             sign operation cannot be performed.
+     */
+    byte[] sign(in byte[] sessionId, in byte[] keyId, in byte[] message);
+
+    /**
+     * Compute an RSA signature on the provided message using the specified
+     * algorithm.
+     *
+     * @param sessionId the session id the call applies to
+     * @param algorithm the signing algorithm, such as "RSASSA-PSS-SHA1"
+     *     or "PKCS1-BlockType1"
+     * @param message the message to compute the signature on
+     * @param wrappedKey the private key returned during provisioning as
+     *     returned by provideProvisionResponse.
+     *
+     * @return signature computed over the message
+     *     Implicit error codes:
+     *       + BAD_VALUE if any parameters are invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             signRSA operation operation cannot be performed
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     */
+    byte[] signRSA(
+            in byte[] sessionId, in String algorithm, in byte[] message,
+            in byte[] wrappedkey);
+
+    /**
+     * Compute a hash of the provided message using the mac algorithm specified
+     * by setMacAlgorithm and the key selected by keyId, and compare with the
+     * expected result.
+     *
+     * @param sessionId the session id the call applies to
+     * @param keyId the ID of the key to use for decryption
+     * @param message the message to compute a hash of
+     * @param signature the signature to verify
+     *
+     * @return true if the signature is verified positively, false otherwise.
+     *     Implicit error codes:
+     *       + ERROR_DRM_SESSION_NOT_OPENED if the session is not opened
+     *       + BAD_VALUE if any parameters are invalid
+     *       + ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *             verify operation cannot be performed.
+     */
+    boolean verify(
+            in byte[] sessionId, in byte[] keyId, in byte[] message,
+            in byte[] signature);
+}
diff --git a/drm/aidl/android/hardware/drm/IDrmPluginListener.aidl b/drm/aidl/android/hardware/drm/IDrmPluginListener.aidl
new file mode 100644
index 0000000..d52da66
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/IDrmPluginListener.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.EventType;
+import android.hardware.drm.KeyStatus;
+
+/**
+ * IDrmPluginListener is a listener interface for Drm events sent from an
+ * IDrmPlugin instance.
+ */
+@VintfStability
+interface IDrmPluginListener {
+    /**
+     * Legacy event sending method, it sends events of various types using a
+     * single overloaded set of parameters. This form is deprecated.
+     *
+     * @param eventType the type of the event
+     * @param sessionId identifies the session the event originated from
+     * @param data event-specific data blob
+     */
+    oneway void onEvent(in EventType eventType, in byte[] sessionId, in byte[] data);
+
+    /**
+     * Send a license expiration update to the listener. The expiration
+     * update indicates how long the current keys are valid before they
+     * need to be renewed.
+     *
+     * @param sessionId identifies the session the event originated from
+     * @param expiryTimeInMS the time when the keys need to be renewed.
+     * The time is in milliseconds, relative to the Unix epoch. A time
+     * of 0 indicates that the keys never expire.
+     */
+    oneway void onExpirationUpdate(in byte[] sessionId, in long expiryTimeInMS);
+
+    /**
+     * Send a keys change event to the listener. The keys change event
+     * indicates the status of each key in the session. Keys can be
+     * indicated as being usable, expired, outputnotallowed or statuspending.
+     *
+     * @param sessionId identifies the session the event originated from
+     * @param keyStatusList indicates the status for each key ID in the
+     * session.
+     * @param hasNewUsableKey indicates if the event includes at least one
+     * key that has become usable.
+     */
+    oneway void onKeysChange(
+            in byte[] sessionId, in KeyStatus[] keyStatusList, in boolean hasNewUsableKey);
+
+    /**
+     * Some device crypto hardware is incapable of retaining crypto
+     * session state across suspend and resume cycles. A
+     * SessionLostState event must be signaled when a session has
+     * become invalid for this reason. This event must not be used to
+     * indicate a failure in the crypto system. Closing the session
+     * and opening a new one must allow the application to resume
+     * normal use of the drm hal module.
+     *
+     * @param sessionId identifies the session that has been invalidated
+     */
+    oneway void onSessionLostState(in byte[] sessionId);
+}
diff --git a/drm/aidl/android/hardware/drm/KeyRequest.aidl b/drm/aidl/android/hardware/drm/KeyRequest.aidl
new file mode 100644
index 0000000..0c73205
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/KeyRequest.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.KeyRequestType;
+
+@VintfStability
+parcelable KeyRequest {
+    /** The opaque key request blob. */
+    byte[] request;
+
+    /**
+     * Enumerated type:
+     *     INITIAL - the first key request for a license
+     *     NONE - indicates that no request is needed because the keys
+     *         are already loaded
+     *     RENEWAL - is a subsequent key request used to refresh the
+     *         keys in a license
+     *     RELEASE - indicates keys are being released
+     *     UPDATE - indicates that the keys need to be refetched after
+     *         the initial license request
+     */
+    KeyRequestType requestType;
+
+    /**
+     * The URL that the request may be sent to,
+     * if provided by the drm HAL. The app can choose to
+     * override this URL. If the HAL implementation does not provide
+     * a defaultUrl, the returned string must be empty.
+     */
+    String defaultUrl;
+}
diff --git a/drm/aidl/android/hardware/drm/KeyRequestType.aidl b/drm/aidl/android/hardware/drm/KeyRequestType.aidl
new file mode 100644
index 0000000..3a603ff
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/KeyRequestType.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * An app determines the type of a key request returned from getKeyRequest.
+ */
+@VintfStability
+@Backing(type="int")
+enum KeyRequestType {
+    /**
+     * Key request type is for an initial license request
+     */
+    INITIAL,
+    /**
+     * Key request type is for license renewal. Renewal requests are used
+     * to extend the validity period for streaming keys.
+     */
+    RENEWAL,
+    /**
+     * Key request type is a release. A key release causes offline keys
+     * to become available for streaming.
+     */
+    RELEASE,
+    /**
+     * Key request type is unknown due to some error condition.
+     */
+    UNKNOWN,
+    /**
+     * Keys are already loaded. No key request is needed.
+     */
+    NONE,
+    /**
+     * Keys have previously been loaded. An additional (non-renewal) license
+     * request is needed.
+     */
+    UPDATE,
+}
diff --git a/drm/aidl/android/hardware/drm/KeySetId.aidl b/drm/aidl/android/hardware/drm/KeySetId.aidl
new file mode 100644
index 0000000..be0ce0e
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/KeySetId.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable KeySetId {
+    byte[] keySetId;
+}
diff --git a/drm/aidl/android/hardware/drm/KeyStatus.aidl b/drm/aidl/android/hardware/drm/KeyStatus.aidl
new file mode 100644
index 0000000..16e042a
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/KeyStatus.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.KeyStatusType;
+
+/**
+ * Used by sendKeysChange to report the usability status of each key
+ * to the app.
+ */
+@VintfStability
+parcelable KeyStatus {
+    byte[] keyId;
+    KeyStatusType type;
+}
diff --git a/drm/aidl/android/hardware/drm/KeyStatusType.aidl b/drm/aidl/android/hardware/drm/KeyStatusType.aidl
new file mode 100644
index 0000000..6902d87
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/KeyStatusType.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+@Backing(type="int")
+enum KeyStatusType {
+    /**
+     * The key is currently usable to decrypt media data.
+     */
+    USABLE,
+    /**
+     * The key is no longer usable to decrypt media data because its expiration
+     * time has passed.
+     */
+    EXPIRED,
+    /**
+     * The key is not currently usable to decrypt media data because its output
+     * requirements cannot currently be met.
+     */
+    OUTPUTNOTALLOWED,
+    /**
+     * The status of the key is not yet known and is being determined.
+     */
+    STATUSPENDING,
+    /**
+     * The key is not currently usable to decrypt media data because of an
+     * internal error in processing unrelated to input parameters.
+     */
+    INTERNALERROR,
+    /**
+     * The key is not yet usable to decrypt media because the start
+     * time is in the future. The key must become usable when
+     * its start time is reached.
+     */
+    USABLEINFUTURE,
+}
diff --git a/drm/aidl/android/hardware/drm/KeyType.aidl b/drm/aidl/android/hardware/drm/KeyType.aidl
new file mode 100644
index 0000000..78b4d83
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/KeyType.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+@Backing(type="int")
+enum KeyType {
+    /**
+     * Drm keys can be for offline content or for online streaming.
+     * Offline keys are persisted on the device and may be used when the device
+     * is disconnected from the network.
+     */
+    OFFLINE,
+    /**
+     * Keys for streaming are not persisted and require the device to be
+     * connected to the network for periodic renewal.
+     */
+    STREAMING,
+    /**
+     * The Release type is used to request that offline keys be no longer
+     * restricted to offline use.
+     */
+    RELEASE,
+}
diff --git a/drm/aidl/android/hardware/drm/KeyValue.aidl b/drm/aidl/android/hardware/drm/KeyValue.aidl
new file mode 100644
index 0000000..e26781b
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/KeyValue.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable KeyValue {
+    String key;
+    String value;
+}
diff --git a/drm/aidl/android/hardware/drm/LogMessage.aidl b/drm/aidl/android/hardware/drm/LogMessage.aidl
new file mode 100644
index 0000000..8ac1ced
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/LogMessage.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.LogPriority;
+
+/**
+ * Returned by getLogMessages to report error diagnostics to the
+ * app.
+ *
+ * The |message| field is for informational purposes only, and
+ * NOT meant to be parsed programmatically when handling errors.
+ * For programmatic error handling, please check the return |Status|
+ * of APIs instead.
+ */
+@VintfStability
+parcelable LogMessage {
+    /**
+     * Epoch time in milliseconds.
+     */
+    long timeMs;
+    LogPriority priority;
+    String message;
+}
diff --git a/drm/aidl/android/hardware/drm/LogPriority.aidl b/drm/aidl/android/hardware/drm/LogPriority.aidl
new file mode 100644
index 0000000..4db3b40
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/LogPriority.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+@Backing(type="int")
+enum LogPriority {
+    UNKNOWN,
+    DEFAULT,
+    VERBOSE,
+    DEBUG,
+    INFO,
+    WARN,
+    ERROR,
+    FATAL,
+}
diff --git a/drm/aidl/android/hardware/drm/Mode.aidl b/drm/aidl/android/hardware/drm/Mode.aidl
new file mode 100644
index 0000000..6fc0065
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/Mode.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * Enumerate the supported crypto modes
+ */
+@VintfStability
+@Backing(type="int")
+enum Mode {
+    UNENCRYPTED = 0,
+    AES_CTR = 1,
+    AES_CBC_CTS = 2,
+    AES_CBC = 3,
+}
diff --git a/drm/aidl/android/hardware/drm/NumberOfSessions.aidl b/drm/aidl/android/hardware/drm/NumberOfSessions.aidl
new file mode 100644
index 0000000..75b7c2e
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/NumberOfSessions.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable NumberOfSessions {
+    /** The number of currently opened sessions. */
+    int currentSessions;
+
+    /** The maximum number of sessions that the device can support. */
+    int maxSessions;
+}
diff --git a/drm/aidl/android/hardware/drm/OfflineLicenseState.aidl b/drm/aidl/android/hardware/drm/OfflineLicenseState.aidl
new file mode 100644
index 0000000..0f447db
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/OfflineLicenseState.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+@Backing(type="int")
+enum OfflineLicenseState {
+    /**
+     * Offline license state is unknown
+     */
+    UNKNOWN,
+    /**
+     * Offline license state is usable, the keys are usable for decryption.
+     */
+    USABLE,
+    /**
+     * Offline license state is inactive, the keys have been marked for
+     * release using {@link #getKeyRequest} with KEY_TYPE_RELEASE but the
+     * key response has not been received.
+     */
+    INACTIVE,
+}
diff --git a/drm/aidl/android/hardware/drm/OpaqueData.aidl b/drm/aidl/android/hardware/drm/OpaqueData.aidl
new file mode 100644
index 0000000..6b2a2e7
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/OpaqueData.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable OpaqueData {
+    byte[] opaqueData;
+}
diff --git a/drm/aidl/android/hardware/drm/Pattern.aidl b/drm/aidl/android/hardware/drm/Pattern.aidl
new file mode 100644
index 0000000..88d22cf
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/Pattern.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * A crypto Pattern is a repeating sequence of encrypted and clear blocks
+ * occurring within the bytes indicated by mNumBytesOfEncryptedDatad bytes
+ * of a subsample. Patterns are used to reduce the CPU overhead of
+ * decrypting samples. As an example, HLS uses 1:9 patterns where every
+ * 10th block is encrypted.
+ */
+@VintfStability
+parcelable Pattern {
+    /**
+     * The number of blocks to be encrypted in the pattern. If zero,
+     * pattern encryption is inoperative.
+     */
+    int encryptBlocks;
+
+    /**
+     * The number of blocks to be skipped (left clear) in the pattern. If
+     * zero, pattern encryption is inoperative.
+     */
+    int skipBlocks;
+}
diff --git a/drm/aidl/android/hardware/drm/ProvideProvisionResponseResult.aidl b/drm/aidl/android/hardware/drm/ProvideProvisionResponseResult.aidl
new file mode 100644
index 0000000..e9f1e2b
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/ProvideProvisionResponseResult.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable ProvideProvisionResponseResult {
+    /**
+     * The public certificate resulting from the provisioning
+     * operation, if any. An empty vector indicates that no
+     * certificate was returned.
+     */
+    byte[] certificate;
+
+    /**
+     * An opaque object containing encrypted private key material
+     * to be used by signRSA when computing an RSA signature on a
+     * message, see the signRSA method.
+     */
+    byte[] wrappedKey;
+}
diff --git a/drm/aidl/android/hardware/drm/ProvisionRequest.aidl b/drm/aidl/android/hardware/drm/ProvisionRequest.aidl
new file mode 100644
index 0000000..eb42d32
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/ProvisionRequest.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable ProvisionRequest {
+    /** The opaque certificate request blob. */
+    byte[] request;
+
+    /**
+     * The URL that the provisioning request may be sent to,
+     * if known by the HAL implementation. An app can choose to
+     * override this URL. If the HAL implementation does not provide
+     * a defaultUrl, the returned string must be empty.
+     */
+    String defaultUrl;
+}
diff --git a/drm/aidl/android/hardware/drm/SecureStop.aidl b/drm/aidl/android/hardware/drm/SecureStop.aidl
new file mode 100644
index 0000000..37cfbd3
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/SecureStop.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * Encapsulates a secure stop opaque object.
+ */
+@VintfStability
+parcelable SecureStop {
+    byte[] opaqueData;
+}
diff --git a/drm/aidl/android/hardware/drm/SecureStopId.aidl b/drm/aidl/android/hardware/drm/SecureStopId.aidl
new file mode 100644
index 0000000..775e60b
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/SecureStopId.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable SecureStopId {
+    byte[] secureStopId;
+}
diff --git a/drm/aidl/android/hardware/drm/SecurityLevel.aidl b/drm/aidl/android/hardware/drm/SecurityLevel.aidl
new file mode 100644
index 0000000..aac1b68
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/SecurityLevel.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+@Backing(type="int")
+enum SecurityLevel {
+    /**
+     * Unable to determine the security level
+     */
+    UNKNOWN,
+    /**
+     * Software-based whitebox crypto
+     */
+    SW_SECURE_CRYPTO,
+    /**
+     * Software-based whitebox crypto and an obfuscated decoder
+     */
+    SW_SECURE_DECODE,
+    /**
+     * DRM key management and crypto operations are performed within a
+     * hardware backed trusted execution environment
+     */
+    HW_SECURE_CRYPTO,
+    /**
+     * DRM key management, crypto operations and decoding of content
+     * are performed within a hardware backed trusted execution environment
+     */
+    HW_SECURE_DECODE,
+    /**
+     * DRM key management, crypto operations, decoding of content and all
+     * handling of the media (compressed and uncompressed) is handled within
+     * a hardware backed trusted execution environment.
+     */
+    HW_SECURE_ALL,
+    /**
+     * The default security level is defined as the highest security level
+     * supported on the device.
+     */
+    DEFAULT,
+}
diff --git a/drm/aidl/android/hardware/drm/SharedBuffer.aidl b/drm/aidl/android/hardware/drm/SharedBuffer.aidl
new file mode 100644
index 0000000..6977284
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/SharedBuffer.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * SharedBuffer describes a decrypt buffer which is defined by a bufferId, an
+ * offset and a size.  The offset is relative to the shared memory base for the
+ * memory region identified by bufferId, which is established by
+ * setSharedMemoryBase().
+ */
+@VintfStability
+parcelable SharedBuffer {
+    /**
+     * The unique buffer identifier
+     */
+    int bufferId;
+    /**
+     * The offset from the shared memory base
+     */
+    long offset;
+    /**
+     * The size of the shared buffer in bytes
+     */
+    long size;
+}
diff --git a/drm/aidl/android/hardware/drm/Status.aidl b/drm/aidl/android/hardware/drm/Status.aidl
new file mode 100644
index 0000000..ee57d64
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/Status.aidl
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+@Backing(type="int")
+enum Status {
+    /**
+     * The DRM plugin must return OK when an operation completes without any
+     * errors.
+     */
+    OK,
+    /**
+     * The DRM plugin must return ERROR_DRM_NO_LICENSE, when decryption is
+     * attempted and no license keys have been provided.
+     */
+    ERROR_DRM_NO_LICENSE,
+    /**
+     * ERROR_DRM_LICENSE_EXPIRED must be returned when an attempt is made
+     * to use a license and the keys in that license have expired.
+     */
+    ERROR_DRM_LICENSE_EXPIRED,
+    /**
+     * The DRM plugin must return ERROR_DRM_SESSION_NOT_OPENED when an
+     * attempt is made to use a session that has not been opened.
+     */
+    ERROR_DRM_SESSION_NOT_OPENED,
+    /**
+     * The DRM plugin must return ERROR_DRM_CANNOT_HANDLE when an unsupported
+     * data format or operation is attempted.
+     */
+    ERROR_DRM_CANNOT_HANDLE,
+    /**
+     * ERROR_DRM_INVALID_STATE must be returned when the device is in a state
+     * where it is not able to perform decryption.
+     */
+    ERROR_DRM_INVALID_STATE,
+    /**
+     * The DRM plugin must return BAD_VALUE whenever an illegal parameter is
+     * passed to one of the interface functions.
+     */
+    BAD_VALUE,
+    /**
+     * The DRM plugin must return ERROR_DRM_NOT_PROVISIONED from getKeyRequest,
+     * openSession or provideKeyResponse when the device has not yet been
+     * provisioned.
+     */
+    ERROR_DRM_NOT_PROVISIONED,
+    /**
+     * ERROR_DRM_RESOURCE_BUSY must be returned when resources, such as drm
+     * sessions or secure buffers are not available to perform a requested
+     * operation because they are already in use.
+     */
+    ERROR_DRM_RESOURCE_BUSY,
+    /**
+     * The DRM Plugin must return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION
+     * when the output protection level enabled on the device is not
+     * sufficient to meet the requirements in the license policy.  HDCP is an
+     * example of a form of output protection.
+     */
+    ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION,
+    /**
+     * The DRM Plugin must return ERROR_DRM_DEVICE_REVOKED from
+     * provideProvisionResponse and provideKeyResponse if the response indicates
+     * that the device has been revoked. Device revocation means that the device
+     * is no longer permitted to play content.
+     */
+    ERROR_DRM_DEVICE_REVOKED,
+    /**
+     * The DRM Plugin must return ERROR_DRM_DECRYPT if the CryptoPlugin
+     * decrypt operation fails.
+     */
+    ERROR_DRM_DECRYPT,
+    /**
+     * ERROR_DRM_UNKNOWN must be returned when a fatal failure occurs and no
+     * other defined error is appropriate.
+     */
+    ERROR_DRM_UNKNOWN,
+    /**
+     * The drm HAL module must return ERROR_DRM_INSUFFICIENT_SECURITY
+     * from the crypto plugin decrypt method when the security level
+     * of the device is not sufficient to meet the requirements in the
+     * license policy.
+     */
+    ERROR_DRM_INSUFFICIENT_SECURITY,
+    /**
+     * The drm HAL module must return ERROR_FRAME_TOO_LARGE from the
+     * decrypt method when the frame being decrypted into the secure
+     * output buffer exceeds the size of the buffer.
+     */
+    ERROR_DRM_FRAME_TOO_LARGE,
+    /**
+     * This error must be returned from any session method when an
+     * attempt is made to use the session after the crypto hardware
+     * state has been invalidated. Some devices are not able to
+     * retain crypto session state across device suspend/resume which
+     * results in invalid session state.
+     */
+    ERROR_DRM_SESSION_LOST_STATE,
+    /**
+     * The drm HAL module must return this error if client
+     * applications using the hal are temporarily exceeding the
+     * capacity of available crypto resources such that a retry of
+     * the operation is likely to succeed.
+     */
+    ERROR_DRM_RESOURCE_CONTENTION,
+    /**
+     * queueSecureInput buffer called with 0 subsamples.
+     */
+    CANNOT_DECRYPT_ZERO_SUBSAMPLES,
+    /**
+     * An error happened within the crypto library used by the drm plugin.
+     */
+    CRYPTO_LIBRARY_ERROR,
+    /**
+     * Non-specific error reported by the device OEM subsystem.
+     */
+    GENERAL_OEM_ERROR,
+    /**
+     * Unexpected internal failure in the drm/crypto plugin.
+     */
+    GENERAL_PLUGIN_ERROR,
+    /**
+     * The init data parameter passed to getKeyRequest is empty or invalid.
+     */
+    INIT_DATA_INVALID,
+    /**
+     * Either the key was not loaded from the license before attempting the
+     * operation, or the key ID parameter provided by the app is incorrect.
+     */
+    KEY_NOT_LOADED,
+    /**
+     * The license response was empty, fields are missing or otherwise unable
+     * to be parsed.
+     */
+    LICENSE_PARSE_ERROR,
+    /**
+     * The operation (e.g. to renew or persist a license) is prohibited by the
+     * license policy.
+     */
+    LICENSE_POLICY_ERROR,
+    /**
+     * Failed to generate a release request because a field in the stored
+     * license is empty or malformed.
+     */
+    LICENSE_RELEASE_ERROR,
+    /**
+     * The license server detected an error in the license request.
+     */
+    LICENSE_REQUEST_REJECTED,
+    /**
+     * Failed to restore an offline license because a field is empty or
+     * malformed.
+     */
+    LICENSE_RESTORE_ERROR,
+    /**
+     * License is in an invalid state for the attempted operation.
+     */
+    LICENSE_STATE_ERROR,
+    /**
+     * Certificate is malformed or is of the wrong type.
+     */
+    MALFORMED_CERTIFICATE,
+    /**
+     * Failure in the media framework.
+     */
+    MEDIA_FRAMEWORK_ERROR,
+    /**
+     * Certificate has not been set.
+     */
+    MISSING_CERTIFICATE,
+    /**
+     * There was an error loading the provisioned certificate.
+     */
+    PROVISIONING_CERTIFICATE_ERROR,
+    /**
+     * Required steps where not performed before provisioning was attempted.
+     */
+    PROVISIONING_CONFIGURATION_ERROR,
+    /**
+     * The provisioning response was empty, fields are missing or otherwise
+     * unable to be parsed.
+     */
+    PROVISIONING_PARSE_ERROR,
+    /**
+     * The provisioning server detected an error in the provisioning request.
+     */
+    PROVISIONING_REQUEST_REJECTED,
+    /**
+     * Provisioning failed in a way that is likely to succeed on a subsequent
+     * attempt.
+     */
+    RETRYABLE_PROVISIONING_ERROR,
+    /**
+     * Failed to generate a secure stop request because a field in the stored
+     * license is empty or malformed.
+     */
+    SECURE_STOP_RELEASE_ERROR,
+    /**
+     * The plugin was unable to read data from the filesystem.
+     */
+    STORAGE_READ_FAILURE,
+    /**
+     * The plugin was unable to write data to the filesystem.
+     */
+    STORAGE_WRITE_FAILURE,
+}
diff --git a/drm/aidl/android/hardware/drm/SubSample.aidl b/drm/aidl/android/hardware/drm/SubSample.aidl
new file mode 100644
index 0000000..68a8fb1
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/SubSample.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+/**
+ * A subsample consists of some number of bytes of clear (unencrypted)
+ * data followed by a number of bytes of encrypted data.
+ */
+@VintfStability
+parcelable SubSample {
+    int numBytesOfClearData;
+    int numBytesOfEncryptedData;
+}
diff --git a/drm/aidl/android/hardware/drm/Uuid.aidl b/drm/aidl/android/hardware/drm/Uuid.aidl
new file mode 100644
index 0000000..b36c409
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/Uuid.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm;
+
+@VintfStability
+parcelable Uuid {
+    byte[] uuid;
+}
diff --git a/dumpstate/aidl/Android.bp b/dumpstate/aidl/Android.bp
new file mode 100644
index 0000000..22d836b
--- /dev/null
+++ b/dumpstate/aidl/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.dumpstate",
+    vendor_available: true,
+    srcs: ["android/hardware/dumpstate/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/dumpstate/aidl/aidl_api/android.hardware.dumpstate/current/android/hardware/dumpstate/IDumpstateDevice.aidl b/dumpstate/aidl/aidl_api/android.hardware.dumpstate/current/android/hardware/dumpstate/IDumpstateDevice.aidl
new file mode 100644
index 0000000..4d78a4c
--- /dev/null
+++ b/dumpstate/aidl/aidl_api/android.hardware.dumpstate/current/android/hardware/dumpstate/IDumpstateDevice.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.dumpstate;
+@VintfStability
+interface IDumpstateDevice {
+  void dumpstateBoard(in ParcelFileDescriptor[] fd, in android.hardware.dumpstate.IDumpstateDevice.DumpstateMode mode, in long timeoutMillis);
+  boolean getVerboseLoggingEnabled();
+  void setVerboseLoggingEnabled(in boolean enable);
+  const int ERROR_UNSUPPORTED_MODE = 1;
+  const int ERROR_DEVICE_LOGGING_NOT_ENABLED = 2;
+  @Backing(type="int") @VintfStability
+  enum DumpstateMode {
+    FULL = 0,
+    INTERACTIVE = 1,
+    REMOTE = 2,
+    WEAR = 3,
+    CONNECTIVITY = 4,
+    WIFI = 5,
+    DEFAULT = 6,
+    PROTO = 7,
+  }
+}
diff --git a/dumpstate/aidl/android/hardware/dumpstate/IDumpstateDevice.aidl b/dumpstate/aidl/android/hardware/dumpstate/IDumpstateDevice.aidl
new file mode 100644
index 0000000..b994d04
--- /dev/null
+++ b/dumpstate/aidl/android/hardware/dumpstate/IDumpstateDevice.aidl
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.dumpstate;
+
+import android.os.ParcelFileDescriptor;
+
+@VintfStability
+interface IDumpstateDevice {
+    /**
+     * Constants that define the type of bug report being taken to restrict content appropriately.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum DumpstateMode {
+        /**
+         * Takes a bug report without user interference.
+         */
+        FULL = 0,
+        /**
+         * Interactive bug report, i.e. triggered by the user.
+         */
+        INTERACTIVE = 1,
+        /**
+         * Remote bug report triggered by DevicePolicyManager, for example.
+         */
+        REMOTE = 2,
+        /**
+         * Bug report triggered on a wear device.
+         */
+        WEAR = 3,
+        /**
+         * Bug report limited to only connectivity info (cellular, wifi, and networking). Sometimes
+         * called "telephony" in legacy contexts.
+         *
+         * All reported information MUST directly relate to connectivity debugging or customer
+         * support and MUST NOT contain unrelated private information. This information MUST NOT
+         * identify user-installed packages (UIDs are OK, package names are not), and MUST NOT
+         * contain logs of user application traffic.
+         */
+        CONNECTIVITY = 4,
+        /**
+         * Bug report limited to only wifi info.
+         */
+        WIFI = 5,
+        /**
+         * Default mode, This mode MUST be supported if the
+         * dumpstate HAL is implemented.
+         */
+        DEFAULT = 6,
+        /**
+         * Takes a report in protobuf.
+         *
+         * The content, if implemented, must be a binary protobuf message written to the first file
+         * descriptor of the native handle. The protobuf schema shall be defined by the vendor.
+         */
+        PROTO = 7,
+    }
+
+    /**
+     * Returned for cases where the device doesn't support the given DumpstateMode (e.g. a phone
+     * trying to use DumpstateMode::WEAR).
+     */
+    const int ERROR_UNSUPPORTED_MODE = 1;
+    /**
+     * Returned when device logging is not enabled.
+     */
+    const int ERROR_DEVICE_LOGGING_NOT_ENABLED = 2;
+
+    /**
+     * Dump device-specific state into the given file descriptors.
+     *
+     * One file descriptor must be passed to this method but two may be passed:
+     * the first descriptor must be used to dump device-specific state in text
+     * format, the second descriptor is optional and may be used to dump
+     * device-specific state in binary format.
+     *
+     * DumpstateMode can be used to limit the information that is output.
+     * For an example of when this is relevant, consider a bug report being generated with
+     * DumpstateMode::CONNECTIVITY - there is no reason to include camera or USB logs in this type
+     * of report.
+     *
+     * When verbose logging is disabled, getVerboseLoggingEnabled returns false, and this
+     * API is called, it may still output essential information but must not include
+     * information that identifies the user.
+     *
+     * @param fd array of file descriptors, with one or two valid file descriptors. The first FD is
+     *         for text output, the second (if present) is for binary output.
+     * @param mode A mode value to restrict dumped content.
+     * @param timeoutMillis An approximate "budget" for how much time this call has been allotted.
+     *     If execution runs longer than this, the IDumpstateDevice service may be killed and only
+     *     partial information will be included in the report.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |ERROR_UNSUPPORTED_MODE|,
+     *         |ERROR_DEVICE_LOGGING_NOT_ENABLED|
+     */
+    void dumpstateBoard(in ParcelFileDescriptor[] fd, in DumpstateMode mode, in long timeoutMillis);
+
+    /**
+     * Queries the current state of verbose device logging. Primarily for UI and informative
+     * purposes.
+     *
+     * Even if verbose logging has been disabled, dumpstateBoard may still be called by the
+     * dumpstate routine, and essential information that does not identify the user may be included.
+     *
+     * @return Whether or not verbose vendor logging is currently enabled.
+     */
+    boolean getVerboseLoggingEnabled();
+
+    /**
+     * Turns verbose device vendor logging on or off.
+     *
+     * The setting should be persistent across reboots. Underlying implementations may need to start
+     * vendor logging daemons, set system properties, or change logging masks, for example. Given
+     * that many vendor logs contain significant amounts of private information and may come with
+     * memory/storage/battery impacts, calling this method on a user build should only be done after
+     * user consent has been obtained, e.g. from a toggle in developer settings.
+     *
+     * Even if verbose logging has been disabled, dumpstateBoard may still be called by the
+     * dumpstate routine, and essential information that does not identify the user may be included.
+     *
+     * @param enable Whether to enable or disable verbose vendor logging.
+     */
+    void setVerboseLoggingEnabled(in boolean enable);
+}
diff --git a/dumpstate/aidl/default/Android.bp b/dumpstate/aidl/default/Android.bp
new file mode 100644
index 0000000..45fdc17
--- /dev/null
+++ b/dumpstate/aidl/default/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.dumpstate-service.example",
+    relative_install_path: "hw",
+    init_rc: ["dumpstate-default.rc"],
+    vintf_fragments: ["dumpstate-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libdumpstateutil",
+        "liblog",
+        "libutils",
+        "android.hardware.dumpstate-V1-ndk",
+    ],
+    srcs: [
+        "main.cpp",
+        "Dumpstate.cpp",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"android.hardware.dumpstate-service.example\"",
+    ],
+}
diff --git a/dumpstate/aidl/default/Dumpstate.cpp b/dumpstate/aidl/default/Dumpstate.cpp
new file mode 100644
index 0000000..a0730fb
--- /dev/null
+++ b/dumpstate/aidl/default/Dumpstate.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/properties.h>
+#include <log/log.h>
+#include "DumpstateUtil.h"
+
+#include "Dumpstate.h"
+
+using android::os::dumpstate::DumpFileToFd;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace dumpstate {
+
+const char kVerboseLoggingProperty[] = "persist.dumpstate.verbose_logging.enabled";
+
+ndk::ScopedAStatus Dumpstate::dumpstateBoard(const std::vector<::ndk::ScopedFileDescriptor>& in_fds,
+                                             IDumpstateDevice::DumpstateMode in_mode,
+                                             int64_t in_timeoutMillis) {
+    (void)in_timeoutMillis;
+
+    if (in_fds.size() < 1) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "No file descriptor");
+    }
+
+    int fd = in_fds[0].get();
+    if (fd < 0) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "Invalid file descriptor");
+    }
+
+    switch (in_mode) {
+        case IDumpstateDevice::DumpstateMode::FULL:
+            return dumpstateBoardImpl(fd, true);
+
+        case IDumpstateDevice::DumpstateMode::DEFAULT:
+            return dumpstateBoardImpl(fd, false);
+
+        case IDumpstateDevice::DumpstateMode::INTERACTIVE:
+        case IDumpstateDevice::DumpstateMode::REMOTE:
+        case IDumpstateDevice::DumpstateMode::WEAR:
+        case IDumpstateDevice::DumpstateMode::CONNECTIVITY:
+        case IDumpstateDevice::DumpstateMode::WIFI:
+        case IDumpstateDevice::DumpstateMode::PROTO:
+            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ERROR_UNSUPPORTED_MODE,
+                                                                           "Unsupported mode");
+
+        default:
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "Invalid mode");
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Dumpstate::getVerboseLoggingEnabled(bool* _aidl_return) {
+    *_aidl_return = getVerboseLoggingEnabledImpl();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Dumpstate::setVerboseLoggingEnabled(bool in_enable) {
+    ::android::base::SetProperty(kVerboseLoggingProperty, in_enable ? "true" : "false");
+    return ndk::ScopedAStatus::ok();
+}
+
+bool Dumpstate::getVerboseLoggingEnabledImpl() {
+    return ::android::base::GetBoolProperty(kVerboseLoggingProperty, false);
+}
+
+ndk::ScopedAStatus Dumpstate::dumpstateBoardImpl(const int fd, const bool full) {
+    ALOGD("DumpstateDevice::dumpstateBoard() FD: %d\n", fd);
+
+    dprintf(fd, "verbose logging: %s\n", getVerboseLoggingEnabledImpl() ? "enabled" : "disabled");
+    dprintf(fd, "[%s] %s\n", (full ? "full" : "default"), "Hello, world!");
+
+    // Shows an example on how to use the libdumpstateutil API.
+    DumpFileToFd(fd, "cmdline", "/proc/self/cmdline");
+
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace dumpstate
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/dumpstate/aidl/default/Dumpstate.h b/dumpstate/aidl/default/Dumpstate.h
new file mode 100644
index 0000000..0629831
--- /dev/null
+++ b/dumpstate/aidl/default/Dumpstate.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/dumpstate/BnDumpstateDevice.h>
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
+#include <android/binder_status.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace dumpstate {
+
+class Dumpstate : public BnDumpstateDevice {
+  private:
+    bool getVerboseLoggingEnabledImpl();
+    ::ndk::ScopedAStatus dumpstateBoardImpl(const int fd, const bool full);
+
+  public:
+    ::ndk::ScopedAStatus dumpstateBoard(const std::vector<::ndk::ScopedFileDescriptor>& in_fds,
+                                        IDumpstateDevice::DumpstateMode in_mode,
+                                        int64_t in_timeoutMillis) override;
+
+    ::ndk::ScopedAStatus getVerboseLoggingEnabled(bool* _aidl_return) override;
+
+    ::ndk::ScopedAStatus setVerboseLoggingEnabled(bool in_enable) override;
+};
+
+}  // namespace dumpstate
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/dumpstate/aidl/default/dumpstate-default.rc b/dumpstate/aidl/default/dumpstate-default.rc
new file mode 100644
index 0000000..4d011dd
--- /dev/null
+++ b/dumpstate/aidl/default/dumpstate-default.rc
@@ -0,0 +1,7 @@
+service vendor.dumpstate-default /vendor/bin/hw/android.hardware.dumpstate-service.example
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.dumpstate.IDumpstateDevice/default
+    oneshot
+    disabled
diff --git a/dumpstate/aidl/default/dumpstate-default.xml b/dumpstate/aidl/default/dumpstate-default.xml
new file mode 100644
index 0000000..877aeed
--- /dev/null
+++ b/dumpstate/aidl/default/dumpstate-default.xml
@@ -0,0 +1,8 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.dumpstate</name>
+        <version>1</version>
+        <fqname>IDumpstateDevice/default</fqname>
+    </hal>
+</manifest>
+
diff --git a/dumpstate/aidl/default/main.cpp b/dumpstate/aidl/default/main.cpp
new file mode 100644
index 0000000..5bc85b4
--- /dev/null
+++ b/dumpstate/aidl/default/main.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dumpstate.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::dumpstate::Dumpstate;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<Dumpstate> dumpstate = ndk::SharedRefBase::make<Dumpstate>();
+
+    const std::string instance = std::string() + Dumpstate::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_registerLazyService(dumpstate->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // Unreachable
+}
diff --git a/dumpstate/aidl/vts/functional/Android.bp b/dumpstate/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..5e516cf
--- /dev/null
+++ b/dumpstate/aidl/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalDumpstateTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalDumpstateTargetTest.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+        "libvintf",
+    ],
+    static_libs: [
+        "android.hardware.dumpstate-V1-ndk",
+    ],
+    test_suites: [
+        "vts",
+    ],
+}
diff --git a/dumpstate/aidl/vts/functional/VtsHalDumpstateTargetTest.cpp b/dumpstate/aidl/vts/functional/VtsHalDumpstateTargetTest.cpp
new file mode 100644
index 0000000..442b0b0
--- /dev/null
+++ b/dumpstate/aidl/vts/functional/VtsHalDumpstateTargetTest.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <functional>
+#include <tuple>
+#include <vector>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::dumpstate::IDumpstateDevice;
+
+// Base class common to all dumpstate HAL AIDL tests.
+template <typename T>
+class DumpstateAidlTestBase : public ::testing::TestWithParam<T> {
+  protected:
+    bool CheckStatus(const ndk::ScopedAStatus& status, const binder_exception_t expected_ex_code,
+                     const int32_t expected_service_specific) {
+        binder_exception_t ex_code = status.getExceptionCode();
+        if (ex_code != expected_ex_code) {
+            return false;
+        }
+        if (ex_code == EX_SERVICE_SPECIFIC) {
+            int32_t service_specific = status.getServiceSpecificError();
+            if (service_specific != expected_service_specific) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+  public:
+    virtual void SetUp() override { GetService(); }
+
+    virtual std::string GetInstanceName() = 0;
+
+    void GetService() {
+        const std::string instance_name = GetInstanceName();
+
+        ASSERT_TRUE(AServiceManager_isDeclared(instance_name.c_str()));
+        auto dumpstateBinder =
+                ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str()));
+        dumpstate = IDumpstateDevice::fromBinder(dumpstateBinder);
+        ASSERT_NE(dumpstate, nullptr) << "Could not get AIDL instance " << instance_name;
+    }
+
+    void ToggleVerboseLogging(bool enable) {
+        ndk::ScopedAStatus status;
+        bool logging_enabled = false;
+
+        status = dumpstate->setVerboseLoggingEnabled(enable);
+        ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.getDescription();
+
+        status = dumpstate->getVerboseLoggingEnabled(&logging_enabled);
+        ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.getDescription();
+        ASSERT_EQ(logging_enabled, enable)
+                << "Verbose logging should now be " << (enable ? "enabled" : "disabled");
+    }
+
+    void EnableVerboseLogging() { ToggleVerboseLogging(true); }
+
+    void DisableVerboseLogging() { ToggleVerboseLogging(false); }
+
+    std::shared_ptr<IDumpstateDevice> dumpstate;
+};
+
+// Tests that don't need to iterate every single DumpstateMode value for dumpstateBoard_1_1.
+class DumpstateAidlGeneralTest : public DumpstateAidlTestBase<std::string> {
+  protected:
+    virtual std::string GetInstanceName() override { return GetParam(); }
+};
+
+// Tests that iterate every single DumpstateMode value for dumpstateBoard_1_1.
+class DumpstateAidlPerModeTest
+    : public DumpstateAidlTestBase<std::tuple<std::string, IDumpstateDevice::DumpstateMode>> {
+  protected:
+    virtual std::string GetInstanceName() override { return std::get<0>(GetParam()); }
+
+    IDumpstateDevice::DumpstateMode GetMode() { return std::get<1>(GetParam()); }
+
+    // Will only execute additional_assertions when status == expected.
+    void AssertStatusForMode(const ::ndk::ScopedAStatus& status,
+                             binder_exception_t expected_ex_code, int32_t expected_service_specific,
+                             std::function<void()> additional_assertions = nullptr) {
+        if (GetMode() == IDumpstateDevice::DumpstateMode::DEFAULT) {
+            ASSERT_TRUE(CheckStatus(status, expected_ex_code, expected_ex_code));
+        } else {
+            // The rest of the modes are optional to support, but they MUST return either the
+            // expected value or UNSUPPORTED_MODE.
+            ASSERT_TRUE(CheckStatus(status, expected_ex_code, expected_service_specific) ||
+                        CheckStatus(status, EX_SERVICE_SPECIFIC,
+                                    IDumpstateDevice::ERROR_UNSUPPORTED_MODE));
+        }
+        if (CheckStatus(status, expected_ex_code, expected_service_specific) &&
+            additional_assertions != nullptr) {
+            additional_assertions();
+        }
+    }
+};
+
+constexpr uint64_t kDefaultTimeoutMillis = 30 * 1000;  // 30 seconds
+
+// Negative test: make sure dumpstateBoard() doesn't crash when passed a empty file descriptor
+// array.
+TEST_P(DumpstateAidlPerModeTest, TestNullHandle) {
+    EnableVerboseLogging();
+
+    std::vector<::ndk::ScopedFileDescriptor> dumpstateFds;  // empty file descriptor vector
+
+    auto status = dumpstate->dumpstateBoard(dumpstateFds, GetMode(), kDefaultTimeoutMillis);
+    AssertStatusForMode(status, EX_ILLEGAL_ARGUMENT, 0);
+}
+
+// Positive test: make sure dumpstateBoard() writes something to the FD.
+TEST_P(DumpstateAidlPerModeTest, TestOk) {
+    EnableVerboseLogging();
+
+    // Index 0 corresponds to the read end of the pipe; 1 to the write end.
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+    std::vector<::ndk::ScopedFileDescriptor> dumpstateFds;
+    dumpstateFds.emplace_back(fds[1]);
+
+    auto status = dumpstate->dumpstateBoard(dumpstateFds, GetMode(), kDefaultTimeoutMillis);
+
+    AssertStatusForMode(status, EX_NONE, 0, [&fds]() {
+        // Check that at least one byte was written.
+        char buff;
+        ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing";
+    });
+
+    close(fds[1]);
+    close(fds[0]);
+}
+
+// Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
+TEST_P(DumpstateAidlPerModeTest, TestHandleWithTwoFds) {
+    EnableVerboseLogging();
+
+    int fds1[2];
+    int fds2[2];
+    ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
+    ASSERT_EQ(0, pipe2(fds2, O_NONBLOCK)) << errno;
+
+    std::vector<::ndk::ScopedFileDescriptor> dumpstateFds;
+    dumpstateFds.emplace_back(fds1[1]);
+    dumpstateFds.emplace_back(fds2[1]);
+
+    auto status = dumpstate->dumpstateBoard(dumpstateFds, GetMode(), kDefaultTimeoutMillis);
+
+    AssertStatusForMode(status, EX_NONE, 0, [&fds1, &fds2]() {
+        // Check that at least one byte was written to one of the FDs.
+        char buff;
+        size_t read1 = read(fds1[0], &buff, 1);
+        size_t read2 = read(fds2[0], &buff, 1);
+        // Sometimes read returns -1, so we can't just add them together and expect >= 1.
+        ASSERT_TRUE(read1 == 1 || read2 == 1) << "Dumped nothing";
+    });
+
+    close(fds1[1]);
+    close(fds1[0]);
+    close(fds2[1]);
+    close(fds2[0]);
+}
+
+// Make sure dumpstateBoard actually validates its arguments.
+TEST_P(DumpstateAidlGeneralTest, TestInvalidModeArgument_Negative) {
+    EnableVerboseLogging();
+
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+    std::vector<::ndk::ScopedFileDescriptor> dumpstateFds;
+    dumpstateFds.emplace_back(fds[1]);
+
+    auto status = dumpstate->dumpstateBoard(dumpstateFds,
+                                            static_cast<IDumpstateDevice::DumpstateMode>(-100),
+                                            kDefaultTimeoutMillis);
+    ASSERT_TRUE(CheckStatus(status, EX_ILLEGAL_ARGUMENT, 0));
+
+    close(fds[1]);
+    close(fds[0]);
+}
+
+TEST_P(DumpstateAidlGeneralTest, TestInvalidModeArgument_Undefined) {
+    EnableVerboseLogging();
+
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+    std::vector<::ndk::ScopedFileDescriptor> dumpstateFds;
+    dumpstateFds.emplace_back(fds[1]);
+
+    auto status = dumpstate->dumpstateBoard(dumpstateFds,
+                                            static_cast<IDumpstateDevice::DumpstateMode>(9001),
+                                            kDefaultTimeoutMillis);
+    ASSERT_TRUE(CheckStatus(status, EX_ILLEGAL_ARGUMENT, 0));
+
+    close(fds[1]);
+    close(fds[0]);
+}
+
+// Make sure disabling verbose logging behaves correctly. Some info is still allowed to be emitted,
+// but it can't have privacy/storage/battery impacts.
+TEST_P(DumpstateAidlPerModeTest, TestDeviceLoggingDisabled) {
+    DisableVerboseLogging();
+
+    // Index 0 corresponds to the read end of the pipe; 1 to the write end.
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+    std::vector<::ndk::ScopedFileDescriptor> dumpstateFds;
+    dumpstateFds.emplace_back(fds[1]);
+
+    auto status = dumpstate->dumpstateBoard(dumpstateFds, GetMode(), kDefaultTimeoutMillis);
+
+    // We don't include additional assertions here about the file passed in. If verbose logging is
+    // disabled, the OEM may choose to include nothing at all, but it is allowed to include some
+    // essential information based on the mode as long as it isn't private user information.
+    AssertStatusForMode(status, EX_NONE, 0);
+
+    close(fds[1]);
+    close(fds[0]);
+}
+
+// Double-enable is perfectly valid, but the second call shouldn't do anything.
+TEST_P(DumpstateAidlGeneralTest, TestRepeatedEnable) {
+    EnableVerboseLogging();
+    EnableVerboseLogging();
+}
+
+// Double-disable is perfectly valid, but the second call shouldn't do anything.
+TEST_P(DumpstateAidlGeneralTest, TestRepeatedDisable) {
+    DisableVerboseLogging();
+    DisableVerboseLogging();
+}
+
+// Toggling in short order is perfectly valid.
+TEST_P(DumpstateAidlGeneralTest, TestRepeatedToggle) {
+    EnableVerboseLogging();
+    DisableVerboseLogging();
+    EnableVerboseLogging();
+    DisableVerboseLogging();
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DumpstateAidlGeneralTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, DumpstateAidlGeneralTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IDumpstateDevice::descriptor)),
+        android::PrintInstanceNameToString);
+
+// Includes the mode's name as part of the description string.
+static inline std::string PrintInstanceNameToStringWithMode(
+        const testing::TestParamInfo<std::tuple<std::string, IDumpstateDevice::DumpstateMode>>&
+                info) {
+    return android::PrintInstanceNameToString(
+                   testing::TestParamInfo(std::get<0>(info.param), info.index)) +
+           "_" + toString(std::get<1>(info.param));
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DumpstateAidlPerModeTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstanceAndMode, DumpstateAidlPerModeTest,
+        testing::Combine(
+                testing::ValuesIn(android::getAidlHalInstanceNames(IDumpstateDevice::descriptor)),
+                testing::ValuesIn(ndk::internal::enum_values<IDumpstateDevice::DumpstateMode>)),
+        PrintInstanceNameToStringWithMode);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index c59d5e7..f8fad94 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -36,6 +36,7 @@
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@common-vts-lib",
+        "android.hardware.gnss-V2-cpp",
     ],
     shared_libs: [
         "android.hardware.gnss.measurement_corrections@1.0",
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 3bbd572..2042dd9 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -39,6 +39,10 @@
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@2.1",
         "android.hardware.gnss@common-vts-lib",
+        "android.hardware.gnss-V2-cpp",
     ],
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
index aaddd96..d7b6eeb 100644
--- a/gnss/2.1/vts/functional/Android.bp
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -40,6 +40,7 @@
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@2.1",
         "android.hardware.gnss@common-vts-lib",
+        "android.hardware.gnss-V2-cpp",
     ],
     shared_libs: [
         "libvintf",
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
index b197eae..4d9c5cc 100644
--- a/gnss/aidl/Android.bp
+++ b/gnss/aidl/Android.bp
@@ -26,7 +26,11 @@
 aidl_interface {
     name: "android.hardware.gnss",
     vendor_available: true,
-    srcs: ["android/hardware/gnss/*.aidl"],
+    srcs: [
+        "android/hardware/gnss/*.aidl",
+        "android/hardware/gnss/measurement_corrections/*.aidl",
+        "android/hardware/gnss/visibility_control/*.aidl",
+    ],
     stability: "vintf",
     backend: {
         java: {
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
index ebb5d0b..aa514da 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
@@ -37,4 +37,11 @@
   android.hardware.gnss.GnssMeasurement[] measurements;
   android.hardware.gnss.GnssClock clock;
   android.hardware.gnss.ElapsedRealtime elapsedRealtime;
+  @nullable android.hardware.gnss.GnssData.GnssAgc[] gnssAgcs;
+  @VintfStability
+  parcelable GnssAgc {
+    double agcLevelDb;
+    android.hardware.gnss.GnssConstellationType constellation = android.hardware.gnss.GnssConstellationType.UNKNOWN;
+    long carrierFrequencyHz;
+  }
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnss.aidl
new file mode 100644
index 0000000..1a69f33
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnss.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gnss;
+@VintfStability
+interface IAGnss {
+  void setCallback(in android.hardware.gnss.IAGnssCallback callback);
+  void dataConnClosed();
+  void dataConnFailed();
+  void setServer(in android.hardware.gnss.IAGnssCallback.AGnssType type, in @utf8InCpp String hostname, in int port);
+  void dataConnOpen(in long networkHandle, in @utf8InCpp String apn, in android.hardware.gnss.IAGnss.ApnIpType apnIpType);
+  @Backing(type="int") @VintfStability
+  enum ApnIpType {
+    INVALID = 0,
+    IPV4 = 1,
+    IPV6 = 2,
+    IPV4V6 = 3,
+  }
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssCallback.aidl
new file mode 100644
index 0000000..2a46f61
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssCallback.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IAGnssCallback {
+  void agnssStatusCb(in android.hardware.gnss.IAGnssCallback.AGnssType type, in android.hardware.gnss.IAGnssCallback.AGnssStatusValue status);
+  @Backing(type="int") @VintfStability
+  enum AGnssType {
+    SUPL = 1,
+    C2K = 2,
+    SUPL_EIMS = 3,
+    SUPL_IMS = 4,
+  }
+  @Backing(type="int") @VintfStability
+  enum AGnssStatusValue {
+    REQUEST_AGNSS_DATA_CONN = 1,
+    RELEASE_AGNSS_DATA_CONN = 2,
+    AGNSS_DATA_CONNECTED = 3,
+    AGNSS_DATA_CONN_DONE = 4,
+    AGNSS_DATA_CONN_FAILED = 5,
+  }
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
new file mode 100644
index 0000000..73df195
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
@@ -0,0 +1,79 @@
+/*
+ * 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.gnss;
+@VintfStability
+interface IAGnssRil {
+  void setCallback(in android.hardware.gnss.IAGnssRilCallback callback);
+  void setRefLocation(in android.hardware.gnss.IAGnssRil.AGnssRefLocation agnssReflocation);
+  void setSetId(in android.hardware.gnss.IAGnssRil.SetIDType type, in @utf8InCpp String setid);
+  void updateNetworkState(in android.hardware.gnss.IAGnssRil.NetworkAttributes attributes);
+  const int NETWORK_CAPABILITY_NOT_METERED = 1;
+  const int NETWORK_CAPABILITY_NOT_ROAMING = 2;
+  @Backing(type="int") @VintfStability
+  enum AGnssRefLocationType {
+    GSM_CELLID = 1,
+    UMTS_CELLID = 2,
+    LTE_CELLID = 4,
+    NR_CELLID = 8,
+  }
+  @Backing(type="int") @VintfStability
+  enum SetIDType {
+    NONE = 0,
+    IMSI = 1,
+    MSISDM = 2,
+  }
+  @VintfStability
+  parcelable AGnssRefLocationCellID {
+    android.hardware.gnss.IAGnssRil.AGnssRefLocationType type;
+    int mcc;
+    int mnc;
+    int lac;
+    long cid;
+    int tac;
+    int pcid;
+    int arfcn;
+  }
+  @VintfStability
+  parcelable AGnssRefLocation {
+    android.hardware.gnss.IAGnssRil.AGnssRefLocationType type;
+    android.hardware.gnss.IAGnssRil.AGnssRefLocationCellID cellID;
+  }
+  @VintfStability
+  parcelable NetworkAttributes {
+    long networkHandle;
+    boolean isConnected;
+    int capabilities;
+    @utf8InCpp String apn;
+  }
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl
new file mode 100644
index 0000000..152b10a
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.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.gnss;
+@VintfStability
+interface IAGnssRilCallback {
+  void requestSetIdCb(in int setIdflag);
+  void requestRefLocCb();
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
index 9bd04a0..a16d27b 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
@@ -43,7 +43,47 @@
   @nullable android.hardware.gnss.IGnssBatching getExtensionGnssBatching();
   @nullable android.hardware.gnss.IGnssGeofence getExtensionGnssGeofence();
   @nullable android.hardware.gnss.IGnssNavigationMessageInterface getExtensionGnssNavigationMessage();
+  android.hardware.gnss.IAGnss getExtensionAGnss();
+  android.hardware.gnss.IAGnssRil getExtensionAGnssRil();
+  android.hardware.gnss.IGnssDebug getExtensionGnssDebug();
+  android.hardware.gnss.visibility_control.IGnssVisibilityControl getExtensionGnssVisibilityControl();
+  void start();
+  void stop();
+  void injectTime(in long timeMs, in long timeReferenceMs, in int uncertaintyMs);
+  void injectLocation(in android.hardware.gnss.GnssLocation location);
+  void injectBestLocation(in android.hardware.gnss.GnssLocation location);
+  void deleteAidingData(in android.hardware.gnss.IGnss.GnssAidingData aidingDataFlags);
+  void setPositionMode(in android.hardware.gnss.IGnss.GnssPositionMode mode, in android.hardware.gnss.IGnss.GnssPositionRecurrence recurrence, in int minIntervalMs, in int preferredAccuracyMeters, in int preferredTimeMs, in boolean lowPowerMode);
+  android.hardware.gnss.IGnssAntennaInfo getExtensionGnssAntennaInfo();
+  @nullable android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsInterface getExtensionMeasurementCorrections();
   const int ERROR_INVALID_ARGUMENT = 1;
   const int ERROR_ALREADY_INIT = 2;
   const int ERROR_GENERIC = 3;
+  @Backing(type="int") @VintfStability
+  enum GnssPositionMode {
+    STANDALONE = 0,
+    MS_BASED = 1,
+    MS_ASSISTED = 2,
+  }
+  @Backing(type="int") @VintfStability
+  enum GnssPositionRecurrence {
+    RECURRENCE_PERIODIC = 0,
+    RECURRENCE_SINGLE = 1,
+  }
+  @Backing(type="int") @VintfStability
+  enum GnssAidingData {
+    DELETE_EPHEMERIS = 1,
+    DELETE_ALMANAC = 2,
+    DELETE_POSITION = 4,
+    DELETE_TIME = 8,
+    DELETE_IONO = 16,
+    DELETE_UTC = 32,
+    DELETE_HEALTH = 64,
+    DELETE_SVDIR = 128,
+    DELETE_SVSTEER = 256,
+    DELETE_SADATA = 512,
+    DELETE_RTI = 1024,
+    DELETE_CELLDB_INFO = 32768,
+    DELETE_ALL = 65535,
+  }
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
new file mode 100644
index 0000000..2734ac1
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gnss;
+@VintfStability
+interface IGnssAntennaInfo {
+  void setCallback(in android.hardware.gnss.IGnssAntennaInfoCallback callback);
+  void close();
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
new file mode 100644
index 0000000..ada9707
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gnss;
+@VintfStability
+interface IGnssAntennaInfoCallback {
+  void gnssAntennaInfoCb(in android.hardware.gnss.IGnssAntennaInfoCallback.GnssAntennaInfo[] gnssAntennaInfos);
+  @VintfStability
+  parcelable Row {
+    double[] row;
+  }
+  @VintfStability
+  parcelable Coord {
+    double x;
+    double xUncertainty;
+    double y;
+    double yUncertainty;
+    double z;
+    double zUncertainty;
+  }
+  @VintfStability
+  parcelable GnssAntennaInfo {
+    long carrierFrequencyHz;
+    android.hardware.gnss.IGnssAntennaInfoCallback.Coord phaseCenterOffsetCoordinateMillimeters;
+    android.hardware.gnss.IGnssAntennaInfoCallback.Row[] phaseCenterVariationCorrectionMillimeters;
+    android.hardware.gnss.IGnssAntennaInfoCallback.Row[] phaseCenterVariationCorrectionUncertaintyMillimeters;
+    android.hardware.gnss.IGnssAntennaInfoCallback.Row[] signalGainCorrectionDbi;
+    android.hardware.gnss.IGnssAntennaInfoCallback.Row[] signalGainCorrectionUncertaintyDbi;
+  }
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
index 492edc3..e1beed3 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
@@ -36,9 +36,15 @@
 interface IGnssBatching {
   void init(in android.hardware.gnss.IGnssBatchingCallback callback);
   int getBatchSize();
-  void start(in long periodNanos, in int flags);
+  void start(in android.hardware.gnss.IGnssBatching.Options options);
   void flush();
   void stop();
   void cleanup();
   const int WAKEUP_ON_FIFO_FULL = 1;
+  @VintfStability
+  parcelable Options {
+    long periodNanos;
+    float minDistanceMeters;
+    int flags;
+  }
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
index fb0931c..957a75f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
@@ -35,8 +35,60 @@
 @VintfStability
 interface IGnssCallback {
   void gnssSetCapabilitiesCb(in int capabilities);
+  void gnssStatusCb(in android.hardware.gnss.IGnssCallback.GnssStatusValue status);
+  void gnssSvStatusCb(in android.hardware.gnss.IGnssCallback.GnssSvInfo[] svInfoList);
+  void gnssLocationCb(in android.hardware.gnss.GnssLocation location);
+  void gnssNmeaCb(in long timestamp, in @utf8InCpp String nmea);
+  void gnssAcquireWakelockCb();
+  void gnssReleaseWakelockCb();
+  void gnssSetSystemInfoCb(in android.hardware.gnss.IGnssCallback.GnssSystemInfo info);
+  void gnssRequestTimeCb();
+  void gnssRequestLocationCb(in boolean independentFromGnss, in boolean isUserEmergency);
+  const int CAPABILITY_SCHEDULING = 1;
+  const int CAPABILITY_MSB = 2;
+  const int CAPABILITY_MSA = 4;
+  const int CAPABILITY_SINGLE_SHOT = 8;
+  const int CAPABILITY_ON_DEMAND_TIME = 16;
+  const int CAPABILITY_GEOFENCING = 32;
+  const int CAPABILITY_MEASUREMENTS = 64;
+  const int CAPABILITY_NAV_MESSAGES = 128;
+  const int CAPABILITY_LOW_POWER_MODE = 256;
   const int CAPABILITY_SATELLITE_BLOCKLIST = 512;
+  const int CAPABILITY_MEASUREMENT_CORRECTIONS = 1024;
+  const int CAPABILITY_ANTENNA_INFO = 2048;
   const int CAPABILITY_CORRELATION_VECTOR = 4096;
   const int CAPABILITY_SATELLITE_PVT = 8192;
   const int CAPABILITY_MEASUREMENT_CORRECTIONS_FOR_DRIVING = 16384;
+  @Backing(type="int") @VintfStability
+  enum GnssStatusValue {
+    NONE = 0,
+    SESSION_BEGIN = 1,
+    SESSION_END = 2,
+    ENGINE_ON = 3,
+    ENGINE_OFF = 4,
+  }
+  @Backing(type="int") @VintfStability
+  enum GnssSvFlags {
+    NONE = 0,
+    HAS_EPHEMERIS_DATA = 1,
+    HAS_ALMANAC_DATA = 2,
+    USED_IN_FIX = 4,
+    HAS_CARRIER_FREQUENCY = 8,
+  }
+  @VintfStability
+  parcelable GnssSvInfo {
+    int svid;
+    android.hardware.gnss.GnssConstellationType constellation;
+    float cN0Dbhz;
+    float basebandCN0DbHz;
+    float elevationDegrees;
+    float azimuthDegrees;
+    long carrierFrequencyHz;
+    int svFlag;
+  }
+  @VintfStability
+  parcelable GnssSystemInfo {
+    int yearOfHw;
+    @utf8InCpp String name;
+  }
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssDebug.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssDebug.aidl
new file mode 100644
index 0000000..27d9887
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssDebug.aidl
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IGnssDebug {
+  android.hardware.gnss.IGnssDebug.DebugData getDebugData();
+  @Backing(type="int") @VintfStability
+  enum SatelliteEphemerisType {
+    EPHEMERIS = 0,
+    ALMANAC_ONLY = 1,
+    NOT_AVAILABLE = 2,
+  }
+  @Backing(type="int") @VintfStability
+  enum SatelliteEphemerisSource {
+    DEMODULATED = 0,
+    SUPL_PROVIDED = 1,
+    OTHER_SERVER_PROVIDED = 2,
+    OTHER = 3,
+  }
+  @Backing(type="int") @VintfStability
+  enum SatelliteEphemerisHealth {
+    GOOD = 0,
+    BAD = 1,
+    UNKNOWN = 2,
+  }
+  @VintfStability
+  parcelable TimeDebug {
+    long timeEstimateMs;
+    float timeUncertaintyNs;
+    float frequencyUncertaintyNsPerSec;
+  }
+  @VintfStability
+  parcelable PositionDebug {
+    boolean valid;
+    double latitudeDegrees;
+    double longitudeDegrees;
+    float altitudeMeters;
+    float speedMetersPerSec;
+    float bearingDegrees;
+    double horizontalAccuracyMeters;
+    double verticalAccuracyMeters;
+    double speedAccuracyMetersPerSecond;
+    double bearingAccuracyDegrees;
+    float ageSeconds;
+  }
+  @VintfStability
+  parcelable SatelliteData {
+    int svid;
+    android.hardware.gnss.GnssConstellationType constellation;
+    android.hardware.gnss.IGnssDebug.SatelliteEphemerisType ephemerisType;
+    android.hardware.gnss.IGnssDebug.SatelliteEphemerisSource ephemerisSource;
+    android.hardware.gnss.IGnssDebug.SatelliteEphemerisHealth ephemerisHealth;
+    float ephemerisAgeSeconds;
+    boolean serverPredictionIsAvailable;
+    float serverPredictionAgeSeconds;
+  }
+  @VintfStability
+  parcelable DebugData {
+    android.hardware.gnss.IGnssDebug.PositionDebug position;
+    android.hardware.gnss.IGnssDebug.TimeDebug time;
+    List<android.hardware.gnss.IGnssDebug.SatelliteData> satelliteDataArray;
+  }
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 24d6f9c..9c4a54b 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -36,4 +36,11 @@
 interface IGnssMeasurementInterface {
   void setCallback(in android.hardware.gnss.IGnssMeasurementCallback callback, in boolean enableFullTracking, in boolean enableCorrVecOutputs);
   void close();
+  void setCallbackWithOptions(in android.hardware.gnss.IGnssMeasurementCallback callback, in android.hardware.gnss.IGnssMeasurementInterface.Options options);
+  @VintfStability
+  parcelable Options {
+    boolean enableFullTracking;
+    boolean enableCorrVecOutputs;
+    int intervalMs;
+  }
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
new file mode 100644
index 0000000..c4cf13f
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss.measurement_corrections;
+@VintfStability
+interface IMeasurementCorrectionsCallback {
+  void setCapabilitiesCb(in int capabilities);
+  const int CAPABILITY_LOS_SATS = 1;
+  const int CAPABILITY_EXCESS_PATH_LENGTH = 2;
+  const int CAPABILITY_REFLECTING_PLANE = 4;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
new file mode 100644
index 0000000..5dc5596
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gnss.measurement_corrections;
+@VintfStability
+interface IMeasurementCorrectionsInterface {
+  void setCorrections(in android.hardware.gnss.measurement_corrections.MeasurementCorrections corrections);
+  void setCallback(in android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsCallback callback);
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
new file mode 100644
index 0000000..f32c8c2
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss.measurement_corrections;
+@VintfStability
+parcelable MeasurementCorrections {
+  double latitudeDegrees;
+  double longitudeDegrees;
+  double altitudeMeters;
+  double horizontalPositionUncertaintyMeters;
+  double verticalPositionUncertaintyMeters;
+  long toaGpsNanosecondsOfWeek;
+  android.hardware.gnss.measurement_corrections.SingleSatCorrection[] satCorrections;
+  boolean hasEnvironmentBearing;
+  float environmentBearingDegrees;
+  float environmentBearingUncertaintyDegrees;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
new file mode 100644
index 0000000..90c3818
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss.measurement_corrections;
+@VintfStability
+parcelable ReflectingPlane {
+  double latitudeDegrees;
+  double longitudeDegrees;
+  double altitudeMeters;
+  double azimuthDegrees;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
new file mode 100644
index 0000000..d18c1a7
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gnss.measurement_corrections;
+@VintfStability
+parcelable SingleSatCorrection {
+  int singleSatCorrectionFlags;
+  android.hardware.gnss.GnssConstellationType constellation;
+  int svid;
+  long carrierFrequencyHz;
+  float probSatIsLos;
+  float excessPathLengthMeters;
+  float excessPathLengthUncertaintyMeters;
+  android.hardware.gnss.measurement_corrections.ReflectingPlane reflectingPlane;
+  const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 1;
+  const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 2;
+  const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 4;
+  const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 8;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
new file mode 100644
index 0000000..f674099
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gnss.visibility_control;
+@VintfStability
+interface IGnssVisibilityControl {
+  void enableNfwLocationAccess(in @utf8InCpp String[] proxyApps);
+  void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
new file mode 100644
index 0000000..37e1886
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss.visibility_control;
+@VintfStability
+interface IGnssVisibilityControlCallback {
+  void nfwNotifyCb(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback.NfwNotification notification);
+  boolean isInEmergencySession();
+  @Backing(type="int") @VintfStability
+  enum NfwProtocolStack {
+    CTRL_PLANE = 0,
+    SUPL = 1,
+    IMS = 10,
+    SIM = 11,
+    OTHER_PROTOCOL_STACK = 100,
+  }
+  @Backing(type="int") @VintfStability
+  enum NfwRequestor {
+    CARRIER = 0,
+    OEM = 10,
+    MODEM_CHIPSET_VENDOR = 11,
+    GNSS_CHIPSET_VENDOR = 12,
+    OTHER_CHIPSET_VENDOR = 13,
+    AUTOMOBILE_CLIENT = 20,
+    OTHER_REQUESTOR = 100,
+  }
+  @Backing(type="int") @VintfStability
+  enum NfwResponseType {
+    REJECTED = 0,
+    ACCEPTED_NO_LOCATION_PROVIDED = 1,
+    ACCEPTED_LOCATION_PROVIDED = 2,
+  }
+  @VintfStability
+  parcelable NfwNotification {
+    String proxyAppPackageName;
+    android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback.NfwProtocolStack protocolStack;
+    String otherProtocolStackName;
+    android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback.NfwRequestor requestor;
+    String requestorId;
+    android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback.NfwResponseType responseType;
+    boolean inEmergencyMode;
+    boolean isCachedLocation;
+  }
+}
diff --git a/gnss/aidl/android/hardware/gnss/GnssData.aidl b/gnss/aidl/android/hardware/gnss/GnssData.aidl
index ed30c98..204eb65 100644
--- a/gnss/aidl/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssData.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.gnss.ElapsedRealtime;
 import android.hardware.gnss.GnssClock;
+import android.hardware.gnss.GnssConstellationType;
 import android.hardware.gnss.GnssMeasurement;
 
 /**
@@ -41,4 +42,55 @@
      * clock.
      */
     ElapsedRealtime elapsedRealtime;
-}
\ No newline at end of file
+
+    /**
+     * Represents a reading of GNSS AGC value of a constellation type and a frequency band.
+     */
+    @VintfStability
+    parcelable GnssAgc {
+        /**
+         * Automatic gain control (AGC) level. AGC acts as a variable gain amplifier adjusting the
+         * power of the incoming signal. The AGC level may be used to indicate potential
+         * interference. Higher gain (and/or lower input power) must be output as a positive number.
+         * Hence in cases of strong jamming, in the band of this signal, this value must go more
+         * negative. This value must be consistent given the same level of the incoming signal
+         * power.
+         *
+         * Note: Different hardware designs (e.g. antenna, pre-amplification, or other RF HW
+         * components) may also affect the typical output of this value on any given hardware design
+         * in an open sky test - the important aspect of this output is that changes in this value
+         * are indicative of changes on input signal power in the frequency band for this
+         * measurement.
+         */
+        double agcLevelDb;
+
+        /**
+         * Constellation type of the SV that transmits the signal.
+         */
+        GnssConstellationType constellation = GnssConstellationType.UNKNOWN;
+
+        /**
+         * Carrier frequency of the signal tracked, for example it can be the
+         * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 =
+         * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it
+         * is the primary common use central frequency, e.g. L1 = 1575.45 MHz
+         * for GPS.
+         *
+         * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
+         * time, two raw measurement structs must be reported for this same
+         * satellite, in one of the measurement structs, all the values related
+         * to L1 must be filled, and in the other all of the values related to
+         * L5 must be filled.
+         */
+        long carrierFrequencyHz;
+    }
+
+    /**
+     * The array of GNSS AGC values.
+     *
+     * This field must be reported when the GNSS measurement engine is running, even when the
+     * GnssMeasurement or GnssClock fields are not reported yet. E.g., when a GNSS signal is too
+     * weak to be acquired, the AGC value must still be reported.
+     */
+    @nullable GnssAgc[] gnssAgcs;
+}
diff --git a/gnss/aidl/android/hardware/gnss/IAGnss.aidl b/gnss/aidl/android/hardware/gnss/IAGnss.aidl
new file mode 100644
index 0000000..30b2167
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IAGnss.aidl
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss;
+
+import android.hardware.gnss.IAGnssCallback;
+import android.hardware.gnss.IAGnssCallback.AGnssType;
+
+/** Extended interface for Assisted GNSS support. */
+@VintfStability
+interface IAGnss {
+    /** Access point name IP type */
+    @VintfStability
+    @Backing(type="int")
+    enum ApnIpType {
+        INVALID = 0,
+        IPV4 = 1,
+        IPV6 = 2,
+        IPV4V6 = 3,
+    }
+
+    /**
+     * Opens the AGNSS interface and provides the callback routines to the
+     * implementation of this interface.
+     *
+     * If setCallback is not called, this interface will not respond to any
+     * other method calls.
+     *
+     * @param callback Handle to the AGNSS status callback interface.
+     */
+    void setCallback(in IAGnssCallback callback);
+
+    /**
+     * Notifies that the AGNSS data connection has been closed.
+     */
+    void dataConnClosed();
+
+    /**
+     * Notifies that a data connection is not available for AGNSS.
+     */
+    void dataConnFailed();
+
+    /**
+     * Sets the hostname and port for the AGNSS server.
+     *
+     * @param type Specifies if SUPL or C2K.
+     * @param hostname Hostname of the AGNSS server.
+     * @param port Port number associated with the server.
+     */
+    void setServer(in AGnssType type, in @utf8InCpp String hostname, in int port);
+
+    /**
+     * Notifies GNSS that a data connection is available and sets the network handle,
+     * name of the APN, and its IP type to be used for SUPL connections.
+     *
+     * The HAL implementation must use the network handle to set the network for the
+     * SUPL connection sockets using the android_setsocknetwork function. This will ensure
+     * that there is a network path to the SUPL server. The network handle can also be used
+     * to get the IP address of SUPL FQDN using the android_getaddrinfofornetwork() function.
+     *
+     * @param networkHandle Handle representing the network for use with the NDK API.
+     * @param apn Access Point Name (follows regular APN naming convention).
+     * @param apnIpType Specifies IP type of APN.
+     */
+    void dataConnOpen(
+            in long networkHandle, in @utf8InCpp String apn, in ApnIpType apnIpType);
+}
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IAGnssCallback.aidl
new file mode 100644
index 0000000..7c25937
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IAGnssCallback.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss;
+
+/** Callback structure for the AGNSS interface. */
+@VintfStability
+interface IAGnssCallback {
+    /** AGNSS service type */
+    @VintfStability
+    @Backing(type="int")
+    enum AGnssType {
+        SUPL = 1,
+        C2K = 2,
+        SUPL_EIMS = 3,
+        SUPL_IMS = 4,
+    }
+
+    /** AGNSS status value */
+    @VintfStability
+    @Backing(type="int")
+    enum AGnssStatusValue {
+        /** GNSS requests data connection for AGNSS. */
+        REQUEST_AGNSS_DATA_CONN = 1,
+
+        /** GNSS releases the AGNSS data connection. */
+        RELEASE_AGNSS_DATA_CONN = 2,
+
+        /** AGNSS data connection initiated */
+        AGNSS_DATA_CONNECTED = 3,
+
+        /** AGNSS data connection completed */
+        AGNSS_DATA_CONN_DONE = 4,
+
+        /** AGNSS data connection failed */
+        AGNSS_DATA_CONN_FAILED = 5,
+    }
+
+    /**
+     * Callback with AGNSS status information.
+     *
+     * The GNSS HAL implementation must use this method to request the framework to setup
+     * network connection for the specified AGNSS service and to update the connection
+     * status so that the framework can release the resources.
+     *
+     * @param type Type of AGNSS service.
+     * @parama status Status of the data connection.
+     */
+    void agnssStatusCb(in AGnssType type, in AGnssStatusValue status);
+}
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
new file mode 100644
index 0000000..c506b04
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+package android.hardware.gnss;
+
+import android.hardware.gnss.IAGnssRilCallback;
+import android.hardware.gnss.IAGnssRilCallback.SetIDType;
+
+/**
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface
+ * Layer interface allows the GNSS chipset to request radio interface layer
+ * information from Android platform. Examples of such information are reference
+ * location, unique subscriber ID, phone number string and network availability changes.
+ */
+@VintfStability
+interface IAGnssRil {
+    /** Network capability mode bitmask for not metered. */
+    const int NETWORK_CAPABILITY_NOT_METERED = 0x01;
+
+    /** Network capability mode bitmask for not roaming. */
+    const int NETWORK_CAPABILITY_NOT_ROAMING = 0x02;
+
+    /** AGNSS reference location type */
+    @VintfStability
+    @Backing(type="int")
+    enum AGnssRefLocationType {
+        GSM_CELLID = 1,
+        UMTS_CELLID = 2,
+        LTE_CELLID = 4,
+        NR_CELLID = 8,
+    }
+
+    /** SET ID type*/
+    @VintfStability
+    @Backing(type="int")
+    enum SetIDType {
+        NONE = 0,
+        IMSI = 1,
+        MSISDM = 2,
+    }
+
+    /**
+     * CellID for 2G, 3G ,LTE and NR used in AGNSS. This is defined in
+     * UserPlane Location Protocol (Version 2.0.4).
+     */
+    @VintfStability
+    parcelable AGnssRefLocationCellID {
+        AGnssRefLocationType type;
+
+        /** Mobile Country Code. */
+        int mcc;
+
+        /** Mobile Network Code .*/
+        int mnc;
+
+        /**
+         * Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE,
+         * lac is populated with tac, to ensure that we don't break old clients that
+         * might rely on the old (wrong) behavior.
+         */
+        int lac;
+
+        /**
+         *  Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE.
+         *  Cell Global Id NR in 5G.
+         */
+        long cid;
+
+        /** Tracking Area Code in LTE and NR. */
+        int tac;
+
+        /** Physical Cell id in LTE and NR (not used in 2G and 3G) */
+        int pcid;
+
+        /** Absolute Radio Frequency Channel Number in NR. */
+        int arfcn;
+    }
+
+    /** Represents ref locations */
+    @VintfStability
+    parcelable AGnssRefLocation {
+        AGnssRefLocationType type;
+
+        AGnssRefLocationCellID cellID;
+    }
+
+    /** Represents network connection status and capabilities. */
+    @VintfStability
+    parcelable NetworkAttributes {
+        /** Network handle of the network for use with the NDK API. */
+        long networkHandle;
+
+        /**
+         * True indicates that network connectivity exists and it is possible to
+         * establish connections and pass data. If false, only the networkHandle field
+         * is populated to indicate that this network has just disconnected.
+         */
+        boolean isConnected;
+
+        /**
+         * A bitfield of flags indicating the capabilities of this network. The bit masks are
+         * defined in NETWORK_CAPABILITY_*.
+         */
+        int capabilities;
+
+        /**
+         * Telephony preferred Access Point Name to use for carrier data connection when
+         * connected to a cellular network. Empty string, otherwise.
+         */
+        @utf8InCpp String apn;
+    }
+
+    /**
+     * Opens the AGNSS interface and provides the callback routines
+     * to the implementation of this interface.
+     *
+     * @param callback Interface for AGnssRil callbacks.
+     *
+     */
+    void setCallback(in IAGnssRilCallback callback);
+
+    /**
+     * Sets the reference location.
+     *
+     * @param agnssReflocation AGNSS reference location CellID.
+     *
+     */
+    void setRefLocation(in AGnssRefLocation agnssReflocation);
+
+    /**
+     * Sets the SET ID.
+     *
+     * @param type Must be populated with either IMSI or MSISDN or NONE.
+     * @param setid If type is IMSI then setid is populated with
+     * a string representing the unique Subscriber ID, for example, the IMSI for
+     * a GMS phone. If type is MSISDN, then setid must contain
+     * the phone number string for line 1. For example, the MSISDN for a GSM phone.
+     * If the type is NONE, then the string must be empty.
+     *
+     */
+    void setSetId(in SetIDType type, in @utf8InCpp String setid);
+
+    /**
+     * Notifies GNSS of network status changes.
+     *
+     * The framework calls this method to update the GNSS HAL implementation of network
+     * state changes.
+     *
+     * @param attributes Updated network attributes.
+     *
+     */
+    void updateNetworkState(in NetworkAttributes attributes);
+}
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl b/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl
new file mode 100644
index 0000000..6fb093e
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package android.hardware.gnss;
+
+/**
+ * Callback for IAGnssRil interface. Used to request SET ID and
+ * Reference Location.
+ */
+@VintfStability
+interface IAGnssRilCallback {
+    /**
+     * The Hal uses this API to request a SET ID.
+     *
+     * @param setIdflag A bitfield of IAGnssRil.SetIDType that is required by
+     * the HAL. The framework will inject an empty SET ID if the flag is NONE.
+     *
+     */
+    void requestSetIdCb(in int setIdflag);
+
+    /**
+     * The Hal uses this API to request a reference location.
+     */
+    void requestRefLocCb();
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index 42cc496..99f2ee4 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -16,14 +16,21 @@
 
 package android.hardware.gnss;
 
+import android.hardware.gnss.GnssLocation;
+import android.hardware.gnss.IAGnss;
+import android.hardware.gnss.IAGnssRil;
+import android.hardware.gnss.IGnssAntennaInfo;
 import android.hardware.gnss.IGnssBatching;
 import android.hardware.gnss.IGnssCallback;
 import android.hardware.gnss.IGnssConfiguration;
+import android.hardware.gnss.IGnssDebug;
 import android.hardware.gnss.IGnssGeofence;
 import android.hardware.gnss.IGnssMeasurementInterface;
 import android.hardware.gnss.IGnssNavigationMessageInterface;
 import android.hardware.gnss.IGnssPowerIndication;
 import android.hardware.gnss.IGnssPsds;
+import android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsInterface;
+import android.hardware.gnss.visibility_control.IGnssVisibilityControl;
 
 /**
  * Represents the standard GNSS (Global Navigation Satellite System) interface.
@@ -42,6 +49,53 @@
     /** Any other error. */
     const int ERROR_GENERIC = 3;
 
+    /** Requested operational mode for GNSS operation. */
+    @VintfStability
+    @Backing(type="int")
+    enum GnssPositionMode {
+        /** Mode for running GNSS standalone (no assistance). */
+        STANDALONE = 0,
+        /** AGNSS MS-Based mode. */
+        MS_BASED = 1,
+        /**
+         * AGNSS MS-Assisted mode. This mode is not maintained by the platform anymore.
+         * It is strongly recommended to use MS_BASED instead.
+         */
+        MS_ASSISTED = 2,
+    }
+
+    /** Requested recurrence mode for GNSS operation. */
+    @VintfStability
+    @Backing(type="int")
+    enum GnssPositionRecurrence {
+        /** Receive GNSS fixes on a recurring basis at a specified period. */
+        RECURRENCE_PERIODIC = 0,
+        /** Request a single shot GNSS fix. */
+        RECURRENCE_SINGLE = 1,
+    }
+
+    /**
+     * Flags used to specify which aiding data to delete when calling
+     * deleteAidingData().
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum GnssAidingData {
+        DELETE_EPHEMERIS = 0x0001,
+        DELETE_ALMANAC = 0x0002,
+        DELETE_POSITION = 0x0004,
+        DELETE_TIME = 0x0008,
+        DELETE_IONO = 0x0010,
+        DELETE_UTC = 0x0020,
+        DELETE_HEALTH = 0x0040,
+        DELETE_SVDIR = 0x0080,
+        DELETE_SVSTEER = 0x0100,
+        DELETE_SADATA = 0x0200,
+        DELETE_RTI = 0x0400,
+        DELETE_CELLDB_INFO = 0x8000,
+        DELETE_ALL = 0xFFFF
+    }
+
     /**
      * Opens the interface and provides the callback routines to the implementation of this
      * interface.
@@ -75,7 +129,7 @@
     /**
      * This method returns the IGnssPsds interface.
      *
-     * @return Handle to the IGnssPsds interface.
+     * @return The IGnssPsds interface.
      */
     @nullable IGnssPsds getExtensionPsds();
 
@@ -84,7 +138,7 @@
      *
      * This method must return non-null.
      *
-     * @return Handle to the IGnssConfiguration interface.
+     * @return The IGnssConfiguration interface.
      */
     IGnssConfiguration getExtensionGnssConfiguration();
 
@@ -93,7 +147,7 @@
      *
      * This method must return non-null.
      *
-     * @return Handle to the IGnssMeasurementInterface interface.
+     * @return The IGnssMeasurementInterface interface.
      */
     IGnssMeasurementInterface getExtensionGnssMeasurement();
 
@@ -102,28 +156,149 @@
      *
      * This method must return non-null.
      *
-     * @return Handle to the IGnssPowerIndication interface.
+     * @return The IGnssPowerIndication interface.
      */
     IGnssPowerIndication getExtensionGnssPowerIndication();
 
     /**
      * This method returns the IGnssBatching interface.
      *
-     * @return Handle to the IGnssBatching interface.
+     * @return The IGnssBatching interface.
      */
     @nullable IGnssBatching getExtensionGnssBatching();
 
     /**
      * This method returns the IGnssGeofence interface.
      *
-     * @return Handle to the IGnssGeofence interface.
+     * @return The IGnssGeofence interface.
      */
     @nullable IGnssGeofence getExtensionGnssGeofence();
 
     /**
      * This method returns the IGnssNavigationMessageInterface.
      *
-     * @return Handle to the IGnssNavigationMessageInterface.
+     * @return The IGnssNavigationMessageInterface.
      */
     @nullable IGnssNavigationMessageInterface getExtensionGnssNavigationMessage();
+
+    /**
+     * This method returns the IAGnss interface.
+     *
+     * @return The IAGnss interface.
+     */
+    IAGnss getExtensionAGnss();
+
+    /**
+     * This method returns the IAGnssRil interface.
+     *
+     * @return The IAGnssRil interface.
+     */
+    IAGnssRil getExtensionAGnssRil();
+
+    /**
+     * This method returns the IGnssDebug interface.
+     *
+     * This method must return non-null.
+     *
+     * @return Handle to the IGnssDebug interface.
+     */
+    IGnssDebug getExtensionGnssDebug();
+
+    /**
+     * This method returns the IGnssVisibilityControl.
+     *
+     * @return Handle to the IGnssVisibilityControl.
+     */
+    IGnssVisibilityControl getExtensionGnssVisibilityControl();
+
+    /**
+     * Starts a location output stream using the IGnssCallback gnssLocationCb(), following the
+     * settings from the most recent call to setPositionMode().
+     *
+     * This output must operate independently of any GNSS location batching operations,
+     * see the IGnssBatching for details.
+     */
+    void start();
+
+    /**
+     * Stops the location output stream.
+     */
+    void stop();
+
+    /**
+     * Injects the current time.
+     *
+     * @param timeMs This is the UTC time received from the NTP server, its value is given in
+     *     milliseconds since January 1, 1970.
+     * @param timeReferenceMs The corresponding value of SystemClock.elapsedRealtime() from the
+     *     device when the NTP response was received in milliseconds.
+     * @param uncertaintyMs Uncertainty associated with the value represented by time. Represented
+     *     in milliseconds.
+     */
+    void injectTime(in long timeMs, in long timeReferenceMs, in int uncertaintyMs);
+
+    /**
+     * Injects current location from another (typically network) location provider.
+     *
+     * @param location Current location from the location provider
+     */
+    void injectLocation(in GnssLocation location);
+
+    /**
+     * Injects current location from the best available location provider.
+     *
+     * Unlike injectLocation, this method may inject a recent GNSS location from the HAL
+     * implementation, if that is the best available location known to the framework.
+     *
+     * @param location Location information from the best available location provider.
+     */
+    void injectBestLocation(in GnssLocation location);
+
+    /**
+     * Specifies that the next call to start will not use the information defined in the flags.
+     * GnssAidingData value of DELETE_ALL is passed for a cold start.
+     *
+     * @param aidingDataFlags Flags specifying the aiding data to be deleted.
+     */
+    void deleteAidingData(in GnssAidingData aidingDataFlags);
+
+    /**
+     * Sets the GnssPositionMode parameter, its associated recurrence value, the time between fixes,
+     * requested fix accuracy, time to first fix.
+     *
+     * @param mode Parameter must be one of MS_BASED or STANDALONE. It is allowed by the platform
+     *     (and it is recommended) to fallback to MS_BASED if MS_ASSISTED is passed in, and MS_BASED
+     *     is supported.
+     * @param recurrence GNSS position recurrence value, either periodic or single.
+     * @param minIntervalMs Represents the time between fixes in milliseconds.
+     * @param preferredAccuracyMeters Represents the requested fix accuracy in meters.
+     * @param preferredTimeMs Represents the requested time to first fix in milliseconds.
+     * @param lowPowerMode When true, and IGnss is the only client to the GNSS hardware, the GNSS
+     *     hardware must make strong tradeoffs to substantially restrict power use. Specifically, in
+     *     the case of a several second long minIntervalMs, the GNSS hardware must not, on average,
+     *     run power hungry operations like RF and signal searches for more than one second per
+     *     interval, and must make exactly one call to gnssSvStatusCb(), and either zero or one call
+     *     to GnssLocationCb() at each interval. When false, HAL must operate in the nominal mode
+     *     and is expected to make power and performance tradoffs such as duty-cycling when signal
+     *     conditions are good and more active searches to reacquire GNSS signals when no signals
+     *     are present. When there are additional clients using the GNSS hardware other than IGnss,
+     *     the GNSS hardware may operate in a higher power mode, on behalf of those clients.
+     */
+    void setPositionMode(in GnssPositionMode mode, in GnssPositionRecurrence recurrence,
+            in int minIntervalMs, in int preferredAccuracyMeters, in int preferredTimeMs,
+            in boolean lowPowerMode);
+
+    /*
+     * This method returns the IGnssAntennaInfo.
+     *
+     * @return Handle to the IGnssAntennaInfo.
+     */
+    IGnssAntennaInfo getExtensionGnssAntennaInfo();
+
+    /**
+     * This method returns the IMeasurementCorrectionsInterface.
+     *
+     * @return Handle to the IMeasurementCorrectionsInterface.
+     */
+    @nullable IMeasurementCorrectionsInterface getExtensionMeasurementCorrections();
 }
diff --git a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl
new file mode 100644
index 0000000..de83b67
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss;
+
+import android.hardware.gnss.IGnssAntennaInfoCallback;
+
+/**
+ * Extended interface for GNSS antenna information support.
+ */
+@VintfStability
+interface IGnssAntennaInfo {
+    /**
+     * Registers the callback routines with the HAL.
+     *
+     * @param callback Handle to the GnssAntennaInfo callback interface.
+     */
+    void setCallback(in IGnssAntennaInfoCallback callback);
+
+    /**
+     * Stops updates from the HAL, and unregisters the callback routines.
+     * After a call to close(), the previously registered callbacks must be
+     * considered invalid by the HAL.
+     * If close() is invoked without a previous setCallback, this function must perform
+     * no work.
+     */
+    void close();
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
new file mode 100644
index 0000000..ef0a7fc
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss;
+
+/**
+ * The callback interface to report GNSS antenna information from the HAL.
+ */
+@VintfStability
+interface IGnssAntennaInfoCallback {
+    /**
+     * A row of doubles. This is used to represent a row in a 2D array, which are used to
+     * characterize the phase center variation corrections and signal gain corrections.
+     */
+    @VintfStability
+    parcelable Row {
+        double[] row;
+    }
+
+    /**
+     * A point in 3D space, with associated uncertainty.
+     */
+    @VintfStability
+    parcelable Coord {
+        double x;
+
+        double xUncertainty;
+
+        double y;
+
+        double yUncertainty;
+
+        double z;
+
+        double zUncertainty;
+    }
+
+    @VintfStability
+    parcelable GnssAntennaInfo {
+        /**
+         * The carrier frequency in Hz.
+         */
+        long carrierFrequencyHz;
+
+        /**
+         * Phase center offset (PCO) with associated 1-sigma uncertainty. PCO is defined with
+         * respect to the origin of the Android sensor coordinate system, e.g., center of primary
+         * screen for mobiles - see sensor or form factor documents for details.
+         */
+        Coord phaseCenterOffsetCoordinateMillimeters;
+
+        /**
+         * 2D vectors representing the phase center variation (PCV) corrections, in
+         * millimeters, at regularly spaced azimuthal angle (theta) and zenith angle
+         * (phi). The PCV correction is added to the phase measurement to obtain the
+         * corrected value.
+         *
+         * The azimuthal angle, theta, is defined with respect to the X axis of the
+         * Android sensor coordinate system, increasing toward the Y axis. The zenith
+         * angle, phi, is defined with respect to the Z axis of the Android Sensor
+         * coordinate system, increasing toward the X-Y plane.
+         *
+         * Each row vector (outer vectors) represents a fixed theta. The first row
+         * corresponds to a theta angle of 0 degrees. The last row corresponds to a
+         * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+         * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+         *
+         * The columns (inner vectors) represent fixed zenith angles, beginning at 0
+         * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+         * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        Row[] phaseCenterVariationCorrectionMillimeters;
+
+        /**
+         * 2D vectors of 1-sigma uncertainty in millimeters associated with the PCV
+         * correction values.
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        Row[] phaseCenterVariationCorrectionUncertaintyMillimeters;
+
+        /**
+         * 2D vectors representing the signal gain corrections at regularly spaced
+         * azimuthal angle (theta) and zenith angle (phi). The values are calculated or
+         * measured at the antenna feed point without considering the radio and receiver
+         * noise figure and path loss contribution, in dBi, i.e., decibel over isotropic
+         * antenna with the same total power. The signal gain correction is added the
+         * signal gain measurement to obtain the corrected value.
+         *
+         * The azimuthal angle, theta, is defined with respect to the X axis of the
+         * Android sensor coordinate system, increasing toward the Y axis. The zenith
+         * angle, phi, is defined with respect to the Z axis of the Android Sensor
+         * coordinate system, increasing toward the X-Y plane.
+         *
+         * Each row vector (outer vectors) represents a fixed theta. The first row
+         * corresponds to a theta angle of 0 degrees. The last row corresponds to a
+         * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+         * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+         *
+         * The columns (inner vectors) represent fixed zenith angles, beginning at 0
+         * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+         * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        Row[] signalGainCorrectionDbi;
+
+        /**
+         * 2D vectors of 1-sigma uncertainty in dBi associated with the signal
+         * gain correction values.
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        Row[] signalGainCorrectionUncertaintyDbi;
+    }
+
+    /**
+     * Called when on connection, and on known-change to these values, such as upon a known
+     * GNSS RF antenna tuning change, or a foldable device state change.
+     *
+     * This is optional. It can never be called if the GNSS antenna information is not
+     * available.
+     */
+    void gnssAntennaInfoCb(in GnssAntennaInfo[] gnssAntennaInfos);
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl b/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
index 0d48ee1..0d03a0f 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
@@ -46,6 +46,25 @@
      */
     const int WAKEUP_ON_FIFO_FULL = 0x01;
 
+    /** Options specifying the batching request. */
+    @VintfStability
+    parcelable Options {
+        /** Time interval between samples in the location batch, in nanoseconds. */
+        long periodNanos;
+
+        /**
+         * The minimum distance in meters that the batching engine should
+         * accumulate before trying another GPS fix when in a challenging GPS environment.
+         *
+         * This is an optional field. If it is set as 0, the chipset can operate in an automatic
+         * mode.
+         */
+        float minDistanceMeters;
+
+        /** A bit field of Flags (WAKEUP_ON_FIFO_FULL) indicating the batching behavior. */
+        int flags;
+    }
+
     /**
      * Open the interface and provides the callback routines to the implementation of this
      * interface.
@@ -83,10 +102,9 @@
      * for using flushBatchedLocation to explicitly ask for the location as needed, to avoid it
      * being dropped.
      *
-     * @param periodNanos  Time interval between samples in the location batch, in nanoseconds
-     * @param flags  A bitfield of flags (WAKEUP_ON_FIFO_FULL) indicating the batching behavior
+     * @param options  Options specifying the batching request.
      */
-    void start(in long periodNanos, in int flags);
+    void start(in Options options);
 
     /**
      * Retrieve all batched locations currently stored.
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
index aad09ef..a74d097 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.gnss;
 
+import android.hardware.gnss.GnssConstellationType;
+import android.hardware.gnss.GnssLocation;
 import android.hardware.gnss.IGnssConfiguration;
 import android.hardware.gnss.IGnssPsds;
 
@@ -26,9 +28,48 @@
  */
 @VintfStability
 interface IGnssCallback {
+    /**
+     * Capability bit mask indicating that GNSS supports scheduling fixes for RECURRENCE_PERIODIC
+     * mode.
+     *
+     * If this is not set, then the framework will use 1000ms for minInterval and will call start()
+     * and stop() to schedule the GNSS.
+     */
+    const int CAPABILITY_SCHEDULING = 1 << 0;
+
+    /** Capability bit mask indicating that GNSS supports MS-Based AGNSS mode */
+    const int CAPABILITY_MSB = 1 << 1;
+
+    /** Capability bit mask indicating that GNSS supports MS-Assisted AGNSS mode */
+    const int CAPABILITY_MSA = 1 << 2;
+
+    /** Capability bit mask indicating that GNSS supports single-shot fixes */
+    const int CAPABILITY_SINGLE_SHOT = 1 << 3;
+
+    /** Capability bit mask indicating that GNSS supports on demand time injection */
+    const int CAPABILITY_ON_DEMAND_TIME = 1 << 4;
+
+    /** Capability bit mask indicating that GNSS supports Geofencing  */
+    const int CAPABILITY_GEOFENCING = 1 << 5;
+
+    /** Capability bit mask indicating that GNSS supports Measurements. */
+    const int CAPABILITY_MEASUREMENTS = 1 << 6;
+
+    /** Capability bit mask indicating that GNSS supports Navigation Messages */
+    const int CAPABILITY_NAV_MESSAGES = 1 << 7;
+
+    /** Capability bit mask indicating that GNSS supports low power mode */
+    const int CAPABILITY_LOW_POWER_MODE = 1 << 8;
+
     /** Capability bit mask indicating that GNSS supports blocklisting satellites */
     const int CAPABILITY_SATELLITE_BLOCKLIST = 1 << 9;
 
+    /** Capability bit mask indicating that GNSS supports measurement corrections */
+    const int CAPABILITY_MEASUREMENT_CORRECTIONS = 1 << 10;
+
+    /** Capability bit mask indicating that GNSS supports antenna info */
+    const int CAPABILITY_ANTENNA_INFO = 1 << 11;
+
     /** Capability bit mask indicating that GNSS supports correlation vector */
     const int CAPABILITY_CORRELATION_VECTOR = 1 << 12;
 
@@ -44,4 +85,221 @@
      * @param capabilities Capability parameter is a bit field of the Capability bit masks.
      */
     void gnssSetCapabilitiesCb(in int capabilities);
+
+    /** GNSS status event values. */
+    @VintfStability
+    @Backing(type="int")
+    enum GnssStatusValue {
+        /** GNSS status unknown. */
+        NONE = 0,
+        /** GNSS has begun navigating. */
+        SESSION_BEGIN = 1,
+        /** GNSS has stopped navigating. */
+        SESSION_END = 2,
+        /** GNSS has powered on but is not navigating. */
+        ENGINE_ON = 3,
+        /** GNSS is powered off. */
+        ENGINE_OFF = 4
+    }
+
+    /**
+     * Flags that indicate information about the satellite
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum GnssSvFlags {
+        NONE = 0,
+        HAS_EPHEMERIS_DATA = 1 << 0,
+        HAS_ALMANAC_DATA = 1 << 1,
+        USED_IN_FIX = 1 << 2,
+        HAS_CARRIER_FREQUENCY = 1 << 3,
+    }
+
+    @VintfStability
+    parcelable GnssSvInfo {
+        /**
+         * Pseudo-random or satellite ID number for the satellite, a.k.a. Space Vehicle (SV), or
+         * FCN/OSN number for Glonass. The distinction is made by looking at constellation field.
+         * Values must be in the range of:
+         *
+         * - GNSS:    1-32
+         * - SBAS:    120-151, 183-192
+         * - GLONASS: 1-24, the orbital slot number (OSN), if known.  Or, if not:
+         *            93-106, the frequency channel number (FCN) (-7 to +6) offset by
+         *            + 100
+         *            i.e. report an FCN of -7 as 93, FCN of 0 as 100, and FCN of +6
+         *            as 106.
+         * - QZSS:    193-200
+         * - Galileo: 1-36
+         * - Beidou:  1-37
+         * - IRNSS:   1-14
+         */
+        int svid;
+
+        /**
+         * Defines the constellation of the given SV.
+         */
+        GnssConstellationType constellation;
+
+        /**
+         * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+         * It contains the measured C/N0 value for the signal at the antenna port.
+         *
+         * This is a mandatory field.
+         */
+        float cN0Dbhz;
+
+        /**
+         * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains
+         * the measured C/N0 value for the signal measured at the baseband.
+         *
+         * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port,
+         * which is reported in cN0DbHz.
+         *
+         * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only
+         * processes one of the components, then the reported basebandCN0DbHz reflects only the
+         * component that is processed.
+         *
+         * This field is mandatory. Like cN0DbHz, it may be reported as 0 for satellites being
+         * reported that may be searched for, but not yet tracked.
+         */
+        float basebandCN0DbHz;
+
+        /** Elevation of SV in degrees. */
+        float elevationDegrees;
+
+        /** Azimuth of SV in degrees. */
+        float azimuthDegrees;
+
+        /**
+         * Carrier frequency of the signal tracked, for example it can be the
+         * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 =
+         * 1176.45 MHz, varying GLO channels, etc. If the field is zero, it is
+         * the primary common use central frequency, e.g. L1 = 1575.45 MHz for
+         * GPS.
+         *
+         * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
+         * time, two GnssSvInfo structs must be reported for this same
+         * satellite, in one of the structs, all the values related
+         * to L1 must be filled, and in the other all of the values related to
+         * L5 must be filled.
+         *
+         * If the data is available, svFlag must contain HAS_CARRIER_FREQUENCY.
+         */
+        long carrierFrequencyHz;
+
+        /** A bit field of the GnssSvFlags. */
+        int svFlag;
+    }
+
+    /**
+     * Called to communicate the status of the GNSS engine.
+     *
+     * @param status Status information from HAL.
+     */
+    void gnssStatusCb(in GnssStatusValue status);
+
+    /**
+     * Callback for the HAL to pass a vector of GnssSvInfo back to the client.
+     *
+     * @param svInfo SV status information from HAL.
+     */
+    void gnssSvStatusCb(in GnssSvInfo[] svInfoList);
+
+    /**
+     * Called when a GNSS location is available.
+     *
+     * @param location Location information from HAL.
+     */
+    void gnssLocationCb(in GnssLocation location);
+
+    /**
+     * Callback for reporting NMEA sentences. Called when NMEA data is available.
+     *
+     * @param timestamp Marks the instance of reporting.
+     * @param nmea Follows standard NMEA 0183. Each sentence begins with a '$'
+     * and ends with a carriage return/line feed sequence and can be no longer
+     * than 80 characters of visible text (plus the line terminators). The data
+     * is contained within this single line with data items separated by commas.
+     * The data itself is just ascii text and may extend over multiple sentences
+     * in certain specialized instances but is normally fully contained in one
+     * variable length sentence. The data may vary in the amount of precision
+     * contained in the message. For example time might be indicated to decimal
+     * parts of a second or location may be shown with 3 or even 4 digits after
+     * the decimal point. Programs that read the data must only use the commas
+     * to determine the field boundaries and not depend on column positions.
+     * There is a provision for a checksum at the end of each sentence which may
+     * or may not be checked by the unit that reads the data. The checksum field
+     * consists of a '*' and two hex digits representing an 8 bit exclusive OR
+     * of all characters between, but not including, the '$' and '*'.
+     */
+    void gnssNmeaCb(in long timestamp, in @utf8InCpp String nmea);
+
+    /**
+     * Callback utility for acquiring the GNSS wakelock. This can be used to prevent
+     * the CPU from suspending while handling GNSS events.
+     */
+    void gnssAcquireWakelockCb();
+
+    /** Callback utility for releasing the GNSS wakelock. */
+    void gnssReleaseWakelockCb();
+
+    /**
+     * Provides information about how new the underlying GPS/GNSS hardware and software is.
+     */
+    @VintfStability
+    parcelable GnssSystemInfo {
+        /**
+         * The year in which the last update was made to the underlying hardware/firmware used to
+         * capture GNSS signals, e.g. 2016.
+         */
+        int yearOfHw;
+
+        /**
+         * The name of the GNSS HAL implementation model and version name.
+         *
+         * This is a user-visible string that identifies the model and version of the GNSS HAL.
+         * For example "ABC Co., Baseband Part 1234, RF Part 567, Software version 3.14.159"
+         *
+         * For privacy reasons, this string must not contain any device-specific serial number or
+         * other identifier that uniquely identifies an individual device.
+         */
+        @utf8InCpp String name;
+    }
+
+    /**
+     * Callback to inform the framework of the GNSS system information.
+     *
+     * This must be called in response to IGnss::setCallback
+     *
+     * @param info GnssSystemInfo about the GPS/GNSS hardware.
+     */
+    void gnssSetSystemInfoCb(in GnssSystemInfo info);
+
+    /** Callback for requesting NTP time */
+    void gnssRequestTimeCb();
+
+    /**
+     * Callback for requesting Location.
+     *
+     * HAL implementation must call this when it wants the framework to provide locations to assist
+     * with GNSS HAL operation, for example, to assist with time to first fix, error recovery, or to
+     * supplement GNSS location for other clients of the GNSS HAL.
+     *
+     * If a request is made with independentFromGnss set to true, the framework must avoid
+     * providing locations derived from GNSS locations (such as "fused" location), to help improve
+     * information independence for situations such as error recovery.
+     *
+     * In response to this method call, GNSS HAL can expect zero, one, or more calls to
+     * IGnss::injectLocation or IGnss::injectBestLocation, dependent on availability of location
+     * from other sources, which may happen at some arbitrary delay. Generally speaking, HAL
+     * implementations must be able to handle calls to IGnss::injectLocation or
+     * IGnss::injectBestLocation at any time.
+     *
+     * @param independentFromGnss True if requesting a location that is independent from GNSS.
+     * @param isUserEmergency True if the location request is for delivery of this location to an
+     *        emergency services endpoint, during a user-initiated emergency session (e.g.
+     *        during-call to E911, or up to 5 minutes after end-of-call or text to E911).
+     */
+    void gnssRequestLocationCb(in boolean independentFromGnss, in boolean isUserEmergency);
 }
diff --git a/gnss/aidl/android/hardware/gnss/IGnssDebug.aidl b/gnss/aidl/android/hardware/gnss/IGnssDebug.aidl
new file mode 100644
index 0000000..475a4a3
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssDebug.aidl
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss;
+
+import android.hardware.gnss.GnssConstellationType;
+
+/**
+ * Extended interface for GNSS Debug support
+ *
+ * This information is used for debugging purpose, e.g., shown in a bugreport to
+ * describe the chipset states including time, position, and satellite data.
+ */
+@VintfStability
+interface IGnssDebug {
+    /** Satellite's ephemeris type */
+    @VintfStability
+    @Backing(type="int")
+    enum SatelliteEphemerisType {
+        EPHEMERIS = 0,
+        ALMANAC_ONLY = 1,
+        NOT_AVAILABLE = 2,
+    }
+
+    /** Satellite's ephemeris source */
+    @VintfStability
+    @Backing(type="int")
+    enum SatelliteEphemerisSource {
+        DEMODULATED = 0,
+        SUPL_PROVIDED = 1,
+        OTHER_SERVER_PROVIDED = 2,
+        OTHER = 3,
+    }
+
+    /** Satellite's ephemeris health */
+    @VintfStability
+    @Backing(type="int")
+    enum SatelliteEphemerisHealth {
+        GOOD = 0,
+        BAD = 1,
+        UNKNOWN = 2,
+    }
+
+    /**
+     * Provides the current best known UTC time estimate.
+     * If no fresh information is available, e.g. after a delete all,
+     * then whatever the effective defaults are on the device must be
+     * provided (e.g. Jan. 1, 2017, with an uncertainty of 5 years) expressed
+     * in the specified units.
+     */
+    @VintfStability
+    parcelable TimeDebug {
+        /** UTC time estimate in milliseconds. */
+        long timeEstimateMs;
+
+        /** 68% time error estimate in nanoseconds. */
+        float timeUncertaintyNs;
+
+        /**
+         * 68% error estimate in local clock drift,
+         * in nanoseconds per second (also known as parts per billion - ppb.)
+         */
+        float frequencyUncertaintyNsPerSec;
+    }
+
+    @VintfStability
+    parcelable PositionDebug {
+        /**
+         * Validity of the data in this struct. False only if no
+         * latitude/longitude information is known.
+         */
+        boolean valid;
+
+        /** Latitude expressed in degrees */
+        double latitudeDegrees;
+
+        /** Longitude expressed in degrees */
+        double longitudeDegrees;
+
+        /** Altitude above ellipsoid expressed in meters */
+        float altitudeMeters;
+
+        /** Represents horizontal speed in meters per second. */
+        float speedMetersPerSec;
+
+        /** Represents heading in degrees. */
+        float bearingDegrees;
+
+        /**
+         * Estimated horizontal accuracy of position expressed in meters,
+         * radial, 68% confidence.
+         */
+        double horizontalAccuracyMeters;
+
+        /**
+         * Estimated vertical accuracy of position expressed in meters, with
+         * 68% confidence.
+         */
+        double verticalAccuracyMeters;
+
+        /**
+         * Estimated speed accuracy in meters per second with 68% confidence.
+         */
+        double speedAccuracyMetersPerSecond;
+
+        /**
+         * Estimated bearing accuracy degrees with 68% confidence.
+         */
+        double bearingAccuracyDegrees;
+
+        /**
+         * Time duration before this report that this position information was
+         * valid.  This can, for example, be a previous injected location with
+         * an age potentially thousands of seconds old, or
+         * extrapolated to the current time (with appropriately increased
+         * accuracy estimates), with a (near) zero age.
+         */
+        float ageSeconds;
+    }
+
+    @VintfStability
+    parcelable SatelliteData {
+        /** Satellite vehicle ID number */
+        int svid;
+
+        /** Defines the constellation type of the given SV. */
+        GnssConstellationType constellation;
+
+        /**
+         * Defines the standard broadcast ephemeris or almanac availability for
+         * the satellite.  To report status of predicted orbit and clock
+         * information, see the serverPrediction fields below.
+         */
+        SatelliteEphemerisType ephemerisType;
+
+        /** Defines the ephemeris source of the satellite. */
+        SatelliteEphemerisSource ephemerisSource;
+
+        /**
+         * Defines whether the satellite is known healthy
+         * (safe for use in location calculation.)
+         */
+        SatelliteEphemerisHealth ephemerisHealth;
+
+        /**
+         * Time duration from this report (current time), minus the
+         * effective time of the ephemeris source (e.g. TOE, TOA.)
+         * Set to 0 when ephemerisType is NOT_AVAILABLE.
+         */
+        float ephemerisAgeSeconds;
+
+        /**
+         * True if a server has provided a predicted orbit and clock model for
+         * this satellite.
+         */
+        boolean serverPredictionIsAvailable;
+
+        /**
+         * Time duration from this report (current time) minus the time of the
+         * start of the server predicted information.  For example, a 1 day
+         * old prediction would be reported as 86400 seconds here.
+         */
+        float serverPredictionAgeSeconds;
+    }
+
+    /**
+     * Provides a set of debug information that is filled by the GNSS chipset
+     * when the method getDebugData() is invoked.
+     */
+    @VintfStability
+    parcelable DebugData {
+        /** Current best known position. */
+        PositionDebug position;
+
+        /** Current best know time estimate */
+        TimeDebug time;
+
+        /**
+         * Provides a list of the available satellite data, for all
+         * satellites and constellations the device can track,
+         * including GnssConstellationType UNKNOWN.
+         */
+        List<SatelliteData> satelliteDataArray;
+    }
+
+    /**
+     * This methods requests position, time and satellite ephemeris debug information
+     * from the HAL.
+     *
+     * @return ret debugData information from GNSS Hal that contains the current best
+     * known position, best known time estimate and a complete list of
+     * constellations that the device can track.
+     */
+    DebugData getDebugData();
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 08c83a4..102cdcd 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -24,6 +24,48 @@
 @VintfStability
 interface IGnssMeasurementInterface {
     /**
+     * Options specifying the GnssMeasurement request.
+     */
+    @VintfStability
+    parcelable Options {
+        /**
+         * Enable full tracking mode.
+         *
+         * If true, GNSS chipset must switch off duty cycling. In such mode no clock discontinuities
+         * are expected and, when supported, carrier phase should be continuous in good signal
+         * conditions. All non-blocklisted, healthy constellations, satellites and frequency bands
+         * that the chipset supports must be reported in this mode. The GNSS chipset is allowed to
+         * consume more power in this mode. If false, API must optimize power via duty cycling,
+         * constellations and frequency limits, etc.
+         */
+        boolean enableFullTracking;
+
+        /**
+         * Enable Correlation Vector outputs.
+         *
+         * If true, enable correlation vectors as part of the raw GNSS measurements outputs. If
+         * false, disable correlation vectors.
+         */
+        boolean enableCorrVecOutputs;
+
+        /**
+         * Time interval between the reported measurements in milliseconds.
+         *
+         * The GNSS chipset must not report measurements with a rate slower than requested. All the
+         * available measurements must be reported to the framework.
+         *
+         * For cases where concurrently serving the location and the measurement requests would not
+         * consume more power than only the measurement request, the faster rate of the 2 requests
+         * must be chosen. Otherwise, it is recommended that the GNSS chipset minimizes the power
+         * consumption with appropriate location and measurement intervals to satisfy both requests.
+         * For example, for 2-sec measurement interval request and 7-sec location interval request,
+         * the GNSS chipset is recommended to run the measurement engine with 2-sec interval and the
+         * location engine with 6-sec interval.
+         */
+        int intervalMs;
+    }
+
+    /**
      * Initializes the interface and registers the callback routines with the HAL. After a
      * successful call to 'setCallback' the HAL must begin to provide updates at an average
      * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
@@ -39,13 +81,9 @@
      *
      * @param enableCorrVecOutputs If true, enable correlation vectors as part of the raw GNSS
      *     measurements outputs. If false, disable correlation vectors.
-     *
-     * Returns ok() if successful. Returns ERROR_ALREADY_INIT if a callback has already been
-     * registered without a corresponding call to 'close'. Returns ERROR_GENERIC for any other
-     * error. The HAL must not generate any other updates upon returning this error code.
      */
     void setCallback(in IGnssMeasurementCallback callback, in boolean enableFullTracking,
-                     in boolean enableCorrVecOutputs);
+            in boolean enableCorrVecOutputs);
 
     /**
      * Stops updates from the HAL, and unregisters the callback routines. After a call to close(),
@@ -55,4 +93,11 @@
      * no work.
      */
     void close();
-}
\ No newline at end of file
+
+    /**
+     * Initializes the interface and registers the callback routines with the HAL.
+     *
+     * @param options See Options definition.
+     */
+    void setCallbackWithOptions(in IGnssMeasurementCallback callback, in Options options);
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
new file mode 100644
index 0000000..d695e70
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.measurement_corrections;
+
+/**
+ * GNSS measurement corrections callback interface.
+ */
+@VintfStability
+interface IMeasurementCorrectionsCallback {
+    /**
+     * Flags to indicate supported measurement corrections capabilities
+     *
+     * Either the LOS_SATS or the EXCESS_PATH_LENGTH capability must be supported.
+     */
+    /**
+     * Capability bit flag indicating that GNSS supports line-of-sight satellite identification
+     * measurement corrections
+     */
+    const int CAPABILITY_LOS_SATS = 1 << 0;
+    /**
+     * Capability bit flag indicating that GNSS supports per satellite excess-path-length
+     * measurement corrections
+     */
+    const int CAPABILITY_EXCESS_PATH_LENGTH = 1 << 1;
+    /**
+     * Capability bit flag indicating that GNSS supports reflecting planes measurement
+     * corrections
+     */
+    const int CAPABILITY_REFLECTING_PLANE = 1 << 2;
+
+    /**
+     * Callback to inform framework the measurement correction specific capabilities of the GNSS
+     * HAL implementation.
+     *
+     * The GNSS HAL must call this method immediately after the framework opens the measurement
+     * corrections interface.
+     *
+     * @param capabilities A bit field of flags indicating the capabilities of measurement
+     *         corrections.
+     *        It is mandatory to support either LOS_STATS or EXCESS_PATH_LENGTH capability.
+     */
+    void setCapabilitiesCb(in int capabilities);
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
new file mode 100644
index 0000000..eeabc6d
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.measurement_corrections;
+
+import android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsCallback;
+import android.hardware.gnss.measurement_corrections.MeasurementCorrections;
+
+/**
+ * Interface for measurement corrections support.
+ */
+@VintfStability
+interface IMeasurementCorrectionsInterface {
+    /**
+     * Injects measurement corrections to be used by the HAL to improve the GNSS location output.
+     *
+     * These are NOT to be used to adjust the IGnssMeasurementCallback output values -
+     * those remain raw, uncorrected measurements.
+     *
+     * In general, these are injected when conditions defined by the platform are met, such as when
+     * GNSS Location is being requested at a sufficiently high accuracy, based on the capabilities
+     * of the GNSS chipset as reported in the IGnssCallback.
+     *
+     * @param corrections The computed corrections to be used by the HAL.
+     */
+    void setCorrections(in MeasurementCorrections corrections);
+
+    /**
+     * Opens the interface and provides the callback routines to the implementation of this
+     * interface.
+     *
+     * @param callback Callback interface for IMeasurementCorrections.
+     */
+    void setCallback(in IMeasurementCorrectionsCallback callback);
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
new file mode 100644
index 0000000..285c7d4
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.measurement_corrections;
+
+import android.hardware.gnss.measurement_corrections.SingleSatCorrection;
+
+/**
+ * A struct containing a set of measurement corrections for all used GNSS satellites at the location
+ * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified
+ * toaGpsNanosecondsOfWeek
+ */
+@VintfStability
+parcelable MeasurementCorrections {
+    /** Represents latitude in degrees at which the corrections are computed.. */
+    double latitudeDegrees;
+
+    /** Represents longitude in degrees at which the corrections are computed.. */
+    double longitudeDegrees;
+
+    /**
+     * Represents altitude in meters above the WGS 84 reference ellipsoid at which the corrections
+     * are computed.
+     */
+    double altitudeMeters;
+
+    /**
+     * Represents the horizontal uncertainty (63% to 68% confidence) in meters on the device
+     * position at which the corrections are provided.
+     *
+     * This value is useful for example to judge how accurate the provided corrections are.
+     */
+    double horizontalPositionUncertaintyMeters;
+
+    /**
+     * Represents the vertical uncertainty (63% to 68% confidence) in meters on the device position
+     * at which the corrections are provided.
+     *
+     * This value is useful for example to judge how accurate the provided corrections are.
+     */
+    double verticalPositionUncertaintyMeters;
+
+    /** Time Of Applicability, GPS time of week in nanoseconds. */
+    long toaGpsNanosecondsOfWeek;
+
+    /**
+     * A set of SingleSatCorrection each containing measurement corrections for a satellite in view
+     */
+    SingleSatCorrection[] satCorrections;
+
+    /**
+     * Boolean indicating if environment bearing is available.
+     */
+    boolean hasEnvironmentBearing;
+
+    /**
+     * Environment bearing in degrees clockwise from true North (0.0 to 360.0], in direction of
+     * user motion. Environment bearing is provided when it is known with high probability that
+     * velocity is aligned with an environment feature, such as a building or road.
+     *
+     * If user speed is zero, environmentBearingDegrees represents bearing of most recent speed
+     * that was > 0.
+     *
+     * As position approaches another road, environmentBearingUncertaintyDegrees will grow, and at
+     * some stage hasEnvironmentBearing = false.
+     *
+     * As position moves towards an open area, environmentBearingUncertaintyDegrees will grow, and
+     * at some stage hasEnvironmentBearing = false.
+     *
+     * If the road is curved in the vicinity of the user location, then
+     * environmentBearingUncertaintyDegrees will include the amount by which the road direction
+     * changes in the area of position uncertainty.
+     *
+     * hasEnvironmentBearing should be checked to verify the environment bearing is available
+     * before calling this method. The value is undefined if hasEnvironmentBearing is false.
+     */
+    float environmentBearingDegrees;
+
+    /**
+     * Environment bearing uncertainty [0 to 180]. It represents the standard deviation of the
+     * physical structure in the circle of position uncertainty. hasEnvironmentBearing becomes false
+     * as the uncertainty value passes a predefined threshold depending on the physical structure
+     * around the user.
+     *
+     * hasEnvironmentBearing should be checked to verify the environment bearing is available
+     * before calling this method. The value is undefined if hasEnvironmentBearing is false.
+     */
+    float environmentBearingUncertaintyDegrees;
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
new file mode 100644
index 0000000..9bf2b44
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.measurement_corrections;
+
+/**
+ * A struct containing the characteristics of the reflecting plane that the satellite signal has
+ * bounced from.
+ *
+ * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
+ * means either reflection planes serving is not supported or the satellite signal has gone
+ * through multiple reflections.
+ */
+@VintfStability
+parcelable ReflectingPlane {
+    /** Represents latitude of the reflecting plane in degrees. */
+    double latitudeDegrees;
+
+    /** Represents longitude of the reflecting plane in degrees. */
+    double longitudeDegrees;
+
+    /**
+     * Represents altitude of the reflecting point in the plane in meters above the WGS 84 reference
+     * ellipsoid.
+     */
+    double altitudeMeters;
+
+    /** Represents azimuth clockwise from north of the reflecting plane in degrees. */
+    double azimuthDegrees;
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
new file mode 100644
index 0000000..d9f7105
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.measurement_corrections;
+
+import android.hardware.gnss.GnssConstellationType;
+import android.hardware.gnss.measurement_corrections.ReflectingPlane;
+
+/**
+ * A struct with measurement corrections for a single visible satellites
+ *
+ * The bit mask singleSatCorrectionFlags indicates which correction values are valid in the struct
+ */
+@VintfStability
+parcelable SingleSatCorrection {
+    /** Bit mask to indicate which values are valid in a SingleSatCorrection object. */
+    /** GnssSingleSatCorrectionFlags has valid satellite-is-line-of-sight-probability field. */
+    const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 0x0001;
+    /** GnssSingleSatCorrectionFlags has valid Excess Path Length field. */
+    const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 0x0002;
+    /** GnssSingleSatCorrectionFlags has valid Excess Path Length Uncertainty field. */
+    const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 0x0004;
+    /** GnssSingleSatCorrectionFlags has valid Reflecting Plane field. */
+    const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 0x0008;
+
+    /** Contains GnssSingleSatCorrectionFlags bits. */
+    int singleSatCorrectionFlags;
+
+    /**
+     * Defines the constellation of the given satellite.
+     */
+    GnssConstellationType constellation;
+
+    /**
+     * Satellite vehicle ID number, as defined in GnssSvInfo::svid
+     */
+    int svid;
+
+    /**
+     * Carrier frequency of the signal to be corrected, for example it can be the
+     * GPS center frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
+     *
+     * For a receiver with capabilities to track multiple frequencies for the same satellite,
+     * multiple corrections for the same satellite may be provided.
+     */
+    long carrierFrequencyHz;
+
+    /**
+     * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
+     * location.
+     */
+    float probSatIsLos;
+
+    /**
+     * Excess path length to be subtracted from pseudorange before using it in calculating location.
+     *
+     * Note this value is NOT to be used to adjust the GnsseasurementCallback outputs.
+     */
+    float excessPathLengthMeters;
+
+    /** Error estimate (1-sigma) for the Excess path length estimate */
+    float excessPathLengthUncertaintyMeters;
+
+    /**
+     * Defines the reflecting plane characteristics such as location and azimuth
+     *
+     * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
+     * means either reflection planes serving is not supported or the satellite signal has gone
+     * through multiple reflections.
+     */
+    ReflectingPlane reflectingPlane;
+}
diff --git a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
new file mode 100644
index 0000000..c9c1549
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.visibility_control;
+
+import android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback;
+
+/**
+ * Represents the GNSS location reporting permissions and notification interface.
+ *
+ * This interface is used to tell the GNSS HAL implementation whether the framework user has
+ * granted permission to the GNSS HAL implementation to provide GNSS location information for
+ * non-framework (NFW), non-user initiated emergency use cases, and to notify the framework user
+ * of these GNSS location information deliveries.
+ *
+ * For user initiated emergency cases (and for the configured extended emergency session duration),
+ * the GNSS HAL implementation must serve the emergency location supporting network initiated
+ * location requests immediately irrespective of this permission settings.
+ *
+ * There is no separate need for the GNSS HAL implementation to monitor the global device location
+ * on/off setting. Permission to use GNSS for non-framework use cases is expressly controlled
+ * by the method enableNfwLocationAccess(). The framework monitors the location permission settings
+ * of the configured proxy applications(s), and device location settings, and calls the method
+ * enableNfwLocationAccess() whenever the user control proxy applications have, or do not have,
+ * location permission. The proxy applications are used to provide user visibility and control of
+ * location access by the non-framework on/off device entities they are representing.
+ *
+ * For device user visibility, the GNSS HAL implementation must call the method
+ * IGnssVisibilityControlCallback.nfwNotifyCb() whenever location request is rejected or
+ * location information is provided to non-framework entities (on or off device). This includes
+ * the network initiated location requests for user-initiated emergency use cases as well.
+ *
+ * The HAL implementations that support this interface must not report GNSS location, measurement,
+ * status, or other information that can be used to derive user location to any entity when not
+ * expressly authorized by this HAL. This includes all endpoints for location information
+ * off the device, including carriers, vendors, OEM and others directly or indirectly.
+ */
+@VintfStability
+interface IGnssVisibilityControl {
+    /**
+     * Enables/disables non-framework entity location access permission in the GNSS HAL.
+     *
+     * The framework will call this method to update GNSS HAL implementation every time the
+     * framework user, through the given proxy application(s) and/or device location settings,
+     * explicitly grants/revokes the location access permission for non-framework, non-user
+     * initiated emergency use cases.
+     *
+     * Whenever the user location information is delivered to non-framework entities, the HAL
+     * implementation must call the method IGnssVisibilityControlCallback.nfwNotifyCb() to notify
+     * the framework for user visibility.
+     *
+     * @param proxyApps Full list of package names of proxy Android applications representing
+     * the non-framework location access entities (on/off the device) for which the framework
+     * user has granted non-framework location access permission. The GNSS HAL implementation
+     * must provide location information only to non-framework entities represented by these
+     * proxy applications.
+     *
+     * The package name of the proxy Android application follows the standard Java language
+     * package naming format. For example, com.example.myapp.
+     */
+    void enableNfwLocationAccess(in @utf8InCpp String[] proxyApps);
+
+    /**
+     * Registers the callback for HAL implementation to use.
+     *
+     * @param callback Handle to IGnssVisibilityControlCallback interface.
+     */
+    void setCallback(in IGnssVisibilityControlCallback callback);
+}
diff --git a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
new file mode 100644
index 0000000..051fbe6
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.visibility_control;
+
+/**
+ * GNSS location reporting permissions and notification callback interface.
+ */
+@VintfStability
+interface IGnssVisibilityControlCallback {
+    /**
+     * Protocol stack that is requesting the non-framework location information.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum NfwProtocolStack {
+        /** Cellular control plane requests */
+        CTRL_PLANE = 0,
+
+        /** All types of SUPL requests */
+        SUPL = 1,
+
+        /** All types of requests from IMS */
+        IMS = 10,
+
+        /** All types of requests from SIM */
+        SIM = 11,
+
+        /** Requests from other protocol stacks */
+        OTHER_PROTOCOL_STACK = 100
+    }
+
+    /**
+     * Entity that is requesting/receiving the location information.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum NfwRequestor {
+        /** Wireless service provider */
+        CARRIER = 0,
+
+        /** Device manufacturer */
+        OEM = 10,
+
+        /** Modem chipset vendor */
+        MODEM_CHIPSET_VENDOR = 11,
+
+        /** GNSS chipset vendor */
+        GNSS_CHIPSET_VENDOR = 12,
+
+        /** Other chipset vendor */
+        OTHER_CHIPSET_VENDOR = 13,
+
+        /** Automobile client */
+        AUTOMOBILE_CLIENT = 20,
+
+        /** Other sources */
+        OTHER_REQUESTOR = 100
+    }
+
+    /**
+     * GNSS response type for non-framework location requests.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum NfwResponseType {
+        /** Request rejected because framework has not given permission for this use case */
+        REJECTED = 0,
+
+        /** Request accepted but could not provide location because of a failure */
+        ACCEPTED_NO_LOCATION_PROVIDED = 1,
+
+        /** Request accepted and location provided */
+        ACCEPTED_LOCATION_PROVIDED = 2,
+    }
+
+    /**
+     * Represents a non-framework location information request/response notification.
+     */
+    @VintfStability
+    parcelable NfwNotification {
+        /**
+         * Package name of the Android proxy application representing the non-framework
+         * entity that requested location. Set to empty string if unknown.
+         *
+         * For user-initiated emergency use cases, this field must be set to empty string
+         * and the inEmergencyMode field must be set to true.
+         */
+        String proxyAppPackageName;
+
+        /** Protocol stack that initiated the non-framework location request. */
+        NfwProtocolStack protocolStack;
+
+        /**
+         * Name of the protocol stack if protocolStack field is set to OTHER_PROTOCOL_STACK.
+         * Otherwise, set to empty string.
+         *
+         * This field is opaque to the framework and used for logging purposes.
+         */
+        String otherProtocolStackName;
+
+        /** Source initiating/receiving the location information. */
+        NfwRequestor requestor;
+
+        /**
+         * Identity of the endpoint receiving the location information. For example, carrier
+         * name, OEM name, SUPL SLP/E-SLP FQDN, chipset vendor name, etc.
+         *
+         * This field is opaque to the framework and used for logging purposes.
+         */
+        String requestorId;
+
+        /** Indicates whether location information was provided for this request. */
+        NfwResponseType responseType;
+
+        /** Is the device in user initiated emergency session. */
+        boolean inEmergencyMode;
+
+        /** Is cached location provided */
+        boolean isCachedLocation;
+    }
+
+    /**
+     * Callback to report a non-framework delivered location.
+     *
+     * The GNSS HAL implementation must call this method to notify the framework whenever
+     * a non-framework location request is made to the GNSS HAL.
+     *
+     * Non-framework entities like low power sensor hubs that request location from GNSS and
+     * only pass location information through Android framework controls are exempt from this
+     * power-spending reporting. However, low power sensor hubs or other chipsets which may send
+     * the location information to anywhere other than Android framework (which provides user
+     * visibility and control), must report location information use through this API whenever
+     * location information (or events driven by that location such as "home" location detection)
+     * leaves the domain of that low power chipset.
+     *
+     * To avoid overly spamming the framework, high speed location reporting of the exact same
+     * type may be throttled to report location at a lower rate than the actual report rate, as
+     * long as the location is reported with a latency of no more than the larger of 5 seconds,
+     * or the next the Android processor awake time. For example, if an Automotive client is
+     * getting location information from the GNSS location system at 20Hz, this method may be
+     * called at 1Hz. As another example, if a low power processor is getting location from the
+     * GNSS chipset, and the Android processor is asleep, the notification to the Android HAL may
+     * be delayed until the next wake of the Android processor.
+     *
+     * @param notification Non-framework delivered location request/response description.
+     */
+    void nfwNotifyCb(in NfwNotification notification);
+
+    /**
+     * Tells if the device is currently in an emergency session.
+     *
+     * Emergency session is defined as the device being actively in a user initiated emergency
+     * call or in post emergency call extension time period.
+     *
+     * If the GNSS HAL implementation cannot determine if the device is in emergency session
+     * mode, it must call this method to confirm that the device is in emergency session before
+     * serving network initiated emergency SUPL and Control Plane location requests.
+     *
+     * @return success True if the framework determines that the device is in emergency session.
+     */
+    boolean isInEmergencySession();
+}
diff --git a/gnss/aidl/default/AGnss.cpp b/gnss/aidl/default/AGnss.cpp
new file mode 100644
index 0000000..e8d5ef7
--- /dev/null
+++ b/gnss/aidl/default/AGnss.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AGnssAidl"
+
+#include "AGnss.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss {
+
+std::shared_ptr<IAGnssCallback> AGnss::sCallback = nullptr;
+
+ndk::ScopedAStatus AGnss::setCallback(const std::shared_ptr<IAGnssCallback>& callback) {
+    ALOGD("AGnss::setCallback");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnss::setServer(AGnssType type, const std::string& hostname, int port) {
+    ALOGD("AGnss::setServer: type: %s, hostname: %s, port: %d", toString(type).c_str(),
+          hostname.c_str(), port);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnss::dataConnOpen(int64_t networkHandle, const std::string& apn,
+                                       ApnIpType apnIpType) {
+    ALOGD("AGnss::dataConnOpen: networkHandle:%" PRId64 ", apn: %s, apnIpType %s", networkHandle,
+          apn.c_str(), toString(apnIpType).c_str());
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/AGnss.h b/gnss/aidl/default/AGnss.h
new file mode 100644
index 0000000..cd973e1
--- /dev/null
+++ b/gnss/aidl/default/AGnss.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnAGnss.h>
+
+namespace aidl::android::hardware::gnss {
+
+using AGnssType = IAGnssCallback::AGnssType;
+
+struct AGnss : public BnAGnss {
+  public:
+    ndk::ScopedAStatus setCallback(const std::shared_ptr<IAGnssCallback>& callback) override;
+    ndk::ScopedAStatus dataConnClosed() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus dataConnFailed() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus setServer(AGnssType type, const std::string& hostname, int port) override;
+    ndk::ScopedAStatus dataConnOpen(int64_t networkHandle, const std::string& apn,
+                                    ApnIpType apnIpType) override;
+
+  private:
+    // Synchronization lock for sCallback
+    mutable std::mutex mMutex;
+    // Guarded by mMutex
+    static std::shared_ptr<IAGnssCallback> sCallback;
+};
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/AGnssRil.cpp b/gnss/aidl/default/AGnssRil.cpp
new file mode 100644
index 0000000..afe0039
--- /dev/null
+++ b/gnss/aidl/default/AGnssRil.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AGnssRilAidl"
+
+#include "AGnssRil.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss {
+
+std::shared_ptr<IAGnssRilCallback> AGnssRil::sCallback = nullptr;
+
+ndk::ScopedAStatus AGnssRil::setCallback(const std::shared_ptr<IAGnssRilCallback>& callback) {
+    ALOGD("AGnssRil::setCallback");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnssRil::setRefLocation(const AGnssRefLocation& agnssReflocation) {
+    const AGnssRefLocationCellID& cellInfo = agnssReflocation.cellID;
+    ALOGD("AGnssRil::setRefLocation: type: %s, mcc: %d, mnc: %d, lac: %d, cid: %" PRId64
+          ", tac: %d, pcid: "
+          "%d, arfcn: %d",
+          toString(agnssReflocation.type).c_str(), cellInfo.mcc, cellInfo.mnc, cellInfo.lac,
+          cellInfo.cid, cellInfo.tac, cellInfo.pcid, cellInfo.arfcn);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnssRil::setSetId(SetIDType type, const std::string& setid) {
+    ALOGD("AGnssRil::setSetId: type:%s, setid: %s", toString(type).c_str(), setid.c_str());
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnssRil::updateNetworkState(const NetworkAttributes& attributes) {
+    ALOGD("AGnssRil::updateNetworkState: networkHandle:%" PRId64
+          ", isConnected: %d, capabilities: %d, "
+          "apn: %s",
+          attributes.networkHandle, attributes.isConnected, attributes.capabilities,
+          attributes.apn.c_str());
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/AGnssRil.h b/gnss/aidl/default/AGnssRil.h
new file mode 100644
index 0000000..7e429ee
--- /dev/null
+++ b/gnss/aidl/default/AGnssRil.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnAGnssRil.h>
+
+namespace aidl::android::hardware::gnss {
+
+struct AGnssRil : public BnAGnssRil {
+  public:
+    ndk::ScopedAStatus setCallback(const std::shared_ptr<IAGnssRilCallback>& callback) override;
+    ndk::ScopedAStatus setRefLocation(const AGnssRefLocation& agnssReflocation) override;
+    ndk::ScopedAStatus setSetId(SetIDType type, const std::string& setid) override;
+    ndk::ScopedAStatus updateNetworkState(const NetworkAttributes& attributes) override;
+
+  private:
+    // Synchronization lock for sCallback
+    mutable std::mutex mMutex;
+    // Guarded by mMutex
+    static std::shared_ptr<IAGnssRilCallback> sCallback;
+};
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index b6df895..4543665 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -55,8 +55,12 @@
         "android.hardware.gnss-V2-ndk",
     ],
     srcs: [
+        "AGnssRil.cpp",
+        "AGnss.cpp",
         "Gnss.cpp",
+        "GnssAntennaInfo.cpp",
         "GnssBatching.cpp",
+        "GnssDebug.cpp",
         "GnssGeofence.cpp",
         "GnssHidlHal.cpp",
         "GnssNavigationMessageInterface.cpp",
@@ -64,6 +68,8 @@
         "GnssPsds.cpp",
         "GnssConfiguration.cpp",
         "GnssMeasurementInterface.cpp",
+        "GnssVisibilityControl.cpp",
+        "MeasurementCorrectionsInterface.cpp",
         "service.cpp",
     ],
     static_libs: [
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 8d58a20..73f4085 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -17,23 +17,41 @@
 #define LOG_TAG "GnssAidl"
 
 #include "Gnss.h"
+#include <inttypes.h>
 #include <log/log.h>
+#include "AGnss.h"
+#include "AGnssRil.h"
+#include "DeviceFileReader.h"
+#include "FixLocationParser.h"
+#include "GnssAntennaInfo.h"
 #include "GnssBatching.h"
 #include "GnssConfiguration.h"
+#include "GnssDebug.h"
 #include "GnssGeofence.h"
 #include "GnssMeasurementInterface.h"
 #include "GnssNavigationMessageInterface.h"
 #include "GnssPsds.h"
+#include "GnssVisibilityControl.h"
+#include "MeasurementCorrectionsInterface.h"
+#include "Utils.h"
 
 namespace aidl::android::hardware::gnss {
+using ::android::hardware::gnss::common::Utils;
+
+using ndk::ScopedAStatus;
+using GnssSvInfo = IGnssCallback::GnssSvInfo;
+
+constexpr int TTFF_MILLIS = 2200;
 
 std::shared_ptr<IGnssCallback> Gnss::sGnssCallback = nullptr;
 
-ndk::ScopedAStatus Gnss::setCallback(const std::shared_ptr<IGnssCallback>& callback) {
-    ALOGD("Gnss::setCallback");
+Gnss::Gnss() : mMinIntervalMs(1000), mFirstFixReceived(false) {}
+
+ScopedAStatus Gnss::setCallback(const std::shared_ptr<IGnssCallback>& callback) {
+    ALOGD("setCallback");
     if (callback == nullptr) {
         ALOGE("%s: Null callback ignored", __func__);
-        return ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
+        return ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
     }
 
     sGnssCallback = callback;
@@ -47,69 +65,246 @@
         ALOGE("%s: Unable to invoke callback.gnssSetCapabilities", __func__);
     }
 
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::close() {
-    ALOGD("Gnss::close");
+std::unique_ptr<GnssLocation> Gnss::getLocationFromHW() {
+    if (!::android::hardware::gnss::common::ReplayUtils::hasFixedLocationDeviceFile()) {
+        return nullptr;
+    }
+    std::string inputStr =
+            ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData();
+    return ::android::hardware::gnss::common::FixLocationParser::getLocationFromInputStr(inputStr);
+}
+
+ScopedAStatus Gnss::start() {
+    ALOGD("start()");
+    if (mIsActive) {
+        ALOGW("Gnss has started. Restarting...");
+        stop();
+    }
+
+    mIsActive = true;
+    this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+    mThread = std::thread([this]() {
+        auto svStatus = filterBlocklistedSatellites(Utils::getMockSvInfoList());
+        this->reportSvStatus(svStatus);
+        if (!mFirstFixReceived) {
+            std::this_thread::sleep_for(std::chrono::milliseconds(TTFF_MILLIS));
+            mFirstFixReceived = true;
+        }
+        while (mIsActive == true) {
+            auto svStatus = filterBlocklistedSatellites(Utils::getMockSvInfoList());
+            this->reportSvStatus(svStatus);
+
+            auto currentLocation = getLocationFromHW();
+            mGnssPowerIndication->notePowerConsumption();
+            if (currentLocation != nullptr) {
+                this->reportLocation(*currentLocation);
+            } else {
+                const auto location = Utils::getMockLocation();
+                this->reportLocation(location);
+            }
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
+        }
+    });
+    return ScopedAStatus::ok();
+}
+
+void Gnss::reportLocation(const GnssLocation& location) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback == nullptr) {
+        ALOGE("%s: GnssCallback is null.", __func__);
+        return;
+    }
+    auto status = sGnssCallback->gnssLocationCb(location);
+    if (!status.isOk()) {
+        ALOGE("%s: Unable to invoke gnssLocationCb", __func__);
+    }
+    return;
+}
+
+void Gnss::reportSvStatus(const std::vector<GnssSvInfo>& svInfoList) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback == nullptr) {
+        ALOGE("%s: sGnssCallback is null.", __func__);
+        return;
+    }
+    auto status = sGnssCallback->gnssSvStatusCb(svInfoList);
+    if (!status.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+std::vector<GnssSvInfo> Gnss::filterBlocklistedSatellites(std::vector<GnssSvInfo> gnssSvInfoList) {
+    ALOGD("filterBlocklistedSatellites");
+    for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
+        if (mGnssConfiguration->isBlocklisted(gnssSvInfoList[i])) {
+            gnssSvInfoList[i].svFlag &= ~(uint32_t)IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        }
+    }
+    return gnssSvInfoList;
+}
+
+void Gnss::reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback == nullptr) {
+        ALOGE("%s: sGnssCallback is null.", __func__);
+        return;
+    }
+    auto status = sGnssCallback->gnssStatusCb(gnssStatusValue);
+    if (!status.isOk()) {
+        ALOGE("%s: Unable to invoke gnssStatusCb", __func__);
+    }
+}
+
+ScopedAStatus Gnss::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::close() {
+    ALOGD("close");
     sGnssCallback = nullptr;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::getExtensionAGnss(std::shared_ptr<IAGnss>* iAGnss) {
+    ALOGD("Gnss::getExtensionAGnss");
+    *iAGnss = SharedRefBase::make<AGnss>();
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) {
-    ALOGD("Gnss::getExtensionPsds");
+ScopedAStatus Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs, int uncertaintyMs) {
+    ALOGD("injectTime. timeMs:%" PRId64 ", timeReferenceMs:%" PRId64 ", uncertaintyMs:%d", timeMs,
+          timeReferenceMs, uncertaintyMs);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::getExtensionAGnssRil(std::shared_ptr<IAGnssRil>* iAGnssRil) {
+    ALOGD("Gnss::getExtensionAGnssRil");
+    *iAGnssRil = SharedRefBase::make<AGnssRil>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::injectLocation(const GnssLocation& location) {
+    ALOGD("injectLocation. lat:%lf, lng:%lf, acc:%f", location.latitudeDegrees,
+          location.longitudeDegrees, location.horizontalAccuracyMeters);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::injectBestLocation(const GnssLocation& location) {
+    ALOGD("injectBestLocation. lat:%lf, lng:%lf, acc:%f", location.latitudeDegrees,
+          location.longitudeDegrees, location.horizontalAccuracyMeters);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::deleteAidingData(GnssAidingData aidingDataFlags) {
+    ALOGD("deleteAidingData. flags:%d", (int)aidingDataFlags);
+    mFirstFixReceived = false;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::setPositionMode(GnssPositionMode, GnssPositionRecurrence, int minIntervalMs,
+                                    int /* preferredAccuracyMeters */, int /* preferredTimeMs */,
+                                    bool lowPowerMode) {
+    ALOGD("setPositionMode. minIntervalMs:%d, lowPowerMode:%d", minIntervalMs, (int)lowPowerMode);
+    mMinIntervalMs = minIntervalMs;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) {
+    ALOGD("getExtensionPsds");
     *iGnssPsds = SharedRefBase::make<GnssPsds>();
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::getExtensionGnssConfiguration(
+ScopedAStatus Gnss::getExtensionGnssConfiguration(
         std::shared_ptr<IGnssConfiguration>* iGnssConfiguration) {
-    ALOGD("Gnss::getExtensionGnssConfiguration");
+    ALOGD("getExtensionGnssConfiguration");
     if (mGnssConfiguration == nullptr) {
         mGnssConfiguration = SharedRefBase::make<GnssConfiguration>();
     }
     *iGnssConfiguration = mGnssConfiguration;
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::getExtensionGnssPowerIndication(
+ScopedAStatus Gnss::getExtensionGnssPowerIndication(
         std::shared_ptr<IGnssPowerIndication>* iGnssPowerIndication) {
-    ALOGD("Gnss::getExtensionGnssPowerIndication");
+    ALOGD("getExtensionGnssPowerIndication");
     if (mGnssPowerIndication == nullptr) {
         mGnssPowerIndication = SharedRefBase::make<GnssPowerIndication>();
     }
 
     *iGnssPowerIndication = mGnssPowerIndication;
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::getExtensionGnssMeasurement(
+ScopedAStatus Gnss::getExtensionGnssMeasurement(
         std::shared_ptr<IGnssMeasurementInterface>* iGnssMeasurement) {
-    ALOGD("Gnss::getExtensionGnssMeasurement");
+    ALOGD("getExtensionGnssMeasurement");
 
     *iGnssMeasurement = SharedRefBase::make<GnssMeasurementInterface>();
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::getExtensionGnssBatching(std::shared_ptr<IGnssBatching>* iGnssBatching) {
-    ALOGD("Gnss::getExtensionGnssBatching");
+ScopedAStatus Gnss::getExtensionGnssBatching(std::shared_ptr<IGnssBatching>* iGnssBatching) {
+    ALOGD("getExtensionGnssBatching");
 
     *iGnssBatching = SharedRefBase::make<GnssBatching>();
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::getExtensionGnssGeofence(std::shared_ptr<IGnssGeofence>* iGnssGeofence) {
-    ALOGD("Gnss::getExtensionGnssGeofence");
+ScopedAStatus Gnss::getExtensionGnssGeofence(std::shared_ptr<IGnssGeofence>* iGnssGeofence) {
+    ALOGD("getExtensionGnssGeofence");
 
     *iGnssGeofence = SharedRefBase::make<GnssGeofence>();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::getExtensionGnssNavigationMessage(
+        std::shared_ptr<IGnssNavigationMessageInterface>* iGnssNavigationMessage) {
+    ALOGD("getExtensionGnssNavigationMessage");
+
+    *iGnssNavigationMessage = SharedRefBase::make<GnssNavigationMessageInterface>();
+    return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::getExtensionGnssDebug(std::shared_ptr<IGnssDebug>* iGnssDebug) {
+    ALOGD("Gnss::getExtensionGnssDebug");
+
+    *iGnssDebug = SharedRefBase::make<GnssDebug>();
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Gnss::getExtensionGnssNavigationMessage(
-        std::shared_ptr<IGnssNavigationMessageInterface>* iGnssNavigationMessage) {
-    ALOGD("Gnss::getExtensionGnssNavigationMessage");
+ndk::ScopedAStatus Gnss::getExtensionGnssVisibilityControl(
+        std::shared_ptr<visibility_control::IGnssVisibilityControl>* iGnssVisibilityControl) {
+    ALOGD("Gnss::getExtensionGnssVisibilityControl");
 
-    *iGnssNavigationMessage = SharedRefBase::make<GnssNavigationMessageInterface>();
+    *iGnssVisibilityControl = SharedRefBase::make<visibility_control::GnssVisibilityControl>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::getExtensionGnssAntennaInfo(
+        std::shared_ptr<IGnssAntennaInfo>* iGnssAntennaInfo) {
+    ALOGD("Gnss::getExtensionGnssAntennaInfo");
+
+    *iGnssAntennaInfo = SharedRefBase::make<GnssAntennaInfo>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::getExtensionMeasurementCorrections(
+        std::shared_ptr<measurement_corrections::IMeasurementCorrectionsInterface>*
+                iMeasurementCorrections) {
+    ALOGD("Gnss::getExtensionMeasurementCorrections");
+
+    *iMeasurementCorrections =
+            SharedRefBase::make<measurement_corrections::MeasurementCorrectionsInterface>();
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 128a6c1..36874b8 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -16,12 +16,21 @@
 
 #pragma once
 
+#include <aidl/android/hardware/gnss/BnAGnss.h>
+#include <aidl/android/hardware/gnss/BnAGnssRil.h>
 #include <aidl/android/hardware/gnss/BnGnss.h>
+#include <aidl/android/hardware/gnss/BnGnssAntennaInfo.h>
 #include <aidl/android/hardware/gnss/BnGnssBatching.h>
 #include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
+#include <aidl/android/hardware/gnss/BnGnssDebug.h>
 #include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
 #include <aidl/android/hardware/gnss/BnGnssPowerIndication.h>
 #include <aidl/android/hardware/gnss/BnGnssPsds.h>
+#include <aidl/android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsInterface.h>
+#include <aidl/android/hardware/gnss/visibility_control/BnGnssVisibilityControl.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
 #include "GnssConfiguration.h"
 #include "GnssPowerIndication.h"
 
@@ -29,8 +38,22 @@
 
 class Gnss : public BnGnss {
   public:
+    Gnss();
+    ~Gnss() { stop(); };
     ndk::ScopedAStatus setCallback(const std::shared_ptr<IGnssCallback>& callback) override;
+    ndk::ScopedAStatus start() override;
+    ndk::ScopedAStatus stop() override;
     ndk::ScopedAStatus close() override;
+
+    ndk::ScopedAStatus injectTime(int64_t timeMs, int64_t timeReferenceMs,
+                                  int uncertaintyMs) override;
+    ndk::ScopedAStatus injectLocation(const GnssLocation& location) override;
+    ndk::ScopedAStatus injectBestLocation(const GnssLocation& location) override;
+    ndk::ScopedAStatus deleteAidingData(GnssAidingData aidingDataFlags) override;
+    ndk::ScopedAStatus setPositionMode(GnssPositionMode mode, GnssPositionRecurrence recurrence,
+                                       int minIntervalMs, int preferredAccuracyMeters,
+                                       int preferredTimeMs, bool lowPowerMode) override;
+
     ndk::ScopedAStatus getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) override;
     ndk::ScopedAStatus getExtensionGnssConfiguration(
             std::shared_ptr<IGnssConfiguration>* iGnssConfiguration) override;
@@ -44,12 +67,38 @@
             std::shared_ptr<IGnssGeofence>* iGnssGeofence) override;
     ndk::ScopedAStatus getExtensionGnssNavigationMessage(
             std::shared_ptr<IGnssNavigationMessageInterface>* iGnssNavigationMessage) override;
+    ndk::ScopedAStatus getExtensionAGnss(std::shared_ptr<IAGnss>* iAGnss) override;
+    ndk::ScopedAStatus getExtensionAGnssRil(std::shared_ptr<IAGnssRil>* iAGnssRil) override;
+    ndk::ScopedAStatus getExtensionGnssDebug(std::shared_ptr<IGnssDebug>* iGnssDebug) override;
+    ndk::ScopedAStatus getExtensionGnssVisibilityControl(
+            std::shared_ptr<android::hardware::gnss::visibility_control::IGnssVisibilityControl>*
+                    iGnssVisibilityControl) override;
+    ndk::ScopedAStatus getExtensionGnssAntennaInfo(
+            std::shared_ptr<IGnssAntennaInfo>* iGnssAntennaInfo) override;
+    ndk::ScopedAStatus getExtensionMeasurementCorrections(
+            std::shared_ptr<android::hardware::gnss::measurement_corrections::
+                                    IMeasurementCorrectionsInterface>* iMeasurementCorrections)
+            override;
 
     std::shared_ptr<GnssConfiguration> mGnssConfiguration;
     std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
 
   private:
+    void reportLocation(const GnssLocation&) const;
+    void reportSvStatus(const std::vector<IGnssCallback::GnssSvInfo>& svInfoList) const;
+    std::vector<IGnssCallback::GnssSvInfo> filterBlocklistedSatellites(
+            std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList);
+    void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
+    std::unique_ptr<GnssLocation> getLocationFromHW();
+
     static std::shared_ptr<IGnssCallback> sGnssCallback;
+
+    std::atomic<long> mMinIntervalMs;
+    std::atomic<bool> mIsActive;
+    std::atomic<bool> mFirstFixReceived;
+    std::thread mThread;
+
+    mutable std::mutex mMutex;
 };
 
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssAntennaInfo.cpp b/gnss/aidl/default/GnssAntennaInfo.cpp
new file mode 100644
index 0000000..72def71
--- /dev/null
+++ b/gnss/aidl/default/GnssAntennaInfo.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssAntennaInfoAidl"
+
+#include "GnssAntennaInfo.h"
+#include <aidl/android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+#include "Utils.h"
+
+namespace aidl::android::hardware::gnss {
+
+using namespace ::android::hardware::gnss;
+using Row = IGnssAntennaInfoCallback::Row;
+using Coord = IGnssAntennaInfoCallback::Coord;
+
+std::shared_ptr<IGnssAntennaInfoCallback> GnssAntennaInfo::sCallback = nullptr;
+
+GnssAntennaInfo::GnssAntennaInfo() : mMinIntervalMs(1000) {}
+
+GnssAntennaInfo::~GnssAntennaInfo() {
+    stop();
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
+ndk::ScopedAStatus GnssAntennaInfo::setCallback(
+        const std::shared_ptr<IGnssAntennaInfoCallback>& callback) {
+    ALOGD("setCallback");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssAntennaInfo callback already set. Resetting the callback...");
+        stop();
+    }
+    start();
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus GnssAntennaInfo::close() {
+    ALOGD("close");
+    stop();
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = nullptr;
+    return ndk::ScopedAStatus::ok();
+}
+
+void GnssAntennaInfo::start() {
+    ALOGD("start");
+    mIsActive = true;
+    mThread = std::thread([this]() {
+        while (mIsActive == true) {
+            if (sCallback != nullptr) {
+                IGnssAntennaInfoCallback::GnssAntennaInfo mockAntennaInfo_1 = {
+                        .carrierFrequencyHz = 1575420000,
+                        .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 1,
+                                                                        .xUncertainty = 0.1,
+                                                                        .y = 2,
+                                                                        .yUncertainty = 0.1,
+                                                                        .z = 3,
+                                                                        .zUncertainty = 0.1},
+                        .phaseCenterVariationCorrectionMillimeters =
+                                {
+                                        Row{std::vector<double>{1, -1, 5, -2, 3, -1}},
+                                        Row{std::vector<double>{-2, 3, 2, 0, 1, 2}},
+                                        Row{std::vector<double>{1, 3, 2, -1, -3, 5}},
+                                },
+                        .phaseCenterVariationCorrectionUncertaintyMillimeters =
+                                {
+                                        Row{std::vector<double>{0.1, 0.2, 0.4, 0.1, 0.2, 0.3}},
+                                        Row{std::vector<double>{0.3, 0.2, 0.3, 0.6, 0.1, 0.1}},
+                                        Row{std::vector<double>{0.1, 0.1, 0.4, 0.2, 0.5, 0.3}},
+                                },
+                        .signalGainCorrectionDbi =
+                                {
+                                        Row{std::vector<double>{2, -3, 1, -3, 0, -4}},
+                                        Row{std::vector<double>{1, 0, -4, 1, 3, -2}},
+                                        Row{std::vector<double>{3, -2, 0, -2, 3, 0}},
+                                },
+                        .signalGainCorrectionUncertaintyDbi =
+                                {
+                                        Row{std::vector<double>{0.3, 0.1, 0.2, 0.6, 0.1, 0.3}},
+                                        Row{std::vector<double>{0.1, 0.1, 0.5, 0.2, 0.3, 0.1}},
+                                        Row{std::vector<double>{0.2, 0.4, 0.2, 0.1, 0.1, 0.2}},
+                                },
+                };
+
+                IGnssAntennaInfoCallback::GnssAntennaInfo mockAntennaInfo_2 = {
+                        .carrierFrequencyHz = 1176450000,
+                        .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5,
+                                                                        .xUncertainty = 0.1,
+                                                                        .y = 6,
+                                                                        .yUncertainty = 0.1,
+                                                                        .z = 7,
+                                                                        .zUncertainty = 0.1},
+                };
+
+                std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo> mockAntennaInfos = {
+                        mockAntennaInfo_1,
+                        mockAntennaInfo_2,
+                };
+                this->reportAntennaInfo(mockAntennaInfos);
+            }
+
+            /** For mock implementation this is good. On real device, we should only report
+                antennaInfo at start and when there is a configuration change. **/
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
+        }
+    });
+}
+
+void GnssAntennaInfo::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void GnssAntennaInfo::reportAntennaInfo(
+        const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+
+    if (sCallback == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+
+    auto ret = sCallback->gnssAntennaInfoCb(antennaInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssAntennaInfo.h b/gnss/aidl/default/GnssAntennaInfo.h
new file mode 100644
index 0000000..2cf7b13
--- /dev/null
+++ b/gnss/aidl/default/GnssAntennaInfo.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnGnssAntennaInfo.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+namespace aidl::android::hardware::gnss {
+
+struct GnssAntennaInfo : public BnGnssAntennaInfo {
+  public:
+    GnssAntennaInfo();
+    ~GnssAntennaInfo();
+    ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<IGnssAntennaInfoCallback>& callback) override;
+    ndk::ScopedAStatus close() override;
+
+  private:
+    void start();
+    void stop();
+    void reportAntennaInfo(
+            const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const;
+
+    // Guarded by mMutex
+    static std::shared_ptr<IGnssAntennaInfoCallback> sCallback;
+
+    std::atomic<bool> mIsActive;
+    std::atomic<long> mMinIntervalMs;
+    std::thread mThread;
+
+    // Synchronization lock for sCallback
+    mutable std::mutex mMutex;
+};
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssBatching.cpp b/gnss/aidl/default/GnssBatching.cpp
index b8be5e5..33e1fd5 100644
--- a/gnss/aidl/default/GnssBatching.cpp
+++ b/gnss/aidl/default/GnssBatching.cpp
@@ -52,17 +52,19 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus GnssBatching::start(int64_t periodNanos, int flags) {
-    ALOGD("start: periodNanos=%" PRId64 ", flags=%d", periodNanos, flags);
+ndk::ScopedAStatus GnssBatching::start(const Options& options) {
+    ALOGD("start: periodNanos=%" PRId64 ", minDistanceMeters=%f, flags=%d", options.periodNanos,
+          options.minDistanceMeters, options.flags);
     if (mIsActive) {
         ALOGW("Gnss has started. Restarting...");
         stop();
     }
 
-    mWakeUpOnFifoFull = (flags & IGnssBatching::WAKEUP_ON_FIFO_FULL) ? true : false;
     // mMinIntervalMs is not smaller than 1 sec
-    periodNanos = (periodNanos < 1e9) ? 1e9 : periodNanos;
+    long periodNanos = (options.periodNanos < 1e9) ? 1e9 : options.periodNanos;
     mMinIntervalMs = periodNanos / 1e6;
+    mWakeUpOnFifoFull = (options.flags & IGnssBatching::WAKEUP_ON_FIFO_FULL) ? true : false;
+    mMinDistanceMeters = options.minDistanceMeters;
 
     mIsActive = true;
     mThread = std::thread([this]() {
diff --git a/gnss/aidl/default/GnssBatching.h b/gnss/aidl/default/GnssBatching.h
index 7cd6e85..6d1d809 100644
--- a/gnss/aidl/default/GnssBatching.h
+++ b/gnss/aidl/default/GnssBatching.h
@@ -28,7 +28,7 @@
     ~GnssBatching();
     ndk::ScopedAStatus init(const std::shared_ptr<IGnssBatchingCallback>& callback) override;
     ndk::ScopedAStatus getBatchSize(int* size) override;
-    ndk::ScopedAStatus start(int64_t periodNanos, int flags) override;
+    ndk::ScopedAStatus start(const Options& options) override;
     ndk::ScopedAStatus flush() override;
     ndk::ScopedAStatus stop() override;
     ndk::ScopedAStatus cleanup() override;
@@ -42,6 +42,7 @@
     std::thread mThread;
     std::atomic<bool> mIsActive;
     std::atomic<long> mMinIntervalMs;
+    std::atomic<float> mMinDistanceMeters;
     std::atomic<bool> mWakeUpOnFifoFull;
 
     // Synchronization lock for sCallback
diff --git a/gnss/aidl/default/GnssConfiguration.cpp b/gnss/aidl/default/GnssConfiguration.cpp
index 30e0d8c..96a1aa2 100644
--- a/gnss/aidl/default/GnssConfiguration.cpp
+++ b/gnss/aidl/default/GnssConfiguration.cpp
@@ -49,4 +49,14 @@
     return (mBlocklistedSourceSet.find(source) != mBlocklistedSourceSet.end());
 }
 
+bool GnssConfiguration::isBlocklisted(const IGnssCallback::GnssSvInfo& gnssSvInfo) const {
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    if (mBlocklistedConstellationSet.find(gnssSvInfo.constellation) !=
+        mBlocklistedConstellationSet.end()) {
+        return true;
+    }
+    BlocklistedSource source = {.constellation = gnssSvInfo.constellation, .svid = gnssSvInfo.svid};
+    return (mBlocklistedSourceSet.find(source) != mBlocklistedSourceSet.end());
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssConfiguration.h b/gnss/aidl/default/GnssConfiguration.h
index 491733c..3c77f32 100644
--- a/gnss/aidl/default/GnssConfiguration.h
+++ b/gnss/aidl/default/GnssConfiguration.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <aidl/android/hardware/gnss/BnGnssCallback.h>
 #include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
 #include <android/hardware/gnss/2.1/IGnssCallback.h>
 #include <mutex>
@@ -62,6 +63,7 @@
     ndk::ScopedAStatus setBlocklist(const vector<BlocklistedSource>& blocklist) override;
 
     bool isBlocklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const;
+    bool isBlocklisted(const IGnssCallback::GnssSvInfo& gnssSvInfo) const;
 
   private:
     BlocklistedSourceSet mBlocklistedSourceSet;
diff --git a/gnss/aidl/default/GnssDebug.cpp b/gnss/aidl/default/GnssDebug.cpp
new file mode 100644
index 0000000..f40c0bc
--- /dev/null
+++ b/gnss/aidl/default/GnssDebug.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssDebugAidl"
+
+#include "GnssDebug.h"
+#include <log/log.h>
+#include "MockLocation.h"
+
+namespace aidl::android::hardware::gnss {
+
+ndk::ScopedAStatus GnssDebug::getDebugData(DebugData* debugData) {
+    ALOGD("GnssDebug::getDebugData");
+
+    PositionDebug positionDebug = {.valid = true,
+                                   .latitudeDegrees = 37.4219999,
+                                   .longitudeDegrees = -122.0840575,
+                                   .altitudeMeters = 1.60062531,
+                                   .speedMetersPerSec = 0,
+                                   .bearingDegrees = 0,
+                                   .horizontalAccuracyMeters = 5,
+                                   .verticalAccuracyMeters = 5,
+                                   .speedAccuracyMetersPerSecond = 1,
+                                   .bearingAccuracyDegrees = 90,
+                                   .ageSeconds = 0.99};
+    TimeDebug timeDebug = {.timeEstimateMs = 1519930775453L,
+                           .timeUncertaintyNs = 1000,
+                           .frequencyUncertaintyNsPerSec = 5.0e4};
+    std::vector<SatelliteData> satelliteDataArrayDebug = {};
+    debugData->position = positionDebug;
+    debugData->time = timeDebug;
+    debugData->satelliteDataArray = satelliteDataArrayDebug;
+
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssDebug.h b/gnss/aidl/default/GnssDebug.h
new file mode 100644
index 0000000..001d47c
--- /dev/null
+++ b/gnss/aidl/default/GnssDebug.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnGnssDebug.h>
+
+namespace aidl::android::hardware::gnss {
+
+struct GnssDebug : public BnGnssDebug {
+  public:
+    ndk::ScopedAStatus getDebugData(DebugData* debugData) override;
+};
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 9e4f7c7..2c7241b 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -56,11 +56,29 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus GnssMeasurementInterface::setCallbackWithOptions(
+        const std::shared_ptr<IGnssMeasurementCallback>& callback, const Options& options) {
+    ALOGD("setCallbackWithOptions: fullTracking:%d, corrVec:%d, intervalMs:%d",
+          (int)options.enableFullTracking, (int)options.enableCorrVecOutputs, options.intervalMs);
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+        stop();
+    }
+    mMinIntervalMillis = options.intervalMs;
+    start(options.enableCorrVecOutputs);
+
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus GnssMeasurementInterface::close() {
     ALOGD("close");
     stop();
     std::unique_lock<std::mutex> lock(mMutex);
     sCallback = nullptr;
+    mMinIntervalMillis = 1000;
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index db63515..bf77806 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -32,6 +32,9 @@
                                    const bool enableFullTracking,
                                    const bool enableCorrVecOutputs) override;
     ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus setCallbackWithOptions(
+            const std::shared_ptr<IGnssMeasurementCallback>& callback,
+            const Options& options) override;
 
   private:
     void start(const bool enableCorrVecOutputs);
diff --git a/gnss/aidl/default/GnssVisibilityControl.cpp b/gnss/aidl/default/GnssVisibilityControl.cpp
new file mode 100644
index 0000000..208d73c
--- /dev/null
+++ b/gnss/aidl/default/GnssVisibilityControl.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssVisibilityControl"
+
+#include "GnssVisibilityControl.h"
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss::visibility_control {
+
+std::shared_ptr<IGnssVisibilityControlCallback> GnssVisibilityControl::sCallback = nullptr;
+
+ndk::ScopedAStatus GnssVisibilityControl::enableNfwLocationAccess(
+        const std::vector<std::string>& proxyApps) {
+    std::string os;
+    bool first = true;
+    for (const auto& proxyApp : proxyApps) {
+        if (first) {
+            first = false;
+        } else {
+            os += " ";
+        }
+        os += proxyApp;
+    }
+
+    ALOGD("GnssVisibilityControl::enableNfwLocationAccess proxyApps: %s", os.c_str());
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus GnssVisibilityControl::setCallback(
+        const std::shared_ptr<IGnssVisibilityControlCallback>& callback) {
+    ALOGD("GnssVisibilityControl::setCallback");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::gnss::visibility_control
diff --git a/gnss/aidl/default/GnssVisibilityControl.h b/gnss/aidl/default/GnssVisibilityControl.h
new file mode 100644
index 0000000..5b36442
--- /dev/null
+++ b/gnss/aidl/default/GnssVisibilityControl.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/visibility_control/BnGnssVisibilityControl.h>
+
+namespace aidl::android::hardware::gnss::visibility_control {
+
+struct GnssVisibilityControl : public BnGnssVisibilityControl {
+  public:
+    ndk::ScopedAStatus enableNfwLocationAccess(const std::vector<std::string>& hostname) override;
+    ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<IGnssVisibilityControlCallback>& callback) override;
+
+  private:
+    // Synchronization lock for sCallback
+    mutable std::mutex mMutex;
+    // Guarded by mMutex
+    static std::shared_ptr<IGnssVisibilityControlCallback> sCallback;
+};
+
+}  // namespace aidl::android::hardware::gnss::visibility_control
diff --git a/gnss/aidl/default/MeasurementCorrectionsInterface.cpp b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
new file mode 100644
index 0000000..0f1851c
--- /dev/null
+++ b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MeasurementCorrectionsInterface"
+
+#include "MeasurementCorrectionsInterface.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss::measurement_corrections {
+
+std::shared_ptr<IMeasurementCorrectionsCallback> MeasurementCorrectionsInterface::sCallback =
+        nullptr;
+
+ndk::ScopedAStatus MeasurementCorrectionsInterface::setCorrections(
+        const MeasurementCorrections& corrections) {
+    ALOGD("setCorrections");
+    ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
+          "satCorrections.size: %d",
+          corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters,
+          corrections.horizontalPositionUncertaintyMeters,
+          corrections.verticalPositionUncertaintyMeters,
+          static_cast<unsigned long long>(corrections.toaGpsNanosecondsOfWeek),
+          static_cast<int>(corrections.satCorrections.size()));
+    for (auto singleSatCorrection : corrections.satCorrections) {
+        ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d"
+              ", cfHz: %" PRId64 ", probLos: %f, epl: %f, eplUnc: %f",
+              singleSatCorrection.singleSatCorrectionFlags, singleSatCorrection.constellation,
+              singleSatCorrection.svid, singleSatCorrection.carrierFrequencyHz,
+              singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+              singleSatCorrection.excessPathLengthUncertaintyMeters);
+        ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+              singleSatCorrection.reflectingPlane.latitudeDegrees,
+              singleSatCorrection.reflectingPlane.longitudeDegrees,
+              singleSatCorrection.reflectingPlane.altitudeMeters,
+              singleSatCorrection.reflectingPlane.azimuthDegrees);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus MeasurementCorrectionsInterface::setCallback(
+        const std::shared_ptr<IMeasurementCorrectionsCallback>& callback) {
+    ALOGD("MeasurementCorrections::setCallback");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+    auto ret = sCallback->setCapabilitiesCb(
+            IMeasurementCorrectionsCallback::CAPABILITY_LOS_SATS |
+            IMeasurementCorrectionsCallback::CAPABILITY_EXCESS_PATH_LENGTH |
+            IMeasurementCorrectionsCallback::CAPABILITY_REFLECTING_PLANE);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::gnss::measurement_corrections
diff --git a/gnss/aidl/default/MeasurementCorrectionsInterface.h b/gnss/aidl/default/MeasurementCorrectionsInterface.h
new file mode 100644
index 0000000..af58725
--- /dev/null
+++ b/gnss/aidl/default/MeasurementCorrectionsInterface.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsInterface.h>
+
+namespace aidl::android::hardware::gnss::measurement_corrections {
+
+struct MeasurementCorrectionsInterface : public BnMeasurementCorrectionsInterface {
+  public:
+    ndk::ScopedAStatus setCorrections(const MeasurementCorrections& corrections) override;
+    ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<IMeasurementCorrectionsCallback>& callback) override;
+
+  private:
+    // Synchronization lock for sCallback
+    mutable std::mutex mMutex;
+    // Guarded by mMutex
+    static std::shared_ptr<IMeasurementCorrectionsCallback> sCallback;
+};
+
+}  // namespace aidl::android::hardware::gnss::measurement_corrections
diff --git a/gnss/aidl/default/service.cpp b/gnss/aidl/default/service.cpp
index 09f1ad2..bbe34f1 100644
--- a/gnss/aidl/default/service.cpp
+++ b/gnss/aidl/default/service.cpp
@@ -42,7 +42,7 @@
     const std::string instance = std::string() + Gnss::descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(gnssAidl->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     sp<IGnss> gnss = new GnssHidlHal(gnssAidl);
     configureRpcThreadpool(1, true /* will join */);
diff --git a/gnss/aidl/vts/AGnssCallbackAidl.cpp b/gnss/aidl/vts/AGnssCallbackAidl.cpp
new file mode 100644
index 0000000..3327835
--- /dev/null
+++ b/gnss/aidl/vts/AGnssCallbackAidl.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AGnssCallbackAidl.h"
+#include <log/log.h>
+
+android::binder::Status AGnssCallbackAidl::agnssStatusCb(const AGnssType type,
+                                                         const AGnssStatusValue status) {
+    ALOGI("agnssStatusCb type %d status %d", type, status);
+    return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/AGnssCallbackAidl.h b/gnss/aidl/vts/AGnssCallbackAidl.h
new file mode 100644
index 0000000..6173e85
--- /dev/null
+++ b/gnss/aidl/vts/AGnssCallbackAidl.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnAGnssCallback.h>
+
+using AGnssType = android::hardware::gnss::IAGnssCallback::AGnssType;
+using AGnssStatusValue = android::hardware::gnss::IAGnssCallback::AGnssStatusValue;
+
+/** Implementation for IAGnssCallback. */
+class AGnssCallbackAidl : public android::hardware::gnss::BnAGnssCallback {
+  public:
+    AGnssCallbackAidl(){};
+    ~AGnssCallbackAidl(){};
+    android::binder::Status agnssStatusCb(const AGnssType type,
+                                          const AGnssStatusValue status) override;
+};
diff --git a/gnss/aidl/vts/AGnssRilCallbackAidl.cpp b/gnss/aidl/vts/AGnssRilCallbackAidl.cpp
new file mode 100644
index 0000000..4e4166d
--- /dev/null
+++ b/gnss/aidl/vts/AGnssRilCallbackAidl.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include "AGnssRilCallbackAidl.h"
+#include <log/log.h>
+
+android::binder::Status AGnssRilCallbackAidl::requestSetIdCb(int setIdflag) {
+    ALOGI("requestSetIdCb setIdflag %d", setIdflag);
+    return android::binder::Status::ok();
+}
+
+android::binder::Status AGnssRilCallbackAidl::requestRefLocCb() {
+    ALOGI("requestRefLocCb");
+    return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/AGnssRilCallbackAidl.h b/gnss/aidl/vts/AGnssRilCallbackAidl.h
new file mode 100644
index 0000000..74b34ee
--- /dev/null
+++ b/gnss/aidl/vts/AGnssRilCallbackAidl.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnAGnssRilCallback.h>
+
+/** Implementation for IAGnssRilCallback. */
+class AGnssRilCallbackAidl : public android::hardware::gnss::BnAGnssRilCallback {
+  public:
+    AGnssRilCallbackAidl(){};
+    ~AGnssRilCallbackAidl(){};
+    android::binder::Status requestSetIdCb(int setIdflag) override;
+    android::binder::Status requestRefLocCb() override;
+};
diff --git a/gnss/aidl/vts/Android.bp b/gnss/aidl/vts/Android.bp
index 4d81519..f02a41e 100644
--- a/gnss/aidl/vts/Android.bp
+++ b/gnss/aidl/vts/Android.bp
@@ -30,12 +30,17 @@
     srcs: [
         "gnss_hal_test.cpp",
         "gnss_hal_test_cases.cpp",
+        "AGnssCallbackAidl.cpp",
+        "AGnssRilCallbackAidl.cpp",
+        "GnssAntennaInfoCallbackAidl.cpp",
         "GnssBatchingCallback.cpp",
         "GnssCallbackAidl.cpp",
         "GnssGeofenceCallback.cpp",
         "GnssMeasurementCallbackAidl.cpp",
         "GnssNavigationMessageCallback.cpp",
         "GnssPowerIndicationCallback.cpp",
+        "GnssVisibilityControlCallback.cpp",
+        "MeasurementCorrectionsCallback.cpp",
         "VtsHalGnssTargetTest.cpp",
     ],
     shared_libs: [
diff --git a/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.cpp b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.cpp
new file mode 100644
index 0000000..11001cd
--- /dev/null
+++ b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GnssAntennaInfoCallbackAidl.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+android::binder::Status GnssAntennaInfoCallbackAidl::gnssAntennaInfoCb(
+        const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
+    ALOGD("GnssAntennaInfo received. Size = %d", (int)gnssAntennaInfos.size());
+    antenna_info_cbq_.store(gnssAntennaInfos);
+    return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.h b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.h
new file mode 100644
index 0000000..77e1057
--- /dev/null
+++ b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnGnssAntennaInfoCallback.h>
+#include <vector>
+#include "GnssCallbackEventQueue.h"
+
+/** Implementation for IGnssAntennaInfoCallback. */
+class GnssAntennaInfoCallbackAidl : public android::hardware::gnss::BnGnssAntennaInfoCallback {
+  public:
+    GnssAntennaInfoCallbackAidl() : antenna_info_cbq_("info"){};
+    ~GnssAntennaInfoCallbackAidl(){};
+
+    android::binder::Status gnssAntennaInfoCb(
+            const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos)
+            override;
+
+    android::hardware::gnss::common::GnssCallbackEventQueue<
+            std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>>
+            antenna_info_cbq_;
+};
diff --git a/gnss/aidl/vts/GnssBatchingCallback.cpp b/gnss/aidl/vts/GnssBatchingCallback.cpp
index 2da3b12..d4eb0a5 100644
--- a/gnss/aidl/vts/GnssBatchingCallback.cpp
+++ b/gnss/aidl/vts/GnssBatchingCallback.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "GnssBatchingCallbackAidl"
+
 #include "GnssBatchingCallback.h"
 #include <inttypes.h>
 #include <log/log.h>
diff --git a/gnss/aidl/vts/GnssCallbackAidl.cpp b/gnss/aidl/vts/GnssCallbackAidl.cpp
index f5c745b..77a2506 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssCallbackAidl.cpp
@@ -14,11 +14,62 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "GnssCallbackAidl"
+
 #include "GnssCallbackAidl.h"
 #include <log/log.h>
 
-android::binder::Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
-    ALOGI("Capabilities received %d", capabilities);
+using android::binder::Status;
+using android::hardware::gnss::GnssLocation;
+using GnssSvInfo = android::hardware::gnss::IGnssCallback::GnssSvInfo;
+using GnssSystemInfo = android::hardware::gnss::IGnssCallback::GnssSystemInfo;
+
+Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
+    ALOGI("Capabilities received %#08x", capabilities);
     capabilities_cbq_.store(capabilities);
-    return android::binder::Status::ok();
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue /* status */) {
+    ALOGI("gnssSvStatusCb");
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
+    ALOGI("gnssSvStatusCb. Size = %d", (int)svInfoList.size());
+    sv_info_list_cbq_.store(svInfoList);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssLocationCb(const GnssLocation& location) {
+    ALOGI("Location received");
+    location_cbq_.store(location);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t /* timestamp */, const std::string& /* nmea */) {
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssAcquireWakelockCb() {
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssReleaseWakelockCb() {
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
+    ALOGI("gnssSetSystemInfoCb, year=%d, name=%s", info.yearOfHw, info.name.c_str());
+    info_cbq_.store(info);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestTimeCb() {
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestLocationCb(const bool /* independentFromGnss */,
+                                               const bool /* isUserEmergency */) {
+    return Status::ok();
 }
diff --git a/gnss/aidl/vts/GnssCallbackAidl.h b/gnss/aidl/vts/GnssCallbackAidl.h
index 7f802ea..209728d 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.h
+++ b/gnss/aidl/vts/GnssCallbackAidl.h
@@ -22,11 +22,37 @@
 /* Callback class for data & Event. */
 class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
   public:
-    GnssCallbackAidl() : capabilities_cbq_("capabilities"){};
+    GnssCallbackAidl()
+        : capabilities_cbq_("capabilities"),
+          info_cbq_("system_info"),
+          location_cbq_("location"),
+          sv_info_list_cbq_("sv_info"){};
     ~GnssCallbackAidl(){};
 
     android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
+    android::binder::Status gnssStatusCb(const GnssStatusValue status) override;
+    android::binder::Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
+    android::binder::Status gnssLocationCb(
+            const android::hardware::gnss::GnssLocation& location) override;
+    android::binder::Status gnssNmeaCb(const int64_t timestamp, const std::string& nmea) override;
+    android::binder::Status gnssAcquireWakelockCb() override;
+    android::binder::Status gnssReleaseWakelockCb() override;
+    android::binder::Status gnssSetSystemInfoCb(const GnssSystemInfo& info) override;
+    android::binder::Status gnssRequestTimeCb() override;
+    android::binder::Status gnssRequestLocationCb(const bool independentFromGnss,
+                                                  const bool isUserEmergency) override;
 
     int last_capabilities_;
+    android::hardware::gnss::IGnssCallback::GnssSystemInfo last_info_;
+    android::hardware::gnss::GnssLocation last_location_;
+
     android::hardware::gnss::common::GnssCallbackEventQueue<int> capabilities_cbq_;
+    android::hardware::gnss::common::GnssCallbackEventQueue<
+            android::hardware::gnss::IGnssCallback::GnssSystemInfo>
+            info_cbq_;
+    android::hardware::gnss::common::GnssCallbackEventQueue<android::hardware::gnss::GnssLocation>
+            location_cbq_;
+    android::hardware::gnss::common::GnssCallbackEventQueue<
+            std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>>
+            sv_info_list_cbq_;
 };
\ No newline at end of file
diff --git a/gnss/aidl/vts/GnssVisibilityControlCallback.cpp b/gnss/aidl/vts/GnssVisibilityControlCallback.cpp
new file mode 100644
index 0000000..aa27af1
--- /dev/null
+++ b/gnss/aidl/vts/GnssVisibilityControlCallback.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GnssVisibilityControlCallback.h"
+#include <log/log.h>
+
+android::binder::Status GnssVisibilityControlCallback::nfwNotifyCb(const NfwNotification&) {
+    // To implement
+    return android::binder::Status::ok();
+}
+
+android::binder::Status GnssVisibilityControlCallback::isInEmergencySession(bool*) {
+    // To implement
+    return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/GnssVisibilityControlCallback.h b/gnss/aidl/vts/GnssVisibilityControlCallback.h
new file mode 100644
index 0000000..fbacde7
--- /dev/null
+++ b/gnss/aidl/vts/GnssVisibilityControlCallback.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/visibility_control/BnGnssVisibilityControlCallback.h>
+
+class GnssVisibilityControlCallback
+    : public android::hardware::gnss::visibility_control::BnGnssVisibilityControlCallback {
+  public:
+    GnssVisibilityControlCallback(){};
+    ~GnssVisibilityControlCallback(){};
+    android::binder::Status nfwNotifyCb(
+            const android::hardware::gnss::visibility_control::IGnssVisibilityControlCallback::
+                    NfwNotification& notification) override;
+    android::binder::Status isInEmergencySession(bool* _aidl_return) override;
+};
diff --git a/gnss/aidl/vts/MeasurementCorrectionsCallback.cpp b/gnss/aidl/vts/MeasurementCorrectionsCallback.cpp
new file mode 100644
index 0000000..db1f7a6
--- /dev/null
+++ b/gnss/aidl/vts/MeasurementCorrectionsCallback.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MeasurementCorrectionsCallback"
+
+#include "MeasurementCorrectionsCallback.h"
+#include <log/log.h>
+
+android::binder::Status MeasurementCorrectionsCallback::setCapabilitiesCb(const int capabilities) {
+    ALOGI("Capabilities received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/MeasurementCorrectionsCallback.h b/gnss/aidl/vts/MeasurementCorrectionsCallback.h
new file mode 100644
index 0000000..27e5b3c
--- /dev/null
+++ b/gnss/aidl/vts/MeasurementCorrectionsCallback.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsCallback.h>
+#include "GnssCallbackEventQueue.h"
+
+class MeasurementCorrectionsCallback
+    : public android::hardware::gnss::measurement_corrections::BnMeasurementCorrectionsCallback {
+  public:
+    MeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
+    ~MeasurementCorrectionsCallback(){};
+    android::binder::Status setCapabilitiesCb(const int capabilities) override;
+
+    android::hardware::gnss::common::GnssCallbackEventQueue<int> capabilities_cbq_;
+    int last_capabilities_;
+};
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index 2447bf8..13c32ee 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -14,20 +14,31 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "GnssHalTest"
+
 #include "gnss_hal_test.h"
 #include <hidl/ServiceManagement.h>
+#include "Utils.h"
 
-using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::GnssLocation;
+using android::hardware::gnss::IGnss;
+using android::hardware::gnss::IGnssCallback;
+using android::hardware::gnss::common::Utils;
+using GnssConstellationTypeV2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 
 void GnssHalTest::SetUp() {
     // Get AIDL handle
     aidl_gnss_hal_ = android::waitForDeclaredService<IGnssAidl>(String16(GetParam().c_str()));
     ASSERT_NE(aidl_gnss_hal_, nullptr);
+    ALOGD("AIDL Interface Version = %d", aidl_gnss_hal_->getInterfaceVersion());
 
-    const auto& hidlInstanceNames = android::hardware::getAllHalInstanceNames(
-            android::hardware::gnss::V2_1::IGnss::descriptor);
-    gnss_hal_ = IGnss_V2_1::getService(hidlInstanceNames[0]);
-    ASSERT_NE(gnss_hal_, nullptr);
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        const auto& hidlInstanceNames = android::hardware::getAllHalInstanceNames(
+                android::hardware::gnss::V2_1::IGnss::descriptor);
+        gnss_hal_ = IGnss_V2_1::getService(hidlInstanceNames[0]);
+        ASSERT_NE(gnss_hal_, nullptr);
+    }
 
     SetUpGnssCallback();
 }
@@ -40,7 +51,6 @@
     if (!status.isOk()) {
         ALOGE("Failed to setCallback");
     }
-
     ASSERT_TRUE(status.isOk());
 
     /*
@@ -48,9 +58,243 @@
      */
     EXPECT_TRUE(aidl_gnss_cb_->capabilities_cbq_.retrieve(aidl_gnss_cb_->last_capabilities_,
                                                           TIMEOUT_SEC));
-
     EXPECT_EQ(aidl_gnss_cb_->capabilities_cbq_.calledCount(), 1);
 
-    // Invoke the super method.
-    GnssHalTestTemplate<IGnss_V2_1>::SetUpGnssCallback();
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        // Invoke the super method.
+        GnssHalTestTemplate<IGnss_V2_1>::SetUpGnssCallback();
+    }
+}
+
+void GnssHalTest::CheckLocation(const GnssLocation& location, bool check_speed) {
+    Utils::checkLocation(location, check_speed, /* check_more_accuracies= */ true);
+}
+
+void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        // Invoke the super method.
+        return GnssHalTestTemplate<IGnss_V2_1>::SetPositionMode(min_interval_msec, low_power_mode);
+    }
+
+    const int kPreferredAccuracy = 0;  // Ideally perfect (matches GnssLocationProvider)
+    const int kPreferredTimeMsec = 0;  // Ideally immediate
+
+    auto status = aidl_gnss_hal_->setPositionMode(
+            IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
+            min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
+
+    ASSERT_TRUE(status.isOk());
+}
+
+bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
+                                             const bool low_power_mode) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        // Invoke the super method.
+        return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckFirstLocation(min_interval_msec,
+                                                                           low_power_mode);
+    }
+
+    SetPositionMode(min_interval_msec, low_power_mode);
+    auto result = aidl_gnss_hal_->start();
+
+    EXPECT_TRUE(result.isOk());
+
+    /*
+     * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
+     * so allow time to demodulate ephemeris over the air.
+     */
+    const int kFirstGnssLocationTimeoutSeconds = 75;
+
+    EXPECT_TRUE(aidl_gnss_cb_->location_cbq_.retrieve(aidl_gnss_cb_->last_location_,
+                                                      kFirstGnssLocationTimeoutSeconds));
+    int locationCalledCount = aidl_gnss_cb_->location_cbq_.calledCount();
+    EXPECT_EQ(locationCalledCount, 1);
+
+    if (locationCalledCount > 0) {
+        // don't require speed on first fix
+        CheckLocation(aidl_gnss_cb_->last_location_, false);
+        return true;
+    }
+    return false;
+}
+
+void GnssHalTest::StopAndClearLocations() {
+    ALOGD("StopAndClearLocations");
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        // Invoke the super method.
+        return GnssHalTestTemplate<IGnss_V2_1>::StopAndClearLocations();
+    }
+
+    auto status = aidl_gnss_hal_->stop();
+    EXPECT_TRUE(status.isOk());
+
+    /*
+     * Clear notify/waiting counter, allowing up till the timeout after
+     * the last reply for final startup messages to arrive (esp. system
+     * info.)
+     */
+    while (aidl_gnss_cb_->location_cbq_.retrieve(aidl_gnss_cb_->last_location_, TIMEOUT_SEC)) {
+    }
+    aidl_gnss_cb_->location_cbq_.reset();
+}
+
+void GnssHalTest::StartAndCheckLocations(int count) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        // Invoke the super method.
+        return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckLocations(count);
+    }
+    const int kMinIntervalMsec = 500;
+    const int kLocationTimeoutSubsequentSec = 2;
+    const bool kLowPowerMode = false;
+
+    EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode));
+
+    for (int i = 1; i < count; i++) {
+        EXPECT_TRUE(aidl_gnss_cb_->location_cbq_.retrieve(aidl_gnss_cb_->last_location_,
+                                                          kLocationTimeoutSubsequentSec));
+        int locationCalledCount = aidl_gnss_cb_->location_cbq_.calledCount();
+        EXPECT_EQ(locationCalledCount, i + 1);
+        // Don't cause confusion by checking details if no location yet
+        if (locationCalledCount > 0) {
+            // Should be more than 1 location by now, but if not, still don't check first fix speed
+            CheckLocation(aidl_gnss_cb_->last_location_, locationCalledCount > 1);
+        }
+    }
+}
+
+std::list<std::vector<IGnssCallback::GnssSvInfo>> GnssHalTest::convertToAidl(
+        const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>>& sv_info_list) {
+    std::list<std::vector<IGnssCallback::GnssSvInfo>> aidl_sv_info_list;
+    for (const auto& sv_info_vec : sv_info_list) {
+        std::vector<IGnssCallback::GnssSvInfo> aidl_sv_info_vec;
+        for (const auto& sv_info : sv_info_vec) {
+            IGnssCallback::GnssSvInfo aidl_sv_info;
+            aidl_sv_info.svid = sv_info.v2_0.v1_0.svid;
+            aidl_sv_info.constellation =
+                    static_cast<GnssConstellationType>(sv_info.v2_0.constellation);
+            aidl_sv_info.cN0Dbhz = sv_info.v2_0.v1_0.cN0Dbhz;
+            aidl_sv_info.basebandCN0DbHz = sv_info.basebandCN0DbHz;
+            aidl_sv_info.elevationDegrees = sv_info.v2_0.v1_0.elevationDegrees;
+            aidl_sv_info.azimuthDegrees = sv_info.v2_0.v1_0.azimuthDegrees;
+            aidl_sv_info.carrierFrequencyHz = (int64_t)sv_info.v2_0.v1_0.carrierFrequencyHz;
+            aidl_sv_info.svFlag = (int)sv_info.v2_0.v1_0.svFlag;
+            aidl_sv_info_vec.push_back(aidl_sv_info);
+        }
+        aidl_sv_info_list.push_back(aidl_sv_info_vec);
+    }
+    return aidl_sv_info_list;
+}
+
+/*
+ * FindStrongFrequentNonGpsSource:
+ *
+ * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
+ *
+ * returns the strongest source,
+ *         or a source with constellation == UNKNOWN if none are found sufficient times
+ */
+BlocklistedSource GnssHalTest::FindStrongFrequentNonGpsSource(
+        const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
+        const int min_observations) {
+    return FindStrongFrequentNonGpsSource(convertToAidl(sv_info_list), min_observations);
+}
+
+BlocklistedSource GnssHalTest::FindStrongFrequentNonGpsSource(
+        const std::list<std::vector<IGnssCallback::GnssSvInfo>> sv_info_list,
+        const int min_observations) {
+    std::map<ComparableBlocklistedSource, SignalCounts> mapSignals;
+
+    for (const auto& sv_info_vec : sv_info_list) {
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            if ((gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.constellation != GnssConstellationType::GPS)) {
+                ComparableBlocklistedSource source;
+                source.id.svid = gnss_sv.svid;
+                source.id.constellation = gnss_sv.constellation;
+
+                const auto& itSignal = mapSignals.find(source);
+                if (itSignal == mapSignals.end()) {
+                    SignalCounts counts;
+                    counts.observations = 1;
+                    counts.max_cn0_dbhz = gnss_sv.cN0Dbhz;
+                    mapSignals.insert(
+                            std::pair<ComparableBlocklistedSource, SignalCounts>(source, counts));
+                } else {
+                    itSignal->second.observations++;
+                    if (itSignal->second.max_cn0_dbhz < gnss_sv.cN0Dbhz) {
+                        itSignal->second.max_cn0_dbhz = gnss_sv.cN0Dbhz;
+                    }
+                }
+            }
+        }
+    }
+
+    float max_cn0_dbhz_with_sufficient_count = 0.;
+    int total_observation_count = 0;
+    int blocklisted_source_count_observation = 0;
+
+    ComparableBlocklistedSource source_to_blocklist;  // initializes to zero = UNKNOWN constellation
+    for (auto const& pairSignal : mapSignals) {
+        total_observation_count += pairSignal.second.observations;
+        if ((pairSignal.second.observations >= min_observations) &&
+            (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
+            source_to_blocklist = pairSignal.first;
+            blocklisted_source_count_observation = pairSignal.second.observations;
+            max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
+        }
+    }
+    ALOGD("Among %d observations, chose svid %d, constellation %d, "
+          "with %d observations at %.1f max CNo",
+          total_observation_count, source_to_blocklist.id.svid,
+          (int)source_to_blocklist.id.constellation, blocklisted_source_count_observation,
+          max_cn0_dbhz_with_sufficient_count);
+
+    return source_to_blocklist.id;
+}
+
+GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
+        const int locations_to_await, const int gnss_sv_info_list_timeout) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return static_cast<GnssConstellationType>(
+                GnssHalTestTemplate<IGnss_V2_1>::startLocationAndGetNonGpsConstellation(
+                        locations_to_await, gnss_sv_info_list_timeout));
+    }
+    aidl_gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(locations_to_await);
+    const int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = aidl_gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, locations_to_await);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, locations_to_await, location_called_count);
+
+    // Find first non-GPS constellation to blocklist
+    GnssConstellationType constellation_to_blocklist = GnssConstellationType::UNKNOWN;
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        std::vector<IGnssCallback::GnssSvInfo> sv_info_vec;
+        aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, gnss_sv_info_list_timeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            auto& gnss_sv = sv_info_vec[iSv];
+            if ((gnss_sv.svFlag & (uint32_t)IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
+                (gnss_sv.constellation != GnssConstellationType::GPS)) {
+                // found a non-GPS constellation
+                constellation_to_blocklist = gnss_sv.constellation;
+                break;
+            }
+        }
+        if (constellation_to_blocklist != GnssConstellationType::UNKNOWN) {
+            break;
+        }
+    }
+
+    if (constellation_to_blocklist == GnssConstellationType::UNKNOWN) {
+        ALOGI("No non-GPS constellations found, constellation blocklist test less effective.");
+        // Proceed functionally to blocklist something.
+        constellation_to_blocklist = GnssConstellationType::GLONASS;
+    }
+
+    return constellation_to_blocklist;
 }
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index e3ecbed..d479af3 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -41,9 +41,50 @@
   public:
     GnssHalTest(){};
     ~GnssHalTest(){};
+
+    struct ComparableBlocklistedSource {
+        android::hardware::gnss::BlocklistedSource id;
+
+        ComparableBlocklistedSource() {
+            id.constellation = android::hardware::gnss::GnssConstellationType::UNKNOWN;
+            id.svid = 0;
+        }
+
+        bool operator<(const ComparableBlocklistedSource& compare) const {
+            return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
+                                                    (id.constellation < compare.id.constellation)));
+        }
+    };
+
+    struct SignalCounts {
+        int observations;
+        float max_cn0_dbhz;
+    };
+
     virtual void SetUp() override;
     virtual void SetUpGnssCallback() override;
 
+    void CheckLocation(const android::hardware::gnss::GnssLocation& location,
+                       const bool check_speed);
+    void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
+    bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode);
+    void StopAndClearLocations();
+    void StartAndCheckLocations(int count);
+
+    android::hardware::gnss::GnssConstellationType startLocationAndGetNonGpsConstellation(
+            const int locations_to_await, const int gnss_sv_info_list_timeout);
+    std::list<std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>> convertToAidl(
+            const std::list<hidl_vec<android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>>&
+                    sv_info_list);
+    android::hardware::gnss::BlocklistedSource FindStrongFrequentNonGpsSource(
+            const std::list<hidl_vec<android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>>
+                    sv_info_list,
+            const int min_observations);
+    android::hardware::gnss::BlocklistedSource FindStrongFrequentNonGpsSource(
+            const std::list<std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>>
+                    sv_info_list,
+            const int min_observations);
+
     sp<IGnssAidl> aidl_gnss_hal_;
     sp<GnssCallbackAidl> aidl_gnss_cb_;  // Primary callback interface
 };
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 830922c..1fa6825 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -16,17 +16,29 @@
 
 #define LOG_TAG "GnssHalTestCases"
 
+#include <android/hardware/gnss/IAGnss.h>
 #include <android/hardware/gnss/IGnss.h>
+#include <android/hardware/gnss/IGnssAntennaInfo.h>
 #include <android/hardware/gnss/IGnssBatching.h>
+#include <android/hardware/gnss/IGnssDebug.h>
 #include <android/hardware/gnss/IGnssMeasurementCallback.h>
 #include <android/hardware/gnss/IGnssMeasurementInterface.h>
 #include <android/hardware/gnss/IGnssPowerIndication.h>
 #include <android/hardware/gnss/IGnssPsds.h>
+#include <android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.h>
+#include <android/hardware/gnss/visibility_control/IGnssVisibilityControl.h>
+#include <cutils/properties.h>
+#include "AGnssCallbackAidl.h"
+#include "AGnssRilCallbackAidl.h"
+#include "GnssAntennaInfoCallbackAidl.h"
 #include "GnssBatchingCallback.h"
 #include "GnssGeofenceCallback.h"
 #include "GnssMeasurementCallbackAidl.h"
 #include "GnssNavigationMessageCallback.h"
 #include "GnssPowerIndicationCallback.h"
+#include "GnssVisibilityControlCallback.h"
+#include "MeasurementCorrectionsCallback.h"
+#include "Utils.h"
 #include "gnss_hal_test.h"
 
 using android::sp;
@@ -36,10 +48,16 @@
 using android::hardware::gnss::GnssData;
 using android::hardware::gnss::GnssMeasurement;
 using android::hardware::gnss::GnssPowerStats;
+using android::hardware::gnss::IAGnss;
+using android::hardware::gnss::IAGnssRil;
 using android::hardware::gnss::IGnss;
+using android::hardware::gnss::IGnssAntennaInfo;
+using android::hardware::gnss::IGnssAntennaInfoCallback;
 using android::hardware::gnss::IGnssBatching;
 using android::hardware::gnss::IGnssBatchingCallback;
+using android::hardware::gnss::IGnssCallback;
 using android::hardware::gnss::IGnssConfiguration;
+using android::hardware::gnss::IGnssDebug;
 using android::hardware::gnss::IGnssGeofence;
 using android::hardware::gnss::IGnssGeofenceCallback;
 using android::hardware::gnss::IGnssMeasurementCallback;
@@ -49,9 +67,19 @@
 using android::hardware::gnss::IGnssPsds;
 using android::hardware::gnss::PsdsType;
 using android::hardware::gnss::SatellitePvt;
+using android::hardware::gnss::common::Utils;
+using android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface;
+using android::hardware::gnss::visibility_control::IGnssVisibilityControl;
 
+using GnssConstellationTypeV2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
 
+static bool IsAutomotiveDevice() {
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
 /*
  * SetupTeardownCreateCleanup:
  * Requests the gnss HAL then calls cleanup
@@ -309,7 +337,11 @@
     auto powerStats1 = gnssPowerIndicationCallback->last_gnss_power_stats_;
 
     // Get a location and request another GnssPowerStats
-    gnss_cb_->location_cbq_.reset();
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        gnss_cb_->location_cbq_.reset();
+    } else {
+        aidl_gnss_cb_->location_cbq_.reset();
+    }
     StartAndCheckFirstLocation(/* min_interval_msec= */ 1000, /* low_power_mode= */ false);
 
     // Request and verify the 2nd GnssPowerStats has larger values than the 1st one
@@ -360,88 +392,6 @@
 }
 
 /*
- * FindStrongFrequentNonGpsSource:
- *
- * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
- *
- * returns the strongest source,
- *         or a source with constellation == UNKNOWN if none are found sufficient times
- */
-BlocklistedSource FindStrongFrequentNonGpsSource(
-        const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
-        const int min_observations) {
-    struct ComparableBlocklistedSource {
-        BlocklistedSource id;
-
-        ComparableBlocklistedSource() {
-            id.constellation = GnssConstellationTypeAidl::UNKNOWN;
-            id.svid = 0;
-        }
-
-        bool operator<(const ComparableBlocklistedSource& compare) const {
-            return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
-                                                    (id.constellation < compare.id.constellation)));
-        }
-    };
-
-    struct SignalCounts {
-        int observations;
-        float max_cn0_dbhz;
-    };
-
-    std::map<ComparableBlocklistedSource, SignalCounts> mapSignals;
-
-    for (const auto& sv_info_vec : sv_info_list) {
-        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
-            const auto& gnss_sv = sv_info_vec[iSv];
-            if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
-                (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
-                ComparableBlocklistedSource source;
-                source.id.svid = gnss_sv.v2_0.v1_0.svid;
-                source.id.constellation =
-                        static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation);
-
-                const auto& itSignal = mapSignals.find(source);
-                if (itSignal == mapSignals.end()) {
-                    SignalCounts counts;
-                    counts.observations = 1;
-                    counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
-                    mapSignals.insert(
-                            std::pair<ComparableBlocklistedSource, SignalCounts>(source, counts));
-                } else {
-                    itSignal->second.observations++;
-                    if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) {
-                        itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
-                    }
-                }
-            }
-        }
-    }
-
-    float max_cn0_dbhz_with_sufficient_count = 0.;
-    int total_observation_count = 0;
-    int blocklisted_source_count_observation = 0;
-
-    ComparableBlocklistedSource source_to_blocklist;  // initializes to zero = UNKNOWN constellation
-    for (auto const& pairSignal : mapSignals) {
-        total_observation_count += pairSignal.second.observations;
-        if ((pairSignal.second.observations >= min_observations) &&
-            (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
-            source_to_blocklist = pairSignal.first;
-            blocklisted_source_count_observation = pairSignal.second.observations;
-            max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
-        }
-    }
-    ALOGD("Among %d observations, chose svid %d, constellation %d, "
-          "with %d observations at %.1f max CNo",
-          total_observation_count, source_to_blocklist.id.svid,
-          (int)source_to_blocklist.id.constellation, blocklisted_source_count_observation,
-          max_cn0_dbhz_with_sufficient_count);
-
-    return source_to_blocklist.id;
-}
-
-/*
  * BlocklistIndividualSatellites:
  *
  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
@@ -466,12 +416,20 @@
     const int kLocationsToAwait = 3;
     const int kRetriesToUnBlocklist = 10;
 
-    gnss_cb_->location_cbq_.reset();
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        gnss_cb_->location_cbq_.reset();
+    } else {
+        aidl_gnss_cb_->location_cbq_.reset();
+    }
     StartAndCheckLocations(kLocationsToAwait);
-    int location_called_count = gnss_cb_->location_cbq_.calledCount();
+    int location_called_count = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                        ? gnss_cb_->location_cbq_.calledCount()
+                                        : aidl_gnss_cb_->location_cbq_.calledCount();
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    int sv_info_list_cbq_size = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                        ? gnss_cb_->sv_info_list_cbq_.size()
+                                        : aidl_gnss_cb_->sv_info_list_cbq_.size();
     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
           sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
@@ -483,14 +441,22 @@
      */
 
     const int kGnssSvInfoListTimeout = 2;
-    std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
-    int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
-                                                     kGnssSvInfoListTimeout);
-
-    ASSERT_EQ(count, sv_info_list_cbq_size);
-
-    BlocklistedSource source_to_blocklist =
-            FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+    BlocklistedSource source_to_blocklist;
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
+        int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
+                                                         kGnssSvInfoListTimeout);
+        ASSERT_EQ(count, sv_info_list_cbq_size);
+        source_to_blocklist =
+                FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+    } else {
+        std::list<std::vector<IGnssCallback::GnssSvInfo>> sv_info_vec_list;
+        int count = aidl_gnss_cb_->sv_info_list_cbq_.retrieve(
+                sv_info_vec_list, sv_info_list_cbq_size, kGnssSvInfoListTimeout);
+        ASSERT_EQ(count, sv_info_list_cbq_size);
+        source_to_blocklist =
+                FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+    }
 
     if (source_to_blocklist.constellation == GnssConstellationTypeAidl::UNKNOWN) {
         // Cannot find a non-GPS satellite. Let the test pass.
@@ -514,32 +480,53 @@
     ASSERT_TRUE(status.isOk());
 
     // retry and ensure satellite not used
-    gnss_cb_->sv_info_list_cbq_.reset();
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        gnss_cb_->sv_info_list_cbq_.reset();
+        gnss_cb_->location_cbq_.reset();
+    } else {
+        aidl_gnss_cb_->sv_info_list_cbq_.reset();
+        aidl_gnss_cb_->location_cbq_.reset();
+    }
 
-    gnss_cb_->location_cbq_.reset();
     StartAndCheckLocations(kLocationsToAwait);
 
     // early exit if test is being run with insufficient signal
-    location_called_count = gnss_cb_->location_cbq_.calledCount();
+    location_called_count = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                    ? gnss_cb_->location_cbq_.calledCount()
+                                    : aidl_gnss_cb_->location_cbq_.calledCount();
     if (location_called_count == 0) {
         ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
     }
     ASSERT_TRUE(location_called_count > 0);
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    sv_info_list_cbq_size = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                    ? gnss_cb_->sv_info_list_cbq_.size()
+                                    : aidl_gnss_cb_->sv_info_list_cbq_.size();
     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
           sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
-        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
-        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
-        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
-            const auto& gnss_sv = sv_info_vec[iSv];
-            EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
-                         (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
-                          source_to_blocklist.constellation) &&
-                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+            hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+            gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                auto& gnss_sv = sv_info_vec[iSv];
+                EXPECT_FALSE(
+                        (gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
+                        (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                         source_to_blocklist.constellation) &&
+                        (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+            }
+        } else {
+            std::vector<IGnssCallback::GnssSvInfo> sv_info_vec;
+            aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                auto& gnss_sv = sv_info_vec[iSv];
+                EXPECT_FALSE((gnss_sv.svid == source_to_blocklist.svid) &&
+                             (gnss_sv.constellation == source_to_blocklist.constellation) &&
+                             (gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX));
+            }
         }
     }
 
@@ -554,36 +541,59 @@
     int unblocklist_loops_remaining = kRetriesToUnBlocklist;
     while (!strongest_sv_is_reobserved && (unblocklist_loops_remaining-- > 0)) {
         StopAndClearLocations();
-        gnss_cb_->sv_info_list_cbq_.reset();
 
-        gnss_cb_->location_cbq_.reset();
+        if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+            gnss_cb_->sv_info_list_cbq_.reset();
+            gnss_cb_->location_cbq_.reset();
+        } else {
+            aidl_gnss_cb_->sv_info_list_cbq_.reset();
+            aidl_gnss_cb_->location_cbq_.reset();
+        }
         StartAndCheckLocations(kLocationsToAwait);
 
         // early exit loop if test is being run with insufficient signal
-        location_called_count = gnss_cb_->location_cbq_.calledCount();
+        location_called_count = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                        ? gnss_cb_->location_cbq_.calledCount()
+                                        : aidl_gnss_cb_->location_cbq_.calledCount();
         if (location_called_count == 0) {
             ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
         }
         ASSERT_TRUE(location_called_count > 0);
 
         // Tolerate 1 less sv status to handle edge cases in reporting.
-        sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+        sv_info_list_cbq_size = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                        ? gnss_cb_->sv_info_list_cbq_.size()
+                                        : aidl_gnss_cb_->sv_info_list_cbq_.size();
         EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
         ALOGD("Clear blocklist, observed %d GnssSvInfo, while awaiting %d Locations"
               ", tries remaining %d",
               sv_info_list_cbq_size, kLocationsToAwait, unblocklist_loops_remaining);
 
         for (int i = 0; i < sv_info_list_cbq_size; ++i) {
-            hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
-            gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
-            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
-                const auto& gnss_sv = sv_info_vec[iSv];
-                if ((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
-                    (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
-                     source_to_blocklist.constellation) &&
-                    (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
-                    strongest_sv_is_reobserved = true;
-                    break;
+            if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+                hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+                gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+                for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                    auto& gnss_sv = sv_info_vec[iSv];
+                    if ((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
+                        (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                         source_to_blocklist.constellation) &&
+                        (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
+                        strongest_sv_is_reobserved = true;
+                        break;
+                    }
+                }
+            } else {
+                std::vector<IGnssCallback::GnssSvInfo> sv_info_vec;
+                aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+                for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                    auto& gnss_sv = sv_info_vec[iSv];
+                    if ((gnss_sv.svid == source_to_blocklist.svid) &&
+                        (gnss_sv.constellation == source_to_blocklist.constellation) &&
+                        (gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
+                        strongest_sv_is_reobserved = true;
+                        break;
+                    }
                 }
             }
             if (strongest_sv_is_reobserved) break;
@@ -645,27 +655,47 @@
     ASSERT_TRUE(status.isOk());
 
     // retry and ensure constellation not used
-    gnss_cb_->sv_info_list_cbq_.reset();
-
-    gnss_cb_->location_cbq_.reset();
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        gnss_cb_->sv_info_list_cbq_.reset();
+        gnss_cb_->location_cbq_.reset();
+    } else {
+        aidl_gnss_cb_->sv_info_list_cbq_.reset();
+        aidl_gnss_cb_->location_cbq_.reset();
+    }
     StartAndCheckLocations(kLocationsToAwait);
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    int sv_info_list_cbq_size = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                        ? gnss_cb_->sv_info_list_cbq_.size()
+                                        : aidl_gnss_cb_->sv_info_list_cbq_.size();
     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
           kLocationsToAwait);
     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
-        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
-        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
-        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
-            const auto& gnss_sv = sv_info_vec[iSv];
-            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
-                          source_to_blocklist_1.constellation) &&
-                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
-            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
-                          source_to_blocklist_2.constellation) &&
-                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+            hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+            gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                const auto& gnss_sv = sv_info_vec[iSv];
+                EXPECT_FALSE(
+                        (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                         source_to_blocklist_1.constellation) &&
+                        (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+                EXPECT_FALSE(
+                        (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                         source_to_blocklist_2.constellation) &&
+                        (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+            }
+        } else {
+            std::vector<IGnssCallback::GnssSvInfo> sv_info_vec;
+            aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                const auto& gnss_sv = sv_info_vec[iSv];
+                EXPECT_FALSE((gnss_sv.constellation == source_to_blocklist_1.constellation) &&
+                             (gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX));
+                EXPECT_FALSE((gnss_sv.constellation == source_to_blocklist_2.constellation) &&
+                             (gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX));
+            }
         }
     }
 
@@ -728,27 +758,47 @@
     StopAndClearLocations();
 
     // retry and ensure constellation not used
-    gnss_cb_->sv_info_list_cbq_.reset();
-
-    gnss_cb_->location_cbq_.reset();
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        gnss_cb_->sv_info_list_cbq_.reset();
+        gnss_cb_->location_cbq_.reset();
+    } else {
+        aidl_gnss_cb_->sv_info_list_cbq_.reset();
+        aidl_gnss_cb_->location_cbq_.reset();
+    }
     StartAndCheckLocations(kLocationsToAwait);
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    int sv_info_list_cbq_size = (aidl_gnss_hal_->getInterfaceVersion() == 1)
+                                        ? gnss_cb_->sv_info_list_cbq_.size()
+                                        : aidl_gnss_cb_->sv_info_list_cbq_.size();
     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
           kLocationsToAwait);
     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
-        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
-        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
-        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
-            const auto& gnss_sv = sv_info_vec[iSv];
-            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
-                          source_to_blocklist_1.constellation) &&
-                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
-            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
-                          source_to_blocklist_2.constellation) &&
-                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+            hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+            gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                const auto& gnss_sv = sv_info_vec[iSv];
+                EXPECT_FALSE(
+                        (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                         source_to_blocklist_1.constellation) &&
+                        (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+                EXPECT_FALSE(
+                        (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                         source_to_blocklist_2.constellation) &&
+                        (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+            }
+        } else {
+            std::vector<IGnssCallback::GnssSvInfo> sv_info_vec;
+            aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                const auto& gnss_sv = sv_info_vec[iSv];
+                EXPECT_FALSE((gnss_sv.constellation == source_to_blocklist_1.constellation) &&
+                             (gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX));
+                EXPECT_FALSE((gnss_sv.constellation == source_to_blocklist_2.constellation) &&
+                             (gnss_sv.svFlag & (int)IGnssCallback::GnssSvFlags::USED_IN_FIX));
+            }
         }
     }
 
@@ -763,6 +813,10 @@
  * TestAllExtensions.
  */
 TEST_P(GnssHalTest, TestAllExtensions) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+
     sp<IGnssBatching> iGnssBatching;
     auto status = aidl_gnss_hal_->getExtensionGnssBatching(&iGnssBatching);
     if (status.isOk() && iGnssBatching != nullptr) {
@@ -793,3 +847,337 @@
         ASSERT_TRUE(status.isOk());
     }
 }
+
+/*
+ * TestAGnssExtension:
+ * 1. Gets the IAGnss extension.
+ * 2. Sets AGnssCallback.
+ * 3. Sets SUPL server host/port.
+ */
+TEST_P(GnssHalTest, TestAGnssExtension) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    sp<IAGnss> iAGnss;
+    auto status = aidl_gnss_hal_->getExtensionAGnss(&iAGnss);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iAGnss != nullptr);
+
+    auto agnssCallback = sp<AGnssCallbackAidl>::make();
+    status = iAGnss->setCallback(agnssCallback);
+    ASSERT_TRUE(status.isOk());
+
+    // Set SUPL server host/port
+    status = iAGnss->setServer(AGnssType::SUPL, std::string("supl.google.com"), 7275);
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * TestAGnssRilExtension:
+ * 1. Gets the IAGnssRil extension.
+ * 2. Sets AGnssRilCallback.
+ * 3. Sets reference location.
+ */
+TEST_P(GnssHalTest, TestAGnssRilExtension) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    sp<IAGnssRil> iAGnssRil;
+    auto status = aidl_gnss_hal_->getExtensionAGnssRil(&iAGnssRil);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iAGnssRil != nullptr);
+
+    auto agnssRilCallback = sp<AGnssRilCallbackAidl>::make();
+    status = iAGnssRil->setCallback(agnssRilCallback);
+    ASSERT_TRUE(status.isOk());
+
+    // Set RefLocation
+    IAGnssRil::AGnssRefLocationCellID agnssReflocationCellId;
+    agnssReflocationCellId.type = IAGnssRil::AGnssRefLocationType::LTE_CELLID;
+    agnssReflocationCellId.mcc = 466;
+    agnssReflocationCellId.mnc = 97;
+    agnssReflocationCellId.lac = 46697;
+    agnssReflocationCellId.cid = 59168142;
+    agnssReflocationCellId.pcid = 420;
+    agnssReflocationCellId.tac = 11460;
+    IAGnssRil::AGnssRefLocation agnssReflocation;
+    agnssReflocation.type = IAGnssRil::AGnssRefLocationType::LTE_CELLID;
+    agnssReflocation.cellID = agnssReflocationCellId;
+
+    status = iAGnssRil->setRefLocation(agnssReflocation);
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * GnssDebugValuesSanityTest:
+ * Ensures that GnssDebug values make sense.
+ */
+TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    sp<IGnssDebug> iGnssDebug;
+    auto status = aidl_gnss_hal_->getExtensionGnssDebug(&iGnssDebug);
+    ASSERT_TRUE(status.isOk());
+
+    if (!IsAutomotiveDevice()) {
+        ASSERT_TRUE(iGnssDebug != nullptr);
+
+        IGnssDebug::DebugData data;
+        auto status = iGnssDebug->getDebugData(&data);
+        ASSERT_TRUE(status.isOk());
+
+        if (data.position.valid) {
+            ASSERT_TRUE(data.position.latitudeDegrees >= -90 &&
+                        data.position.latitudeDegrees <= 90);
+            ASSERT_TRUE(data.position.longitudeDegrees >= -180 &&
+                        data.position.longitudeDegrees <= 180);
+            ASSERT_TRUE(data.position.altitudeMeters >= -1000 &&  // Dead Sea: -414m
+                        data.position.altitudeMeters <= 20000);   // Mount Everest: 8850m
+            ASSERT_TRUE(data.position.speedMetersPerSec >= 0 &&
+                        data.position.speedMetersPerSec <= 600);
+            ASSERT_TRUE(data.position.bearingDegrees >= -360 &&
+                        data.position.bearingDegrees <= 360);
+            ASSERT_TRUE(data.position.horizontalAccuracyMeters > 0 &&
+                        data.position.horizontalAccuracyMeters <= 20000000);
+            ASSERT_TRUE(data.position.verticalAccuracyMeters > 0 &&
+                        data.position.verticalAccuracyMeters <= 20000);
+            ASSERT_TRUE(data.position.speedAccuracyMetersPerSecond > 0 &&
+                        data.position.speedAccuracyMetersPerSecond <= 500);
+            ASSERT_TRUE(data.position.bearingAccuracyDegrees > 0 &&
+                        data.position.bearingAccuracyDegrees <= 180);
+            ASSERT_TRUE(data.position.ageSeconds >= 0);
+        }
+        ASSERT_TRUE(data.time.timeEstimateMs >= 1483228800000);  // Jan 01 2017 00:00:00 GMT.
+        ASSERT_TRUE(data.time.timeUncertaintyNs > 0);
+        ASSERT_TRUE(data.time.frequencyUncertaintyNsPerSec > 0 &&
+                    data.time.frequencyUncertaintyNsPerSec <= 2.0e5);  // 200 ppm
+    }
+}
+
+/*
+ * TestGnssVisibilityControlExtension:
+ * 1. Gets the IGnssVisibilityControl extension.
+ * 2. Sets GnssVisibilityControlCallback
+ * 3. Sets proxy apps
+ */
+TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    sp<IGnssVisibilityControl> iGnssVisibilityControl;
+    auto status = aidl_gnss_hal_->getExtensionGnssVisibilityControl(&iGnssVisibilityControl);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssVisibilityControl != nullptr);
+    auto gnssVisibilityControlCallback = sp<GnssVisibilityControlCallback>::make();
+    status = iGnssVisibilityControl->setCallback(gnssVisibilityControlCallback);
+    ASSERT_TRUE(status.isOk());
+
+    std::vector<std::string> proxyApps{std::string("com.example.ims"),
+                                       std::string("com.example.mdt")};
+    status = iGnssVisibilityControl->enableNfwLocationAccess(proxyApps);
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * TestGnssMeasurementSetCallbackWithOptions:
+ * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
+ * 2. Sets a GnssMeasurementCallback with intervalMillis option, waits for measurements reported,
+ *    and verifies mandatory fields are valid.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementSetCallbackWithOptions) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    const int kFirstGnssMeasurementTimeoutSeconds = 10;
+    const int kNumMeasurementEvents = 5;
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    auto callback = sp<GnssMeasurementCallbackAidl>::make();
+    IGnssMeasurementInterface::Options options;
+    options.intervalMs = 2000;
+    status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+    ASSERT_TRUE(status.isOk());
+
+    for (int i = 0; i < kNumMeasurementEvents; i++) {
+        GnssData lastMeasurement;
+        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
+                                                      kFirstGnssMeasurementTimeoutSeconds));
+        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+
+        // Validity check GnssData fields
+        CheckGnssMeasurementClockFields(lastMeasurement);
+    }
+
+    status = iGnssMeasurement->close();
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * TestGnssAgcInGnssMeasurement:
+ * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
+ * 2. Sets a GnssMeasurementCallback, waits for a measurement.
+ */
+TEST_P(GnssHalTest, TestGnssAgcInGnssMeasurement) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    const int kFirstGnssMeasurementTimeoutSeconds = 10;
+    const int kNumMeasurementEvents = 15;
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    auto callback = sp<GnssMeasurementCallbackAidl>::make();
+    status = iGnssMeasurement->setCallback(callback, /* enableFullTracking= */ false,
+                                           /* enableCorrVecOutputs */ false);
+    ASSERT_TRUE(status.isOk());
+
+    for (int i = 0; i < kNumMeasurementEvents; i++) {
+        GnssData lastMeasurement;
+        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
+                                                      kFirstGnssMeasurementTimeoutSeconds));
+        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+
+        // Validity check GnssData fields
+        CheckGnssMeasurementClockFields(lastMeasurement);
+
+        ASSERT_TRUE(lastMeasurement.gnssAgcs.has_value());
+        for (const auto& gnssAgc : lastMeasurement.gnssAgcs.value()) {
+            ASSERT_TRUE(gnssAgc.has_value());
+            ASSERT_TRUE(gnssAgc.value().carrierFrequencyHz >= 0);
+        }
+    }
+
+    status = iGnssMeasurement->close();
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * TestGnssAntennaInfo:
+ * Sets a GnssAntennaInfoCallback, waits for report, and verifies
+ * 1. phaseCenterOffsetCoordinateMillimeters is valid
+ * 2. phaseCenterOffsetCoordinateUncertaintyMillimeters is valid.
+ * PhaseCenterVariationCorrections and SignalGainCorrections are optional.
+ */
+TEST_P(GnssHalTest, TestGnssAntennaInfo) {
+    const int kAntennaInfoTimeoutSeconds = 2;
+
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+
+    sp<IGnssAntennaInfo> iGnssAntennaInfo;
+    auto status = aidl_gnss_hal_->getExtensionGnssAntennaInfo(&iGnssAntennaInfo);
+    ASSERT_TRUE(status.isOk());
+
+    if (!(aidl_gnss_cb_->last_capabilities_ & (int)GnssCallbackAidl::CAPABILITY_ANTENNA_INFO) ||
+        iGnssAntennaInfo == nullptr) {
+        ALOGD("GnssAntennaInfo AIDL is not supported.");
+        return;
+    }
+
+    auto callback = sp<GnssAntennaInfoCallbackAidl>::make();
+    status = iGnssAntennaInfo->setCallback(callback);
+    ASSERT_TRUE(status.isOk());
+
+    std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo> antennaInfos;
+    ASSERT_TRUE(callback->antenna_info_cbq_.retrieve(antennaInfos, kAntennaInfoTimeoutSeconds));
+    EXPECT_EQ(callback->antenna_info_cbq_.calledCount(), 1);
+    ASSERT_TRUE(antennaInfos.size() > 0);
+
+    for (auto antennaInfo : antennaInfos) {
+        // Remaining fields are optional
+        if (!antennaInfo.phaseCenterVariationCorrectionMillimeters.empty()) {
+            int numRows = antennaInfo.phaseCenterVariationCorrectionMillimeters.size();
+            int numColumns = antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size();
+            // Must have at least 1 row and 2 columns
+            ASSERT_TRUE(numRows >= 1 && numColumns >= 2);
+
+            // Corrections and uncertainties must have same dimensions
+            ASSERT_TRUE(antennaInfo.phaseCenterVariationCorrectionMillimeters.size() ==
+                        antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.size());
+            ASSERT_TRUE(
+                    antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size() ==
+                    antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters[0].row.size());
+
+            // Must be rectangular
+            for (auto row : antennaInfo.phaseCenterVariationCorrectionMillimeters) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+            for (auto row : antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+        }
+        if (!antennaInfo.signalGainCorrectionDbi.empty()) {
+            int numRows = antennaInfo.signalGainCorrectionDbi.size();
+            int numColumns = antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size();
+            // Must have at least 1 row and 2 columns
+            ASSERT_TRUE(numRows >= 1 && numColumns >= 2);
+
+            // Corrections and uncertainties must have same dimensions
+            ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi.size() ==
+                        antennaInfo.signalGainCorrectionUncertaintyDbi.size());
+            ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi[0].row.size() ==
+                        antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size());
+
+            // Must be rectangular
+            for (auto row : antennaInfo.signalGainCorrectionDbi) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+            for (auto row : antennaInfo.signalGainCorrectionUncertaintyDbi) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+        }
+    }
+
+    iGnssAntennaInfo->close();
+}
+
+/*
+ * TestGnssMeasurementCorrections:
+ * If measurement corrections capability is supported, verifies that the measurement corrections
+ * capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH
+ * capability flag is set.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    if (!(aidl_gnss_cb_->last_capabilities_ &
+          (int)GnssCallbackAidl::CAPABILITY_MEASUREMENT_CORRECTIONS)) {
+        return;
+    }
+
+    sp<IMeasurementCorrectionsInterface> iMeasurementCorrectionsAidl;
+    auto status = aidl_gnss_hal_->getExtensionMeasurementCorrections(&iMeasurementCorrectionsAidl);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iMeasurementCorrectionsAidl != nullptr);
+
+    // Setup measurement corrections callback.
+    auto gnssMeasurementCorrectionsCallback = sp<MeasurementCorrectionsCallback>::make();
+    status = iMeasurementCorrectionsAidl->setCallback(gnssMeasurementCorrectionsCallback);
+    ASSERT_TRUE(status.isOk());
+
+    const int kTimeoutSec = 5;
+    EXPECT_TRUE(gnssMeasurementCorrectionsCallback->capabilities_cbq_.retrieve(
+            gnssMeasurementCorrectionsCallback->last_capabilities_, kTimeoutSec));
+    ASSERT_TRUE(gnssMeasurementCorrectionsCallback->capabilities_cbq_.calledCount() > 0);
+
+    ASSERT_TRUE((gnssMeasurementCorrectionsCallback->last_capabilities_ &
+                 (MeasurementCorrectionsCallback::CAPABILITY_LOS_SATS |
+                  MeasurementCorrectionsCallback::CAPABILITY_EXCESS_PATH_LENGTH)) != 0);
+
+    // Set a mock MeasurementCorrections.
+    status = iMeasurementCorrectionsAidl->setCorrections(
+            Utils::getMockMeasurementCorrections_aidl());
+    ASSERT_TRUE(status.isOk());
+}
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index 05bec88..b896f04 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -39,6 +39,7 @@
         "v2_1/GnssMeasurement.cpp",
         "v2_1/GnssMeasurementCorrections.cpp",
         "DeviceFileReader.cpp",
+        "FixLocationParser.cpp",
         "GnssRawMeasurementParser.cpp",
         "GnssReplayUtils.cpp",
         "MockLocation.cpp",
diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp
index 7d4fb04..dfc086a 100644
--- a/gnss/common/utils/default/DeviceFileReader.cpp
+++ b/gnss/common/utils/default/DeviceFileReader.cpp
@@ -22,8 +22,17 @@
 
 void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) {
     char inputBuffer[INPUT_BUFFER_SIZE];
-    int mGnssFd = open(ReplayUtils::getGnssPath().c_str(),
-                       O_RDWR | O_NONBLOCK);
+    std::string deviceFilePath = "";
+    if (command == CMD_GET_LOCATION) {
+        deviceFilePath = ReplayUtils::getFixedLocationPath();
+    } else if (command == CMD_GET_RAWMEASUREMENT) {
+        deviceFilePath = ReplayUtils::getGnssPath();
+    } else {
+        // Invalid command
+        return;
+    }
+
+    int mGnssFd = open(deviceFilePath.c_str(), O_RDWR | O_NONBLOCK);
 
     if (mGnssFd == -1) {
         return;
@@ -68,10 +77,13 @@
     }
 
     // Cache the injected data.
-    if (ReplayUtils::isGnssRawMeasurement(inputStr)) {
-        data_[CMD_GET_RAWMEASUREMENT] = inputStr;
-    } else if (ReplayUtils::isNMEA(inputStr)) {
+    if (command == CMD_GET_LOCATION) {
+        // TODO validate data
         data_[CMD_GET_LOCATION] = inputStr;
+    } else if (command == CMD_GET_RAWMEASUREMENT) {
+        if (ReplayUtils::isGnssRawMeasurement(inputStr)) {
+            data_[CMD_GET_RAWMEASUREMENT] = inputStr;
+        }
     }
 }
 
diff --git a/gnss/common/utils/default/FixLocationParser.cpp b/gnss/common/utils/default/FixLocationParser.cpp
new file mode 100644
index 0000000..f391d96
--- /dev/null
+++ b/gnss/common/utils/default/FixLocationParser.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include "FixLocationParser.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+using aidl::android::hardware::gnss::ElapsedRealtime;
+using aidl::android::hardware::gnss::GnssLocation;
+
+std::unique_ptr<GnssLocation> FixLocationParser::getLocationFromInputStr(
+        const std::string& locationStr) {
+    /*
+     * Fix,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps,
+     * AccuracyMeters,BearingDegrees,UnixTimeMillis,SpeedAccuracyMps,BearingAccuracyDegrees,
+     * elapsedRealtimeNanos
+     */
+    if (locationStr.empty()) {
+        return nullptr;
+    }
+    std::vector<std::string> locationStrRecords;
+    ParseUtils::splitStr(locationStr, LINE_SEPARATOR, locationStrRecords);
+    if (locationStrRecords.empty()) {
+        return nullptr;
+    }
+
+    std::vector<std::string> locationValues;
+    ParseUtils::splitStr(locationStrRecords[0], COMMA_SEPARATOR, locationValues);
+    if (locationValues.size() < 12) {
+        return nullptr;
+    }
+    ElapsedRealtime elapsedRealtime = {
+            .flags = ElapsedRealtime::HAS_TIMESTAMP_NS | ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS,
+            .timestampNs = ::android::elapsedRealtimeNano(),
+            // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+            // In an actual implementation provide an estimate of the synchronization uncertainty
+            // or don't set the field.
+            .timeUncertaintyNs = 1020400};
+
+    GnssLocation location = {
+            .gnssLocationFlags = 0xFF,
+            .latitudeDegrees = ParseUtils::tryParseDouble(locationValues[2], 0),
+            .longitudeDegrees = ParseUtils::tryParseDouble(locationValues[3], 0),
+            .altitudeMeters = ParseUtils::tryParseDouble(locationValues[4], 0),
+            .speedMetersPerSec = ParseUtils::tryParseDouble(locationValues[5], 0),
+            .bearingDegrees = ParseUtils::tryParseDouble(locationValues[7], 0),
+            .horizontalAccuracyMeters = ParseUtils::tryParseDouble(locationValues[6], 0),
+            .verticalAccuracyMeters = ParseUtils::tryParseDouble(locationValues[6], 0),
+            .speedAccuracyMetersPerSecond = ParseUtils::tryParseDouble(locationValues[9], 0),
+            .bearingAccuracyDegrees = ParseUtils::tryParseDouble(locationValues[10], 0),
+            .timestampMillis = ParseUtils::tryParseLongLong(locationValues[8], 0),
+            .elapsedRealtime = elapsedRealtime};
+    return std::make_unique<GnssLocation>(location);
+}
+
+}  // namespace common
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp
index e3f4ff8..37da571 100644
--- a/gnss/common/utils/default/GnssReplayUtils.cpp
+++ b/gnss/common/utils/default/GnssReplayUtils.cpp
@@ -29,11 +29,24 @@
     return GNSS_PATH;
 }
 
+std::string ReplayUtils::getFixedLocationPath() {
+    char devname_value[PROPERTY_VALUE_MAX] = "";
+    if (property_get("debug.location.fixedlocation.devname", devname_value, NULL) > 0) {
+        return devname_value;
+    }
+    return FIXED_LOCATION_PATH;
+}
+
 bool ReplayUtils::hasGnssDeviceFile() {
     struct stat sb;
     return stat(getGnssPath().c_str(), &sb) != -1;
 }
 
+bool ReplayUtils::hasFixedLocationDeviceFile() {
+    struct stat sb;
+    return stat(getFixedLocationPath().c_str(), &sb) != -1;
+}
+
 bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) {
     // TODO: add more logic check to by pass invalid data.
     return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos);
@@ -41,7 +54,7 @@
 
 bool ReplayUtils::isNMEA(const std::string& inputStr) {
     return !inputStr.empty() && (inputStr.find("$GPRMC,", 0) != std::string::npos ||
-                                 inputStr.find("$GPRMA,", 0) != std::string::npos);
+                                 inputStr.find("$GPGGA,", 0) != std::string::npos);
 }
 
 }  // namespace common
diff --git a/gnss/common/utils/default/NmeaFixInfo.cpp b/gnss/common/utils/default/NmeaFixInfo.cpp
index c7ee134..22aef90 100644
--- a/gnss/common/utils/default/NmeaFixInfo.cpp
+++ b/gnss/common/utils/default/NmeaFixInfo.cpp
@@ -34,6 +34,9 @@
 namespace gnss {
 namespace common {
 
+using aidl::android::hardware::gnss::ElapsedRealtime;
+using aidl::android::hardware::gnss::GnssLocation;
+
 NmeaFixInfo::NmeaFixInfo() : hasGMCRecord(false), hasGGARecord(false) {}
 
 float NmeaFixInfo::getAltitudeMeters() const {
@@ -237,6 +240,40 @@
 }
 
 /**
+ * Convert V2_0::GnssLocation to aidl::GnssLocation.
+ */
+std::unique_ptr<GnssLocation> NmeaFixInfo::getAidlLocationFromInputStr(
+        const std::string& inputStr) {
+    std::unique_ptr<V2_0::GnssLocation> locationV2 = getLocationFromInputStr(inputStr);
+    if (locationV2 == nullptr) {
+        return nullptr;
+    }
+
+    ElapsedRealtime elapsedRealtime = {
+            .flags = ElapsedRealtime::HAS_TIMESTAMP_NS | ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS,
+            .timestampNs = ::android::elapsedRealtimeNano(),
+            // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+            // In an actual implementation provide an estimate of the synchronization uncertainty
+            // or don't set the field.
+            .timeUncertaintyNs = 1020400};
+
+    GnssLocation location = {
+            .gnssLocationFlags = locationV2->v1_0.gnssLocationFlags,
+            .latitudeDegrees = locationV2->v1_0.latitudeDegrees,
+            .longitudeDegrees = locationV2->v1_0.longitudeDegrees,
+            .altitudeMeters = locationV2->v1_0.altitudeMeters,
+            .speedMetersPerSec = locationV2->v1_0.speedMetersPerSec,
+            .bearingDegrees = locationV2->v1_0.bearingDegrees,
+            .horizontalAccuracyMeters = locationV2->v1_0.horizontalAccuracyMeters,
+            .verticalAccuracyMeters = locationV2->v1_0.verticalAccuracyMeters,
+            .speedAccuracyMetersPerSecond = locationV2->v1_0.speedAccuracyMetersPerSecond,
+            .bearingAccuracyDegrees = locationV2->v1_0.bearingAccuracyDegrees,
+            .timestampMillis = locationV2->v1_0.timestamp,
+            .elapsedRealtime = elapsedRealtime};
+    return std::make_unique<GnssLocation>(location);
+}
+
+/**
  * Parses the input string in NMEA format and convert to GnssLocation.
  */
 std::unique_ptr<V2_0::GnssLocation> NmeaFixInfo::toGnssLocation() const {
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index c339e72..1ff84eb 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -27,14 +27,18 @@
 
 using aidl::android::hardware::gnss::ElapsedRealtime;
 using aidl::android::hardware::gnss::GnssClock;
+using aidl::android::hardware::gnss::GnssConstellationType;
 using aidl::android::hardware::gnss::GnssData;
 using aidl::android::hardware::gnss::GnssLocation;
 using aidl::android::hardware::gnss::GnssMeasurement;
 using aidl::android::hardware::gnss::IGnss;
 using aidl::android::hardware::gnss::IGnssMeasurementCallback;
 using aidl::android::hardware::gnss::SatellitePvt;
+using GnssSvInfo = aidl::android::hardware::gnss::IGnssCallback::GnssSvInfo;
+using GnssSvFlags = aidl::android::hardware::gnss::IGnssCallback::GnssSvFlags;
 
-using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags;
+using GnssSvFlagsV1_0 = V1_0::IGnssCallback::GnssSvFlags;
+using GnssAgc = aidl::android::hardware::gnss::GnssData::GnssAgc;
 using GnssMeasurementFlagsV1_0 = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
 using GnssMeasurementFlagsV2_1 = V2_1::IGnssMeasurementCallback::GnssMeasurementFlags;
 using GnssMeasurementStateV2_0 = V2_0::IGnssMeasurementCallback::GnssMeasurementState;
@@ -144,7 +148,7 @@
 
 GnssData Utils::getMockMeasurement(const bool enableCorrVecOutputs) {
     aidl::android::hardware::gnss::GnssSignalType signalType = {
-            .constellation = aidl::android::hardware::gnss::GnssConstellationType::GLONASS,
+            .constellation = GnssConstellationType::GLONASS,
             .carrierFrequencyHz = 1.59975e+09,
             .codeType = aidl::android::hardware::gnss::GnssSignalType::CODE_TYPE_C,
     };
@@ -228,8 +232,23 @@
         measurement.flags |= GnssMeasurement::HAS_CORRELATION_VECTOR;
     }
 
-    GnssData gnssData = {
-            .measurements = {measurement}, .clock = clock, .elapsedRealtime = timestamp};
+    GnssAgc gnssAgc1 = {
+            .agcLevelDb = 3.5,
+            .constellation = GnssConstellationType::GLONASS,
+            .carrierFrequencyHz = (int64_t)kGloG1FreqHz,
+    };
+
+    GnssAgc gnssAgc2 = {
+            .agcLevelDb = -5.1,
+            .constellation = GnssConstellationType::GPS,
+            .carrierFrequencyHz = (int64_t)kGpsL1FreqHz,
+    };
+
+    GnssData gnssData = {.measurements = {measurement},
+                         .clock = clock,
+                         .elapsedRealtime = timestamp,
+                         .gnssAgcs = std::make_optional(std::vector(
+                                 {std::make_optional(gnssAgc1), std::make_optional(gnssAgc2)}))};
     return gnssData;
 }
 
@@ -289,6 +308,40 @@
     return location;
 }
 
+namespace {
+GnssSvInfo getMockSvInfo(int svid, GnssConstellationType type, float cN0DbHz, float basebandCN0DbHz,
+                         float elevationDegrees, float azimuthDegrees, long carrierFrequencyHz) {
+    GnssSvInfo svInfo = {
+            .svid = svid,
+            .constellation = type,
+            .cN0Dbhz = cN0DbHz,
+            .basebandCN0DbHz = basebandCN0DbHz,
+            .elevationDegrees = elevationDegrees,
+            .azimuthDegrees = azimuthDegrees,
+            .carrierFrequencyHz = carrierFrequencyHz,
+            .svFlag = (int)GnssSvFlags::USED_IN_FIX | (int)GnssSvFlags::HAS_EPHEMERIS_DATA |
+                      (int)GnssSvFlags::HAS_ALMANAC_DATA | (int)GnssSvFlags::HAS_CARRIER_FREQUENCY};
+    return svInfo;
+}
+}  // anonymous namespace
+
+std::vector<GnssSvInfo> Utils::getMockSvInfoList() {
+    std::vector<GnssSvInfo> gnssSvInfoList = {
+            getMockSvInfo(3, GnssConstellationType::GPS, 32.5, 27.5, 59.1, 166.5, kGpsL1FreqHz),
+            getMockSvInfo(5, GnssConstellationType::GPS, 27.0, 22.0, 29.0, 56.5, kGpsL1FreqHz),
+            getMockSvInfo(17, GnssConstellationType::GPS, 30.5, 25.5, 71.0, 77.0, kGpsL5FreqHz),
+            getMockSvInfo(26, GnssConstellationType::GPS, 24.1, 19.1, 28.0, 253.0, kGpsL5FreqHz),
+            getMockSvInfo(5, GnssConstellationType::GLONASS, 20.5, 15.5, 11.5, 116.0, kGloG1FreqHz),
+            getMockSvInfo(17, GnssConstellationType::GLONASS, 21.5, 16.5, 28.5, 186.0,
+                          kGloG1FreqHz),
+            getMockSvInfo(18, GnssConstellationType::GLONASS, 28.3, 25.3, 38.8, 69.0, kGloG1FreqHz),
+            getMockSvInfo(10, GnssConstellationType::GLONASS, 25.0, 20.0, 66.0, 247.0,
+                          kGloG1FreqHz),
+            getMockSvInfo(3, GnssConstellationType::IRNSS, 22.0, 19.7, 35.0, 112.0, kIrnssL5FreqHz),
+    };
+    return gnssSvInfoList;
+}
+
 hidl_vec<GnssSvInfoV2_1> Utils::getMockSvInfoListV2_1() {
     GnssSvInfoV1_0 gnssSvInfoV1_0 = Utils::getMockSvInfoV1_0(3, V1_0::GnssConstellationType::GPS,
                                                              32.5, 59.1, 166.5, kGpsL1FreqHz);
@@ -360,15 +413,15 @@
 GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type,
                                         float cN0DbHz, float elevationDegrees, float azimuthDegrees,
                                         float carrierFrequencyHz) {
-    GnssSvInfoV1_0 svInfo = {.svid = svid,
-                             .constellation = type,
-                             .cN0Dbhz = cN0DbHz,
-                             .elevationDegrees = elevationDegrees,
-                             .azimuthDegrees = azimuthDegrees,
-                             .carrierFrequencyHz = carrierFrequencyHz,
-                             .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA |
-                                       GnssSvFlags::HAS_ALMANAC_DATA |
-                                       GnssSvFlags::HAS_CARRIER_FREQUENCY};
+    GnssSvInfoV1_0 svInfo = {
+            .svid = svid,
+            .constellation = type,
+            .cN0Dbhz = cN0DbHz,
+            .elevationDegrees = elevationDegrees,
+            .azimuthDegrees = azimuthDegrees,
+            .carrierFrequencyHz = carrierFrequencyHz,
+            .svFlag = GnssSvFlagsV1_0::USED_IN_FIX | GnssSvFlagsV1_0::HAS_EPHEMERIS_DATA |
+                      GnssSvFlagsV1_0::HAS_ALMANAC_DATA | GnssSvFlagsV1_0::HAS_CARRIER_FREQUENCY};
     return svInfo;
 }
 
diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h
index f205ba6..489413e 100644
--- a/gnss/common/utils/default/include/Constants.h
+++ b/gnss/common/utils/default/include/Constants.h
@@ -36,6 +36,7 @@
 
 // Location replay constants
 constexpr char GNSS_PATH[] = "/dev/gnss0";
+constexpr char FIXED_LOCATION_PATH[] = "/dev/gnss1";
 constexpr int INPUT_BUFFER_SIZE = 256;
 constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION";
 constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT";
diff --git a/gnss/common/utils/default/include/FixLocationParser.h b/gnss/common/utils/default/include/FixLocationParser.h
new file mode 100644
index 0000000..a738914
--- /dev/null
+++ b/gnss/common/utils/default/include/FixLocationParser.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_gnss_common_default_FixLocationParser_H_
+#define android_hardware_gnss_common_default_FixLocationParser_H_
+
+#include <aidl/android/hardware/gnss/BnGnss.h>
+
+#include <utils/SystemClock.h>
+#include <string>
+#include <vector>
+
+#include <Constants.h>
+#include <Utils.h>
+#include <log/log.h>
+#include "Constants.h"
+#include "ParseUtils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+struct FixLocationParser {
+  public:
+    static std::unique_ptr<aidl::android::hardware::gnss::GnssLocation> getLocationFromInputStr(
+            const std::string& inputStr);
+};
+
+}  // namespace common
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_gnss_common_default_FixLocationParser_H_
\ No newline at end of file
diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h
index 32c0e58..d1bbed4 100644
--- a/gnss/common/utils/default/include/GnssReplayUtils.h
+++ b/gnss/common/utils/default/include/GnssReplayUtils.h
@@ -37,10 +37,14 @@
 struct ReplayUtils {
     static std::string getGnssPath();
 
+    static std::string getFixedLocationPath();
+
     static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs);
 
     static bool hasGnssDeviceFile();
 
+    static bool hasFixedLocationDeviceFile();
+
     static bool isGnssRawMeasurement(const std::string& inputStr);
 
     static bool isNMEA(const std::string& inputStr);
diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h
index 5c27045..4073361 100644
--- a/gnss/common/utils/default/include/NmeaFixInfo.h
+++ b/gnss/common/utils/default/include/NmeaFixInfo.h
@@ -22,6 +22,7 @@
 #include <hidl/Status.h>
 #include <ctime>
 #include <string>
+#include "aidl/android/hardware/gnss/IGnss.h"
 namespace android {
 namespace hardware {
 namespace gnss {
@@ -45,6 +46,8 @@
 
   public:
     static std::unique_ptr<V2_0::GnssLocation> getLocationFromInputStr(const std::string& inputStr);
+    static std::unique_ptr<aidl::android::hardware::gnss::GnssLocation> getAidlLocationFromInputStr(
+            const std::string& inputStr);
 
   private:
     static void splitStr(const std::string& line, const char& delimiter,
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index 4500ee6..7065a6fb 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -35,9 +35,13 @@
             const bool enableCorrVecOutputs);
     static V2_0::IGnssMeasurementCallback::GnssData getMockMeasurementV2_0();
     static V2_1::IGnssMeasurementCallback::GnssData getMockMeasurementV2_1();
+
     static aidl::android::hardware::gnss::GnssLocation getMockLocation();
     static V2_0::GnssLocation getMockLocationV2_0();
     static V1_0::GnssLocation getMockLocationV1_0();
+
+    static std::vector<aidl::android::hardware::gnss::IGnssCallback::GnssSvInfo>
+    getMockSvInfoList();
     static hidl_vec<V2_1::IGnssCallback::GnssSvInfo> getMockSvInfoListV2_1();
     static V2_1::IGnssCallback::GnssSvInfo getMockSvInfoV2_1(
             V2_0::IGnssCallback::GnssSvInfo gnssSvInfoV2_0, float basebandCN0DbHz);
@@ -48,6 +52,7 @@
                                                              float cN0DbHz, float elevationDegrees,
                                                              float azimuthDegrees,
                                                              float carrierFrequencyHz);
+
     static hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo> getMockAntennaInfos();
 };
 
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index 47eff2e..f92e609 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -44,6 +44,7 @@
         "android.hardware.gnss@2.1",
         "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss-V2-cpp",
     ],
     static_libs: [
         "libgtest",
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index be22ff6..da4c07f 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -15,6 +15,8 @@
  */
 
 #include <Utils.h>
+#include <android/hardware/gnss/BnGnss.h>
+#include <android/hardware/gnss/IGnss.h>
 #include "gtest/gtest.h"
 
 #include <cutils/properties.h>
@@ -27,71 +29,20 @@
 using namespace measurement_corrections::V1_0;
 using V1_0::GnssLocationFlags;
 
-void Utils::checkLocation(const V1_0::GnssLocation& location, bool check_speed,
-                          bool check_more_accuracies) {
-    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG);
-    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE);
-    if (check_speed) {
-        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED);
-    }
-    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
-    // New uncertainties available in O must be provided,
-    // at least when paired with modern hardware (2017+)
-    if (check_more_accuracies) {
-        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY);
-        if (check_speed) {
-            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY);
-            if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
-                EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY);
-            }
-        }
-    }
-    EXPECT_GE(location.latitudeDegrees, -90.0);
-    EXPECT_LE(location.latitudeDegrees, 90.0);
-    EXPECT_GE(location.longitudeDegrees, -180.0);
-    EXPECT_LE(location.longitudeDegrees, 180.0);
-    EXPECT_GE(location.altitudeMeters, -1000.0);
-    EXPECT_LE(location.altitudeMeters, 30000.0);
-    if (check_speed) {
-        EXPECT_GE(location.speedMetersPerSec, 0.0);
-        EXPECT_LE(location.speedMetersPerSec, 5.0);  // VTS tests are stationary.
+using MeasurementCorrectionsAidl =
+        android::hardware::gnss::measurement_corrections::MeasurementCorrections;
+using ReflectingPlaneAidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using SingleSatCorrectionAidl =
+        android::hardware::gnss::measurement_corrections::SingleSatCorrection;
 
-        // Non-zero speeds must be reported with an associated bearing
-        if (location.speedMetersPerSec > 0.0) {
-            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING);
-        }
-    }
+template <>
+int64_t Utils::getLocationTimestampMillis(const android::hardware::gnss::GnssLocation& location) {
+    return location.timestampMillis;
+}
 
-    /*
-     * Tolerating some especially high values for accuracy estimate, in case of
-     * first fix with especially poor geometry (happens occasionally)
-     */
-    EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
-    EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
-
-    /*
-     * Some devices may define bearing as -180 to +180, others as 0 to 360.
-     * Both are okay & understandable.
-     */
-    if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
-        EXPECT_GE(location.bearingDegrees, -180.0);
-        EXPECT_LE(location.bearingDegrees, 360.0);
-    }
-    if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
-        EXPECT_GT(location.verticalAccuracyMeters, 0.0);
-        EXPECT_LE(location.verticalAccuracyMeters, 500.0);
-    }
-    if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
-        EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
-        EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
-    }
-    if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
-        EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
-        EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
-    }
-
-    // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
-    EXPECT_GT(location.timestamp, 1.48e12);
+template <>
+int64_t Utils::getLocationTimestampMillis(const V1_0::GnssLocation& location) {
+    return location.timestamp;
 }
 
 const MeasurementCorrections Utils::getMockMeasurementCorrections() {
@@ -119,6 +70,7 @@
             .singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY |
                                         GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH |
                                         GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC,
+
             .constellation = V1_0::GnssConstellationType::GPS,
             .svid = 9,
             .carrierFrequencyHz = 1.59975e+09,
@@ -170,6 +122,56 @@
     return mockCorrections_1_1;
 }
 
+const MeasurementCorrectionsAidl Utils::getMockMeasurementCorrections_aidl() {
+    ReflectingPlaneAidl reflectingPlane;
+    reflectingPlane.latitudeDegrees = 37.4220039;
+    reflectingPlane.longitudeDegrees = -122.0840991;
+    reflectingPlane.altitudeMeters = 250.35;
+    reflectingPlane.azimuthDegrees = 203.0;
+
+    SingleSatCorrectionAidl singleSatCorrection1;
+    singleSatCorrection1.singleSatCorrectionFlags =
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE;
+    singleSatCorrection1.constellation = android::hardware::gnss::GnssConstellationType::GPS;
+    singleSatCorrection1.svid = 12;
+    singleSatCorrection1.carrierFrequencyHz = 1.59975e+09;
+    singleSatCorrection1.probSatIsLos = 0.50001;
+    singleSatCorrection1.excessPathLengthMeters = 137.4802;
+    singleSatCorrection1.excessPathLengthUncertaintyMeters = 25.5;
+    singleSatCorrection1.reflectingPlane = reflectingPlane;
+
+    SingleSatCorrectionAidl singleSatCorrection2;
+    singleSatCorrection2.singleSatCorrectionFlags =
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC;
+    singleSatCorrection2.constellation = GnssConstellationType::GPS;
+    singleSatCorrection2.svid = 9;
+    singleSatCorrection2.carrierFrequencyHz = 1.59975e+09;
+    singleSatCorrection2.probSatIsLos = 0.873;
+    singleSatCorrection2.excessPathLengthMeters = 26.294;
+    singleSatCorrection2.excessPathLengthUncertaintyMeters = 10.0;
+
+    std::vector<SingleSatCorrectionAidl> singleSatCorrections = {singleSatCorrection1,
+                                                                 singleSatCorrection2};
+    MeasurementCorrectionsAidl mockCorrections;
+    mockCorrections.latitudeDegrees = 37.4219999;
+    mockCorrections.longitudeDegrees = -122.0840575;
+    mockCorrections.altitudeMeters = 30.60062531;
+    mockCorrections.horizontalPositionUncertaintyMeters = 9.23542;
+    mockCorrections.verticalPositionUncertaintyMeters = 15.02341;
+    mockCorrections.toaGpsNanosecondsOfWeek = 2935633453L;
+    mockCorrections.hasEnvironmentBearing = true;
+    mockCorrections.environmentBearingDegrees = 45.0;
+    mockCorrections.environmentBearingUncertaintyDegrees = 4.0;
+    mockCorrections.satCorrections = singleSatCorrections;
+
+    return mockCorrections;
+}
+
 /*
  * MapConstellationType:
  * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index 91c1167..4ea6cd6 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -21,6 +21,9 @@
 #include <android/hardware/gnss/2.0/IGnss.h>
 #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
 #include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsInterface.h>
+
+#include <gtest/gtest.h>
 
 namespace android {
 namespace hardware {
@@ -28,19 +31,94 @@
 namespace common {
 
 struct Utils {
-    static void checkLocation(const V1_0::GnssLocation& location, bool check_speed,
-                              bool check_more_accuracies);
+  public:
+    template <class T>
+    static void checkLocation(const T& location, bool check_speed, bool check_more_accuracies);
     static const measurement_corrections::V1_0::MeasurementCorrections
     getMockMeasurementCorrections();
     static const measurement_corrections::V1_1::MeasurementCorrections
     getMockMeasurementCorrections_1_1();
+    static const android::hardware::gnss::measurement_corrections::MeasurementCorrections
+    getMockMeasurementCorrections_aidl();
 
     static V1_0::GnssConstellationType mapConstellationType(
             V2_0::GnssConstellationType constellation);
 
     static bool isAutomotiveDevice();
+
+  private:
+    template <class T>
+    static int64_t getLocationTimestampMillis(const T&);
 };
 
+template <class T>
+void Utils::checkLocation(const T& location, bool check_speed, bool check_more_accuracies) {
+    EXPECT_TRUE(location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_LAT_LONG);
+    EXPECT_TRUE(location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_ALTITUDE);
+    if (check_speed) {
+        EXPECT_TRUE(location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_SPEED);
+    }
+    EXPECT_TRUE(location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
+    // New uncertainties available in O must be provided,
+    // at least when paired with modern hardware (2017+)
+    if (check_more_accuracies) {
+        EXPECT_TRUE(location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_VERTICAL_ACCURACY);
+        if (check_speed) {
+            EXPECT_TRUE(location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_SPEED_ACCURACY);
+            if (location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_BEARING) {
+                EXPECT_TRUE(location.gnssLocationFlags &
+                            V1_0::GnssLocationFlags::HAS_BEARING_ACCURACY);
+            }
+        }
+    }
+    EXPECT_GE(location.latitudeDegrees, -90.0);
+    EXPECT_LE(location.latitudeDegrees, 90.0);
+    EXPECT_GE(location.longitudeDegrees, -180.0);
+    EXPECT_LE(location.longitudeDegrees, 180.0);
+    EXPECT_GE(location.altitudeMeters, -1000.0);
+    EXPECT_LE(location.altitudeMeters, 30000.0);
+    if (check_speed) {
+        EXPECT_GE(location.speedMetersPerSec, 0.0);
+        EXPECT_LE(location.speedMetersPerSec, 5.0);  // VTS tests are stationary.
+
+        // Non-zero speeds must be reported with an associated bearing
+        if (location.speedMetersPerSec > 0.0) {
+            EXPECT_TRUE(location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_BEARING);
+        }
+    }
+
+    /*
+     * Tolerating some especially high values for accuracy estimate, in case of
+     * first fix with especially poor geometry (happens occasionally)
+     */
+    EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
+    EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
+
+    /*
+     * Some devices may define bearing as -180 to +180, others as 0 to 360.
+     * Both are okay & understandable.
+     */
+    if (location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_BEARING) {
+        EXPECT_GE(location.bearingDegrees, -180.0);
+        EXPECT_LE(location.bearingDegrees, 360.0);
+    }
+    if (location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        EXPECT_GT(location.verticalAccuracyMeters, 0.0);
+        EXPECT_LE(location.verticalAccuracyMeters, 500.0);
+    }
+    if (location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
+        EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
+    }
+    if (location.gnssLocationFlags & V1_0::GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
+        EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
+    }
+
+    // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
+    EXPECT_GT(getLocationTimestampMillis(location), 1.48e12);
+}
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/gnss/common/utils/vts/include/v2_1/GnssCallback.h b/gnss/common/utils/vts/include/v2_1/GnssCallback.h
index ab1375d..09a67de 100644
--- a/gnss/common/utils/vts/include/v2_1/GnssCallback.h
+++ b/gnss/common/utils/vts/include/v2_1/GnssCallback.h
@@ -28,7 +28,6 @@
 using android::hardware::gnss::common::GnssCallbackEventQueue;
 using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
-using android::hardware::gnss::V2_0::GnssConstellationType;
 
 using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
 using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
new file mode 100644
index 0000000..ea8a599
--- /dev/null
+++ b/graphics/allocator/aidl/Android.bp
@@ -0,0 +1,40 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.graphics.allocator",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: ["android/hardware/graphics/allocator/*.aidl"],
+    imports: [
+        "android.hardware.common-V2",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media.swcodec",
+            ],
+            vndk: {
+                enabled: true,
+            },
+            min_sdk_version: "29",
+        },
+    },
+}
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationError.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationError.aidl
new file mode 100644
index 0000000..6e7b739
--- /dev/null
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationError.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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.graphics.allocator;
+@Backing(type="int") @VintfStability
+enum AllocationError {
+  BAD_DESCRIPTOR = 0,
+  NO_RESOURCES = 1,
+  UNSUPPORTED = 2,
+}
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationResult.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationResult.aidl
new file mode 100644
index 0000000..73cfeb5
--- /dev/null
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationResult.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.graphics.allocator;
+@VintfStability
+parcelable AllocationResult {
+  int stride;
+  android.hardware.common.NativeHandle[] buffers;
+}
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
new file mode 100644
index 0000000..fe0b0a2
--- /dev/null
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 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.graphics.allocator;
+@VintfStability
+interface IAllocator {
+  android.hardware.graphics.allocator.AllocationResult allocate(in byte[] descriptor, in int count);
+}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationError.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationError.aidl
new file mode 100644
index 0000000..c6b77b9
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationError.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.graphics.allocator;
+
+@VintfStability
+@Backing(type="int")
+enum AllocationError {
+    /**
+     * Invalid BufferDescriptor.
+     */
+    BAD_DESCRIPTOR,
+
+    /**
+     * Resource unavailable.
+     */
+    NO_RESOURCES,
+
+    /**
+     * Permanent failure.
+     */
+    UNSUPPORTED
+}
\ No newline at end of file
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
new file mode 100644
index 0000000..0774e25
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.graphics.allocator;
+
+import android.hardware.common.NativeHandle;
+
+ /**
+ * Result of an IAllocator::allocate call.
+ *
+ * @sa +ndk libnativewindow#AHardwareBuffer_Desc
+ */
+@VintfStability
+parcelable AllocationResult {
+    int stride;
+    NativeHandle[] buffers;
+}
\ No newline at end of file
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
new file mode 100644
index 0000000..8c3ca96
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.graphics.allocator;
+
+import android.hardware.graphics.allocator.AllocationResult;
+
+@VintfStability
+interface IAllocator {
+    /**
+     * Allocates buffers with the properties specified by the descriptor.
+     *
+     * Allocations should be optimized for usage bits provided in the
+     * descriptor.
+     *
+     * @param descriptor Properties of the buffers to allocate. This must be
+     *     obtained from IMapper::createDescriptor().
+     * @param count The number of buffers to allocate.
+     * @return An AllocationResult containing the result of an error, or
+     *         an AllocationError status
+     */
+    AllocationResult allocate(in byte[] descriptor, in int count);
+}
diff --git a/graphics/common/OWNERS b/graphics/common/OWNERS
new file mode 100644
index 0000000..94999ea
--- /dev/null
+++ b/graphics/common/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1075130
+adyabr@google.com
+alecmouri@google.com
+jreck@google.com
+scroggo@google.com
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
index b4ef451..e1edb17 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
@@ -54,10 +54,11 @@
   RENDERSCRIPT = 1048576,
   VIDEO_DECODER = 4194304,
   SENSOR_DIRECT_DATA = 8388608,
+  GPU_DATA_BUFFER = 16777216,
   GPU_CUBE_MAP = 33554432,
   GPU_MIPMAP_COMPLETE = 67108864,
   HW_IMAGE_ENCODER = 134217728,
-  GPU_DATA_BUFFER = 16777216,
+  FRONT_BUFFER = 4294967296,
   VENDOR_MASK = -268435456,
   VENDOR_MASK_HI = -281474976710656,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
index 04a863b..512fecb 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
@@ -63,4 +63,5 @@
   STENCIL_8 = 53,
   YCBCR_P010 = 54,
   HSV_888 = 55,
+  R_8 = 56,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Point.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Point.aidl
new file mode 100644
index 0000000..3722803
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Point.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.common;
+@VintfStability
+parcelable Point {
+  int x;
+  int y;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
index 5c3d4cb..359c655 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
@@ -34,6 +34,7 @@
 package android.hardware.graphics.common;
 @Backing(type="int") @VintfStability
 enum Transform {
+  NONE = 0,
   FLIP_H = 1,
   FLIP_V = 2,
   ROT_90 = 4,
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
index d978f46..60dfbfb 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
@@ -87,6 +87,12 @@
     /** buffer is used as a sensor direct report output */
     SENSOR_DIRECT_DATA                 = 1 << 23,
 
+    /**
+     * buffer is used as as an OpenGL shader storage or uniform
+     * buffer object
+     */
+    GPU_DATA_BUFFER                    = 1 << 24,
+
     /** buffer is used as a cube map texture */
     GPU_CUBE_MAP                       = 1 << 25,
 
@@ -98,17 +104,34 @@
      */
     HW_IMAGE_ENCODER                   = 1 << 27,
 
-    /**
-     * buffer is used as as an OpenGL shader storage or uniform
-     * buffer object
-     */
-    GPU_DATA_BUFFER                    = 1 << 24,
+    /* Bits 28-31 are reserved for vendor usage */
 
-    /** bits 25-27 must be zero and are reserved for future versions */
+    /**
+    * Buffer is used for front-buffer rendering.
+    *
+    * To satisfy an allocation with this usage, the resulting buffer
+    * must operate as equivalent to shared memory for all targets.
+    *
+    * For CPU_USAGE_* other than NEVER, this means the buffer must
+    * "lock in place". The buffers must be directly accessible via mapping.
+    *
+    * For GPU_RENDER_TARGET the buffer must behave equivalent to a
+    * single-buffered EGL surface. For example glFlush must perform
+    * a flush, same as if the default framebuffer was single-buffered.
+    *
+    * For COMPOSER_* the HWC must not perform any caching for this buffer
+    * when submitted for composition. HWCs do not need to do any form
+    * of auto-refresh, and they are allowed to cache composition results between
+    * presents from SF (such as for panel self-refresh), but for any given
+    * present the buffer must be composited from even if it otherwise appears
+    * to be the same as a previous composition.
+    */
+    FRONT_BUFFER                       = 1L << 32,
+
     /** bits 28-31 are reserved for vendor extensions */
     VENDOR_MASK                        = 0xf << 28,
 
-    /** bits 32-47 must be zero and are reserved for future versions */
+    /** bits 33-47 must be zero and are reserved for future versions */
     /** bits 48-63 are reserved for vendor extensions */
     VENDOR_MASK_HI                     = (1L * 0xffff) << 48,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
index eb87f8d..4e891f6 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -498,4 +498,11 @@
      * interpretation is defined by the dataspace.
      */
     HSV_888 = 0x37,
+
+    /**
+     * 8 bit format with a single 8-bit component.
+     *
+     * The component values are unsigned normalized to the range [0, 1].
+     */
+    R_8 = 0x38,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Point.aidl b/graphics/common/aidl/android/hardware/graphics/common/Point.aidl
new file mode 100644
index 0000000..b3ede44
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Point.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * General purpose definition of a point.
+ */
+
+@VintfStability
+parcelable Point {
+    int x;
+    int y;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 7719d6e..74a9ce3 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -22,8 +22,9 @@
  * This is an enum that defines the common types of gralloc 4 buffer metadata. The comments for
  * each enum include a description of the metadata that is associated with the type.
  *
- * IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may
- * support setting these standard buffer metadata types as well.
+ * IMapper@4.x must support getting the following standard buffer metadata types, with the exception
+ * of SMPTE 2094-10 metadata. IMapper@4.x may support setting these standard buffer metadata types
+ * as well.
  *
  * When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is
  * is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl b/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
index 325816c..4b3a1b1 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
@@ -23,6 +23,11 @@
 @Backing(type="int")
 enum Transform {
     /**
+     * Identity transform (i.e. no rotation or flip).
+     */
+    NONE = 0,
+
+    /**
      * Horizontal flip. FLIP_H/FLIP_V is applied before ROT_90.
      */
     FLIP_H = 1 << 0,
diff --git a/graphics/composer/2.1/default/OWNERS b/graphics/composer/2.1/default/OWNERS
index 709c4d1..331c80d 100644
--- a/graphics/composer/2.1/default/OWNERS
+++ b/graphics/composer/2.1/default/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
diff --git a/graphics/composer/2.1/utils/OWNERS b/graphics/composer/2.1/utils/OWNERS
index 7af69b4..83c4f5f 100644
--- a/graphics/composer/2.1/utils/OWNERS
+++ b/graphics/composer/2.1/utils/OWNERS
@@ -1,2 +1,3 @@
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
diff --git a/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp
index 1ead138..ccbc5b1 100644
--- a/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp
@@ -30,7 +30,7 @@
 
 std::vector<Display> GraphicsComposerCallback::getDisplays() const {
     std::lock_guard<std::mutex> lock(mMutex);
-    return std::vector<Display>(mDisplays.begin(), mDisplays.end());
+    return mDisplays;
 }
 
 int GraphicsComposerCallback::getInvalidHotplugCount() const {
@@ -51,12 +51,17 @@
 Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection connection) {
     std::lock_guard<std::mutex> lock(mMutex);
 
+    auto it = std::find(mDisplays.begin(), mDisplays.end(), display);
     if (connection == Connection::CONNECTED) {
-        if (!mDisplays.insert(display).second) {
+        if (it == mDisplays.end()) {
+            mDisplays.push_back(display);
+        } else {
             mInvalidHotplugCount++;
         }
     } else if (connection == Connection::DISCONNECTED) {
-        if (!mDisplays.erase(display)) {
+        if (it != mDisplays.end()) {
+            mDisplays.erase(it);
+        } else {
             mInvalidHotplugCount++;
         }
     }
@@ -67,7 +72,8 @@
 Return<void> GraphicsComposerCallback::onRefresh(Display display) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (mDisplays.count(display) == 0) {
+    auto it = std::find(mDisplays.begin(), mDisplays.end(), display);
+    if (it == mDisplays.end()) {
         mInvalidRefreshCount++;
     }
 
@@ -77,7 +83,8 @@
 Return<void> GraphicsComposerCallback::onVsync(Display display, int64_t) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (!mVsyncAllowed || mDisplays.count(display) == 0) {
+    auto it = std::find(mDisplays.begin(), mDisplays.end(), display);
+    if (!mVsyncAllowed || it == mDisplays.end()) {
         mInvalidVsyncCount++;
     }
 
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h
index e3c348f..da64052 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h
@@ -19,7 +19,7 @@
 #include <android/hardware/graphics/composer/2.1/IComposerCallback.h>
 
 #include <mutex>
-#include <unordered_set>
+#include <vector>
 
 namespace android {
 namespace hardware {
@@ -48,7 +48,7 @@
 
     mutable std::mutex mMutex;
     // the set of all currently connected displays
-    std::unordered_set<Display> mDisplays;
+    std::vector<Display> mDisplays;
     // true only when vsync is enabled
     bool mVsyncAllowed = true;
 
diff --git a/graphics/composer/2.1/vts/OWNERS b/graphics/composer/2.1/vts/OWNERS
index ea06752..a643bbd 100644
--- a/graphics/composer/2.1/vts/OWNERS
+++ b/graphics/composer/2.1/vts/OWNERS
@@ -1,5 +1,6 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
 
 # VTS team
diff --git a/graphics/composer/2.1/vts/functional/OWNERS b/graphics/composer/2.1/vts/functional/OWNERS
index a2ed8c8..3d970d1 100644
--- a/graphics/composer/2.1/vts/functional/OWNERS
+++ b/graphics/composer/2.1/vts/functional/OWNERS
@@ -1,2 +1,4 @@
 # Bug component: 25423
+adyabr@google.com
+alecmouri@google.com
 sumir@google.com
diff --git a/graphics/composer/2.2/default/OWNERS b/graphics/composer/2.2/default/OWNERS
index 709c4d1..e8f584d 100644
--- a/graphics/composer/2.2/default/OWNERS
+++ b/graphics/composer/2.2/default/OWNERS
@@ -1,3 +1,5 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
+
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
index 709c4d1..331c80d 100644
--- a/graphics/composer/2.2/utils/OWNERS
+++ b/graphics/composer/2.2/utils/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index 30596fc..a1794af 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -17,6 +17,7 @@
 #include <composer-vts/2.2/ReadbackVts.h>
 #include <composer-vts/2.2/RenderEngineVts.h>
 #include "renderengine/ExternalTexture.h"
+#include "renderengine/impl/ExternalTexture.h"
 
 namespace android {
 namespace hardware {
@@ -281,11 +282,11 @@
 
 LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
     LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
-    layerSettings.source.buffer.buffer = std::make_shared<renderengine::ExternalTexture>(
+    layerSettings.source.buffer.buffer = std::make_shared<renderengine::impl::ExternalTexture>(
             new GraphicBuffer(mBufferHandle->get(), GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
                               static_cast<int32_t>(mFormat), 1, mUsage, mStride),
             mRenderEngine.getInternalRenderEngine(),
-            renderengine::ExternalTexture::Usage::READABLE);
+            renderengine::impl::ExternalTexture::Usage::READABLE);
 
     layerSettings.source.buffer.usePremultipliedAlpha =
             mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index 2d4cc7d..4a33fb5 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <composer-vts/2.2/RenderEngineVts.h>
+#include "renderengine/impl/ExternalTexture.h"
 
 namespace android {
 namespace hardware {
@@ -68,8 +69,8 @@
                    [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings {
                        return settings;
                    });
-    auto texture = std::make_shared<renderengine::ExternalTexture>(
-            mGraphicBuffer, *mRenderEngine, renderengine::ExternalTexture::Usage::WRITEABLE);
+    auto texture = std::make_shared<renderengine::impl::ExternalTexture>(
+            mGraphicBuffer, *mRenderEngine, renderengine::impl::ExternalTexture::Usage::WRITEABLE);
     auto [status, readyFence] = mRenderEngine
                                         ->drawLayers(mDisplaySettings, compositionLayers, texture,
                                                      true, std::move(bufferFence))
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
index 31b0dc7..a4eb0ca 100644
--- a/graphics/composer/2.2/vts/functional/OWNERS
+++ b/graphics/composer/2.2/vts/functional/OWNERS
@@ -1,5 +1,6 @@
 # Bug component: 25423
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
 sumir@google.com
diff --git a/graphics/composer/2.3/default/OWNERS b/graphics/composer/2.3/default/OWNERS
index 709c4d1..331c80d 100644
--- a/graphics/composer/2.3/default/OWNERS
+++ b/graphics/composer/2.3/default/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
index 709c4d1..331c80d 100644
--- a/graphics/composer/2.3/utils/OWNERS
+++ b/graphics/composer/2.3/utils/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS
index 31b0dc7..a4eb0ca 100644
--- a/graphics/composer/2.3/vts/functional/OWNERS
+++ b/graphics/composer/2.3/vts/functional/OWNERS
@@ -1,5 +1,6 @@
 # Bug component: 25423
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
 sumir@google.com
diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS
index 709c4d1..331c80d 100644
--- a/graphics/composer/2.4/default/OWNERS
+++ b/graphics/composer/2.4/default/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS
index 709c4d1..331c80d 100644
--- a/graphics/composer/2.4/utils/OWNERS
+++ b/graphics/composer/2.4/utils/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
diff --git a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp
index c9366a8..51e1ab7 100644
--- a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp
@@ -25,7 +25,7 @@
 
 std::vector<Display> GraphicsComposerCallback::getDisplays() const {
     std::lock_guard<std::mutex> lock(mMutex);
-    return std::vector<Display>(mDisplays.begin(), mDisplays.end());
+    return mDisplays;
 }
 
 int32_t GraphicsComposerCallback::getInvalidHotplugCount() const {
@@ -71,12 +71,17 @@
 Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection connection) {
     std::lock_guard<std::mutex> lock(mMutex);
 
+    auto it = std::find(mDisplays.begin(), mDisplays.end(), display);
     if (connection == Connection::CONNECTED) {
-        if (!mDisplays.insert(display).second) {
+        if (it == mDisplays.end()) {
+            mDisplays.push_back(display);
+        } else {
             mInvalidHotplugCount++;
         }
     } else if (connection == Connection::DISCONNECTED) {
-        if (!mDisplays.erase(display)) {
+        if (it != mDisplays.end()) {
+            mDisplays.erase(it);
+        } else {
             mInvalidHotplugCount++;
         }
     }
@@ -87,7 +92,8 @@
 Return<void> GraphicsComposerCallback::onRefresh(Display display) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (mDisplays.count(display) == 0) {
+    auto it = std::find(mDisplays.begin(), mDisplays.end(), display);
+    if (it == mDisplays.end()) {
         mInvalidRefreshCount++;
     }
 
@@ -106,7 +112,8 @@
 Return<void> GraphicsComposerCallback::onVsync_2_4(Display display, int64_t, VsyncPeriodNanos) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (!mVsyncAllowed || mDisplays.count(display) == 0) {
+    auto it = std::find(mDisplays.begin(), mDisplays.end(), display);
+    if (!mVsyncAllowed || it == mDisplays.end()) {
         mInvalidVsync_2_4Count++;
     }
 
@@ -117,7 +124,8 @@
         Display display, const VsyncPeriodChangeTimeline& updatedTimeline) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (mDisplays.count(display) == 0) {
+    auto it = std::find(mDisplays.begin(), mDisplays.end(), display);
+    if (it == mDisplays.end()) {
         mInvalidVsyncPeriodChangeCount++;
     }
 
@@ -134,4 +142,4 @@
     return Void();
 }
 
-}  // namespace android::hardware::graphics::composer::V2_4::vts
\ No newline at end of file
+}  // namespace android::hardware::graphics::composer::V2_4::vts
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h
index f4e23ae..c03070b 100644
--- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h
@@ -18,7 +18,7 @@
 #include <android/hardware/graphics/composer/2.4/IComposerCallback.h>
 
 #include <mutex>
-#include <unordered_set>
+#include <vector>
 
 namespace android::hardware::graphics::composer::V2_4::vts {
 
@@ -56,7 +56,7 @@
 
     mutable std::mutex mMutex;
     // the set of all currently connected displays
-    std::unordered_set<Display> mDisplays;
+    std::vector<Display> mDisplays;
     // true only when vsync is enabled
     bool mVsyncAllowed = true;
 
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
index 31b0dc7..a4eb0ca 100644
--- a/graphics/composer/2.4/vts/functional/OWNERS
+++ b/graphics/composer/2.4/vts/functional/OWNERS
@@ -1,5 +1,6 @@
 # Bug component: 25423
 # Graphics team
 adyabr@google.com
+alecmouri@google.com
 lpy@google.com
 sumir@google.com
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index b071f71..fa294ff 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -161,7 +161,8 @@
         return mGralloc->allocate(
                 width, height, /*layerCount*/ 1,
                 static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
-                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN));
+                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY));
     }
 
     struct TestParameters {
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index e33c653..2532a7a 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -31,12 +31,13 @@
         enabled: true,
         support_system_process: true,
     },
-    srcs: ["android/hardware/graphics/composer3/*.aidl"],
+    srcs: [
+        "android/hardware/graphics/composer3/*.aidl",
+    ],
     stability: "vintf",
     imports: [
         "android.hardware.graphics.common-V3",
         "android.hardware.common-V2",
-        "android.hardware.common.fmq-V1",
     ],
     backend: {
         cpp: {
@@ -54,25 +55,12 @@
     },
 }
 
-cc_library {
-    name: "android.hardware.graphics.composer3-translate-ndk",
-    vendor_available: true,
-    srcs: ["android/hardware/graphics/composer3/translate-ndk.cpp"],
-    shared_libs: [
-        "libbinder_ndk",
-        "libhidlbase",
-        "android.hardware.graphics.composer3-V1-ndk",
-        "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.composer@2.4",
-    ],
-    export_include_dirs: ["include"],
-}
-
 cc_library_headers {
     name: "android.hardware.graphics.composer3-command-buffer",
     vendor_available: true,
     shared_libs: [
         "android.hardware.graphics.composer3-V1-ndk",
+        "android.hardware.common-V2-ndk",
         "libbase",
         "libfmq",
         "libsync",
@@ -86,3 +74,16 @@
     ],
     export_include_dirs: ["include"],
 }
+
+cc_test {
+    name: "android.hardware.graphics.composer3-hidl2aidl-asserts",
+    vendor_available: true,
+    srcs: ["android/hardware/graphics/composer3/Hidl2AidlAsserts.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+        "libhidlbase",
+        "android.hardware.graphics.composer3-V1-ndk",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.4",
+    ],
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/BlendMode.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/BlendMode.aidl
deleted file mode 100644
index a522d53..0000000
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/BlendMode.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.graphics.composer3;
-@Backing(type="int") @VintfStability
-enum BlendMode {
-  INVALID = 0,
-  NONE = 1,
-  PREMULTIPLIED = 2,
-  COVERAGE = 3,
-}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Buffer.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Buffer.aidl
new file mode 100644
index 0000000..a33ad23
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Buffer.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable Buffer {
+  int slot;
+  @nullable android.hardware.common.NativeHandle handle;
+  @nullable ParcelFileDescriptor fence;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ChangedCompositionLayer.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ChangedCompositionLayer.aidl
new file mode 100644
index 0000000..7e47ba8
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ChangedCompositionLayer.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+parcelable ChangedCompositionLayer {
+  long layer;
+  android.hardware.graphics.composer3.Composition composition;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl
new file mode 100644
index 0000000..9a5ca97
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+parcelable ChangedCompositionTypes {
+  long display;
+  android.hardware.graphics.composer3.ChangedCompositionLayer[] layers;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTarget.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTarget.aidl
new file mode 100644
index 0000000..7632707
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTarget.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ClientTarget {
+  android.hardware.graphics.composer3.Buffer buffer;
+  android.hardware.graphics.common.Dataspace dataspace;
+  android.hardware.graphics.common.Rect[] damage;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
new file mode 100644
index 0000000..f0fb22e
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ClientTargetPropertyWithNits {
+  long display;
+  android.hardware.graphics.composer3.ClientTargetProperty clientTargetProperty;
+  float whitePointNits;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
new file mode 100644
index 0000000..480a85c
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ClockMonotonicTimestamp {
+  long timestampNanos;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Color.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Color.aidl
index 7733deb..8222909 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Color.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Color.aidl
@@ -34,8 +34,8 @@
 package android.hardware.graphics.composer3;
 @VintfStability
 parcelable Color {
-  byte r;
-  byte g;
-  byte b;
-  byte a;
+  float r;
+  float g;
+  float b;
+  float a;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Command.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Command.aidl
deleted file mode 100644
index e19105d..0000000
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Command.aidl
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.graphics.composer3;
-@Backing(type="int") @VintfStability
-enum Command {
-  LENGTH_MASK = 65535,
-  OPCODE_SHIFT = 16,
-  OPCODE_MASK = -65536,
-  SELECT_DISPLAY = 0,
-  SELECT_LAYER = 65536,
-  SET_ERROR = 16777216,
-  SET_CHANGED_COMPOSITION_TYPES = 16842752,
-  SET_DISPLAY_REQUESTS = 16908288,
-  SET_PRESENT_FENCE = 16973824,
-  SET_RELEASE_FENCES = 17039360,
-  SET_COLOR_TRANSFORM = 33554432,
-  SET_CLIENT_TARGET = 33619968,
-  SET_OUTPUT_BUFFER = 33685504,
-  VALIDATE_DISPLAY = 33751040,
-  ACCEPT_DISPLAY_CHANGES = 33816576,
-  PRESENT_DISPLAY = 33882112,
-  PRESENT_OR_VALIDATE_DISPLAY = 33947648,
-  SET_LAYER_CURSOR_POSITION = 50331648,
-  SET_LAYER_BUFFER = 50397184,
-  SET_LAYER_SURFACE_DAMAGE = 50462720,
-  SET_LAYER_BLEND_MODE = 67108864,
-  SET_LAYER_COLOR = 67174400,
-  SET_LAYER_COMPOSITION_TYPE = 67239936,
-  SET_LAYER_DATASPACE = 67305472,
-  SET_LAYER_DISPLAY_FRAME = 67371008,
-  SET_LAYER_PLANE_ALPHA = 67436544,
-  SET_LAYER_SIDEBAND_STREAM = 67502080,
-  SET_LAYER_SOURCE_CROP = 67567616,
-  SET_LAYER_TRANSFORM = 67633152,
-  SET_LAYER_VISIBLE_REGION = 67698688,
-  SET_LAYER_Z_ORDER = 67764224,
-  SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT = 67829760,
-  SET_LAYER_PER_FRAME_METADATA = 50528256,
-  SET_LAYER_FLOAT_COLOR = 67895296,
-  SET_LAYER_COLOR_TRANSFORM = 67960832,
-  SET_LAYER_PER_FRAME_METADATA_BLOBS = 50593792,
-  SET_CLIENT_TARGET_PROPERTY = 17104896,
-  SET_LAYER_GENERIC_METADATA = 68026368,
-  SET_LAYER_WHITE_POINT_NITS = 50659328,
-}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandError.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandError.aidl
new file mode 100644
index 0000000..103bfdc
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandError.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+parcelable CommandError {
+  int commandIndex;
+  int errorCode;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
new file mode 100644
index 0000000..ebbb31e
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+union CommandResultPayload {
+  android.hardware.graphics.composer3.CommandError error;
+  android.hardware.graphics.composer3.ChangedCompositionTypes changedCompositionTypes;
+  android.hardware.graphics.composer3.DisplayRequest displayRequest;
+  android.hardware.graphics.composer3.PresentFence presentFence;
+  android.hardware.graphics.composer3.ReleaseFences releaseFences;
+  android.hardware.graphics.composer3.PresentOrValidate presentOrValidateResult;
+  android.hardware.graphics.composer3.ClientTargetPropertyWithNits clientTargetProperty;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Composition.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Composition.aidl
index e327e87..d2d8f04 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Composition.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Composition.aidl
@@ -40,4 +40,5 @@
   SOLID_COLOR = 3,
   CURSOR = 4,
   SIDEBAND = 5,
+  DISPLAY_DECORATION = 6,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayBrightness.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayBrightness.aidl
new file mode 100644
index 0000000..be623df
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayBrightness.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+parcelable DisplayBrightness {
+  float brightness;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
index 0bcd870..b41ac8a 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -40,4 +40,7 @@
   BRIGHTNESS = 3,
   PROTECTED_CONTENTS = 4,
   AUTO_LOW_LATENCY_MODE = 5,
+  SUSPEND = 6,
+  DISPLAY_DECORATION = 7,
+  DISPLAY_IDLE_TIMER = 8,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
new file mode 100644
index 0000000..662240e
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable DisplayCommand {
+  long display;
+  android.hardware.graphics.composer3.LayerCommand[] layers;
+  @nullable float[] colorTransformMatrix;
+  @nullable android.hardware.graphics.composer3.DisplayBrightness brightness;
+  @nullable android.hardware.graphics.composer3.ClientTarget clientTarget;
+  @nullable android.hardware.graphics.composer3.Buffer virtualDisplayOutputBuffer;
+  @nullable android.hardware.graphics.composer3.ClockMonotonicTimestamp expectedPresentTime;
+  boolean validateDisplay;
+  boolean acceptDisplayChanges;
+  boolean presentDisplay;
+  boolean presentOrValidateDisplay;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl
index 26e7d97..13462ce 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl
@@ -32,8 +32,17 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.graphics.composer3;
-@Backing(type="int") @VintfStability
-enum DisplayRequest {
-  FLIP_CLIENT_TARGET = 1,
-  WRITE_CLIENT_TARGET_TO_OUTPUT = 2,
+@VintfStability
+parcelable DisplayRequest {
+  long display;
+  int mask;
+  android.hardware.graphics.composer3.DisplayRequest.LayerRequest[] layerRequests;
+  const int FLIP_CLIENT_TARGET = 1;
+  const int WRITE_CLIENT_TARGET_TO_OUTPUT = 2;
+  @VintfStability
+  parcelable LayerRequest {
+    long layer;
+    int mask;
+    const int CLEAR_CLIENT_TARGET = 1;
+  }
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ExecuteCommandsStatus.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ExecuteCommandsStatus.aidl
deleted file mode 100644
index 41a1afe..0000000
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ExecuteCommandsStatus.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.graphics.composer3;
-@VintfStability
-parcelable ExecuteCommandsStatus {
-  boolean queueChanged;
-  int length;
-  android.hardware.common.NativeHandle[] handles;
-}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/FloatColor.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/FloatColor.aidl
deleted file mode 100644
index faadf57..0000000
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/FloatColor.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.graphics.composer3;
-@VintfStability
-parcelable FloatColor {
-  float r;
-  float g;
-  float b;
-  float a;
-}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/HandleIndex.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/HandleIndex.aidl
deleted file mode 100644
index b87870d..0000000
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/HandleIndex.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.graphics.composer3;
-@Backing(type="int") @VintfStability
-enum HandleIndex {
-  EMPTY = -1,
-  CACHED = -2,
-}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
index f82d02e..21620e7 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -39,4 +39,5 @@
   oneway void onSeamlessPossible(long display);
   oneway void onVsync(long display, long timestamp, int vsyncPeriodNanos);
   oneway void onVsyncPeriodTimingChanged(long display, in android.hardware.graphics.composer3.VsyncPeriodChangeTimeline updatedTimeline);
+  oneway void onVsyncIdle(long display);
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index d7cab2b..2de699b 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -38,12 +38,11 @@
   android.hardware.graphics.composer3.VirtualDisplay createVirtualDisplay(int width, int height, android.hardware.graphics.common.PixelFormat formatHint, int outputBufferSlotCount);
   void destroyLayer(long display, long layer);
   void destroyVirtualDisplay(long display);
-  android.hardware.graphics.composer3.ExecuteCommandsStatus executeCommands(int inLength, in android.hardware.common.NativeHandle[] inHandles);
+  android.hardware.graphics.composer3.CommandResultPayload[] executeCommands(in android.hardware.graphics.composer3.DisplayCommand[] commands);
   int getActiveConfig(long display);
   android.hardware.graphics.composer3.ColorMode[] getColorModes(long display);
   float[] getDataspaceSaturationMatrix(android.hardware.graphics.common.Dataspace dataspace);
   int getDisplayAttribute(long display, int config, android.hardware.graphics.composer3.DisplayAttribute attribute);
-  boolean getDisplayBrightnessSupport(long display);
   android.hardware.graphics.composer3.DisplayCapability[] getDisplayCapabilities(long display);
   int[] getDisplayConfigs(long display);
   android.hardware.graphics.composer3.DisplayConnectionType getDisplayConnectionType(long display);
@@ -52,29 +51,29 @@
   int getDisplayVsyncPeriod(long display);
   android.hardware.graphics.composer3.DisplayContentSample getDisplayedContentSample(long display, long maxFrames, long timestamp);
   android.hardware.graphics.composer3.DisplayContentSamplingAttributes getDisplayedContentSamplingAttributes(long display);
-  boolean getDozeSupport(long display);
+  android.hardware.graphics.common.Transform getDisplayPhysicalOrientation(long display);
   android.hardware.graphics.composer3.HdrCapabilities getHdrCapabilities(long display);
-  android.hardware.graphics.composer3.LayerGenericMetadataKey[] getLayerGenericMetadataKeys();
   int getMaxVirtualDisplayCount();
-  android.hardware.common.fmq.MQDescriptor<int,android.hardware.common.fmq.SynchronizedReadWrite> getOutputCommandQueue();
   android.hardware.graphics.composer3.PerFrameMetadataKey[] getPerFrameMetadataKeys(long display);
   android.hardware.graphics.composer3.ReadbackBufferAttributes getReadbackBufferAttributes(long display);
-  ParcelFileDescriptor getReadbackBufferFence(long display);
+  @nullable ParcelFileDescriptor getReadbackBufferFence(long display);
   android.hardware.graphics.composer3.RenderIntent[] getRenderIntents(long display, android.hardware.graphics.composer3.ColorMode mode);
   android.hardware.graphics.composer3.ContentType[] getSupportedContentTypes(long display);
   void registerCallback(in android.hardware.graphics.composer3.IComposerCallback callback);
   void setActiveConfig(long display, int config);
   android.hardware.graphics.composer3.VsyncPeriodChangeTimeline setActiveConfigWithConstraints(long display, int config, in android.hardware.graphics.composer3.VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints);
+  void setBootDisplayConfig(long display, int config);
+  void clearBootDisplayConfig(long display);
+  int getPreferredBootDisplayConfig(long display);
   void setAutoLowLatencyMode(long display, boolean on);
   void setClientTargetSlotCount(long display, int clientTargetSlotCount);
   void setColorMode(long display, android.hardware.graphics.composer3.ColorMode mode, android.hardware.graphics.composer3.RenderIntent intent);
   void setContentType(long display, android.hardware.graphics.composer3.ContentType type);
-  void setDisplayBrightness(long display, float brightness);
   void setDisplayedContentSamplingEnabled(long display, boolean enable, android.hardware.graphics.composer3.FormatColorComponent componentMask, long maxFrames);
-  void setInputCommandQueue(in android.hardware.common.fmq.MQDescriptor<int,android.hardware.common.fmq.SynchronizedReadWrite> descriptor);
   void setPowerMode(long display, android.hardware.graphics.composer3.PowerMode mode);
-  void setReadbackBuffer(long display, in android.hardware.common.NativeHandle buffer, in ParcelFileDescriptor releaseFence);
+  void setReadbackBuffer(long display, in android.hardware.common.NativeHandle buffer, in @nullable ParcelFileDescriptor releaseFence);
   void setVsyncEnabled(long display, boolean enabled);
+  void setIdleTimerEnabled(long display, int timeoutMs);
   const int EX_BAD_CONFIG = 1;
   const int EX_BAD_DISPLAY = 2;
   const int EX_BAD_LAYER = 3;
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
new file mode 100644
index 0000000..c1c0117
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable LayerCommand {
+  long layer;
+  @nullable android.hardware.graphics.common.Point cursorPosition;
+  @nullable android.hardware.graphics.composer3.Buffer buffer;
+  @nullable android.hardware.graphics.common.Rect[] damage;
+  @nullable android.hardware.graphics.composer3.ParcelableBlendMode blendMode;
+  @nullable android.hardware.graphics.composer3.Color color;
+  @nullable android.hardware.graphics.composer3.ParcelableComposition composition;
+  @nullable android.hardware.graphics.composer3.ParcelableDataspace dataspace;
+  @nullable android.hardware.graphics.common.Rect displayFrame;
+  @nullable android.hardware.graphics.composer3.PlaneAlpha planeAlpha;
+  @nullable android.hardware.common.NativeHandle sidebandStream;
+  @nullable android.hardware.graphics.common.FRect sourceCrop;
+  @nullable android.hardware.graphics.composer3.ParcelableTransform transform;
+  @nullable android.hardware.graphics.common.Rect[] visibleRegion;
+  @nullable android.hardware.graphics.composer3.ZOrder z;
+  @nullable float[] colorTransform;
+  @nullable android.hardware.graphics.composer3.Luminance whitePointNits;
+  @nullable android.hardware.graphics.composer3.PerFrameMetadata[] perFrameMetadata;
+  @nullable android.hardware.graphics.composer3.PerFrameMetadataBlob[] perFrameMetadataBlob;
+  @nullable android.hardware.graphics.common.Rect[] blockingRegion;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerGenericMetadataKey.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerGenericMetadataKey.aidl
deleted file mode 100644
index 73385d4..0000000
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerGenericMetadataKey.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.graphics.composer3;
-@VintfStability
-parcelable LayerGenericMetadataKey {
-  String name;
-  boolean mandatory;
-}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerRequest.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerRequest.aidl
deleted file mode 100644
index cfafc50..0000000
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerRequest.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.graphics.composer3;
-@Backing(type="int") @VintfStability
-enum LayerRequest {
-  CLEAR_CLIENT_TARGET = 1,
-}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl
new file mode 100644
index 0000000..adb49a8
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable Luminance {
+  float nits;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableBlendMode.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableBlendMode.aidl
new file mode 100644
index 0000000..f1fee5f
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableBlendMode.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ParcelableBlendMode {
+  android.hardware.graphics.common.BlendMode blendMode;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableComposition.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableComposition.aidl
new file mode 100644
index 0000000..98fbb66
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableComposition.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ParcelableComposition {
+  android.hardware.graphics.composer3.Composition composition;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableDataspace.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableDataspace.aidl
new file mode 100644
index 0000000..76ecf85
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableDataspace.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ParcelableDataspace {
+  android.hardware.graphics.common.Dataspace dataspace;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableTransform.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableTransform.aidl
new file mode 100644
index 0000000..b673656
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ParcelableTransform.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ParcelableTransform {
+  android.hardware.graphics.common.Transform transform;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PlaneAlpha.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PlaneAlpha.aidl
new file mode 100644
index 0000000..c48c2a8
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PlaneAlpha.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable PlaneAlpha {
+  float alpha;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PresentFence.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PresentFence.aidl
new file mode 100644
index 0000000..3bb09cd
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PresentFence.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+parcelable PresentFence {
+  long display;
+  ParcelFileDescriptor fence;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PresentOrValidate.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PresentOrValidate.aidl
new file mode 100644
index 0000000..e6ddeba
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/PresentOrValidate.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+parcelable PresentOrValidate {
+  long display;
+  android.hardware.graphics.composer3.PresentOrValidate.Result result;
+  @VintfStability
+  enum Result {
+    Validated = 0,
+    Presented = 1,
+  }
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ReleaseFences.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ReleaseFences.aidl
new file mode 100644
index 0000000..d623661
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ReleaseFences.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.graphics.composer3;
+@VintfStability
+parcelable ReleaseFences {
+  long display;
+  android.hardware.graphics.composer3.ReleaseFences.Layer[] layers;
+  @VintfStability
+  parcelable Layer {
+    long layer;
+    ParcelFileDescriptor fence;
+  }
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ZOrder.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ZOrder.aidl
new file mode 100644
index 0000000..ea96ea3
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ZOrder.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ZOrder {
+  int z;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/BlendMode.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/BlendMode.aidl
deleted file mode 100644
index c6fd063..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/BlendMode.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-/**
- * Blend modes, settable per layer.
- */
-@VintfStability
-@Backing(type="int")
-enum BlendMode {
-    INVALID = 0,
-    /**
-     * colorOut = colorSrc
-     */
-    NONE = 1,
-    /**
-     * colorOut = colorSrc + colorDst * (1 - alphaSrc)
-     */
-    PREMULTIPLIED = 2,
-    /**
-     * colorOut = colorSrc * alphaSrc + colorDst * (1 - alphaSrc)
-     */
-    COVERAGE = 3,
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Buffer.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Buffer.aidl
new file mode 100644
index 0000000..415a9b6
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Buffer.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.common.NativeHandle;
+
+@VintfStability
+parcelable Buffer {
+    /**
+     * Buffer slot in the range [0, bufferSlotCount) where bufferSlotCount is
+     * the parameter used when the layer was created.
+     * @see IComposer.createLayer.
+     * The slot is used as a buffer caching mechanism. When the Buffer.handle
+     * is null, the implementation uses the previous buffer associated with this
+     * slot.
+     */
+    int slot;
+
+    /**
+     * Buffer Handle. Can be null if this is the same buffer that was sent
+     * previously on this slot.
+     */
+    @nullable NativeHandle handle;
+
+    /**
+     * Buffer fence that represents when it is safe to access the buffer.
+     * A null fence indicates that the buffer can be accessed immediately.
+     */
+    @nullable ParcelFileDescriptor fence;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionLayer.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionLayer.aidl
new file mode 100644
index 0000000..fb25163
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionLayer.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.Composition;
+
+@VintfStability
+parcelable ChangedCompositionLayer {
+    /**
+     * The layer which this commands refers to.
+     * @see IComposer.createLayer
+     */
+    long layer;
+
+    /**
+     * The new composition type.
+     */
+    Composition composition;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl
new file mode 100644
index 0000000..ddd45b7
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.ChangedCompositionLayer;
+import android.hardware.graphics.composer3.Composition;
+
+@VintfStability
+parcelable ChangedCompositionTypes {
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+
+    /**
+     * Indicates which layers has composition changes
+     */
+    ChangedCompositionLayer[] layers;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl
new file mode 100644
index 0000000..56488d5
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.common.Dataspace;
+import android.hardware.graphics.common.Rect;
+import android.hardware.graphics.composer3.Buffer;
+
+@VintfStability
+parcelable ClientTarget {
+    /**
+     * Client target Buffer
+     */
+    Buffer buffer;
+
+    /**
+     * The dataspace of the buffer, as described in LayerCommand.dataspace.
+     */
+    Dataspace dataspace;
+
+    /**
+     * The surface damage regions.
+     */
+    Rect[] damage;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
new file mode 100644
index 0000000..5037651
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.ClientTargetProperty;
+
+@VintfStability
+parcelable ClientTargetPropertyWithNits {
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+
+    /**
+     * The Client target property.
+     */
+    ClientTargetProperty clientTargetProperty;
+
+    /**
+     * The white points nits as described in CommandResultPayload.clientTargetProperty
+     */
+    float whitePointNits;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
new file mode 100644
index 0000000..0cfd1c4
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+/**
+ * Represents a nanoseconds timestamp in CLOCK_MONOTONIC.
+ */
+@VintfStability
+parcelable ClockMonotonicTimestamp {
+    long timestampNanos;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Color.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Color.aidl
index 979f677..151a854 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Color.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Color.aidl
@@ -16,10 +16,13 @@
 
 package android.hardware.graphics.composer3;
 
+/**
+ * Color representation as a floating point number in the range [0.0 - 1.0]
+ */
 @VintfStability
 parcelable Color {
-    byte r;
-    byte g;
-    byte b;
-    byte a;
+    float r;
+    float g;
+    float b;
+    float a;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Command.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Command.aidl
deleted file mode 100644
index 95c07ac..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Command.aidl
+++ /dev/null
@@ -1,763 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-import android.hardware.graphics.composer3.Command;
-
-/**
- * The command interface allows composer3 to reduce binder overhead by sending
- * atomic command stream in a command message queue. These commands are usually
- * sent on a per frame basic and contains the information that describes how the
- * display is composited. @see IComposerClient.executeCommands.
- */
-@VintfStability
-@Backing(type="int")
-enum Command {
-    LENGTH_MASK = 0xffff,
-    OPCODE_SHIFT = 16,
-    OPCODE_MASK = 0xffff << OPCODE_SHIFT,
-
-    // special commands
-
-    /**
-     * SELECT_DISPLAY has this pseudo prototype
-     *
-     *   selectDisplay(long display);
-     *
-     * Selects the current display implied by all other commands.
-     *
-     * @param display is the newly selected display.
-     */
-    SELECT_DISPLAY = 0x000 << OPCODE_SHIFT,
-
-    /**
-     * SELECT_LAYER has this pseudo prototype
-     *
-     *   selectLayer(long layer);
-     *
-     * Selects the current layer implied by all implicit layer commands.
-     *
-     * @param layer is the newly selected layer.
-     */
-    SELECT_LAYER = 0x001 << OPCODE_SHIFT,
-
-    // value commands (for return values)
-
-    /**
-     * SET_ERROR has this pseudo prototype
-     *
-     *   setError(uint32_t location, int error);
-     *
-     * Indicates an error generated by a command.
-     *
-     * @param location is the offset of the command in the input command
-     *        message queue.
-     * @param error is the error generated by the command.
-     */
-    SET_ERROR = 0x100 << OPCODE_SHIFT,
-
-    /**
-     * SET_CHANGED_COMPOSITION_TYPES has this pseudo prototype
-     *
-     *   setChangedCompositionTypes(long[] layers,
-     *                              Composition[] types);
-     *
-     * Sets the layers for which the device requires a different composition
-     * type than had been set prior to the last call to VALIDATE_DISPLAY. The
-     * client must either update its state with these types and call
-     * ACCEPT_DISPLAY_CHANGES, or must set new types and attempt to validate
-     * the display again.
-     *
-     * @param layers is an array of layer handles.
-     * @param types is an array of composition types, each corresponding to
-     *         an element of layers.
-     */
-    SET_CHANGED_COMPOSITION_TYPES = 0x101 << OPCODE_SHIFT,
-
-    /**
-     * SET_DISPLAY_REQUESTS has this pseudo prototype
-     *
-     *   setDisplayRequests(int displayRequestMask,
-     *                      long[] layers,
-     *                      int[] layerRequestMasks);
-     *
-     * Sets the display requests and the layer requests required for the last
-     * validated configuration.
-     *
-     * Display requests provide information about how the client must handle
-     * the client target. Layer requests provide information about how the
-     * client must handle an individual layer.
-     *
-     * @param displayRequestMask is the display requests for the current
-     *        validated state.
-     * @param layers is an array of layers which all have at least one
-     *        request.
-     * @param layerRequestMasks is the requests corresponding to each element
-     *        of layers.
-     */
-    SET_DISPLAY_REQUESTS = 0x102 << OPCODE_SHIFT,
-
-    /**
-     * SET_PRESENT_FENCE has this pseudo prototype
-     *
-     *   setPresentFence(int presentFenceIndex);
-     *
-     * Sets the present fence as a result of PRESENT_DISPLAY. For physical
-     * displays, this fence must be signaled at the vsync when the result
-     * of composition of this frame starts to appear (for video-mode panels)
-     * or starts to transfer to panel memory (for command-mode panels). For
-     * virtual displays, this fence must be signaled when writes to the output
-     * buffer have completed and it is safe to read from it.
-     *
-     * @param presentFenceIndex is an index into outHandles array.
-     */
-    SET_PRESENT_FENCE = 0x103 << OPCODE_SHIFT,
-
-    /**
-     * SET_RELEASE_FENCES has this pseudo prototype
-     *
-     *   setReleaseFences(long[] layers,
-     *                    int[] releaseFenceIndices);
-     *
-     * Sets the release fences for device layers on this display which will
-     * receive new buffer contents this frame.
-     *
-     * A release fence is a file descriptor referring to a sync fence object
-     * which must be signaled after the device has finished reading from the
-     * buffer presented in the prior frame. This indicates that it is safe to
-     * start writing to the buffer again. If a given layer's fence is not
-     * returned from this function, it must be assumed that the buffer
-     * presented on the previous frame is ready to be written.
-     *
-     * The fences returned by this function must be unique for each layer
-     * (even if they point to the same underlying sync object).
-     *
-     * @param layers is an array of layer handles.
-     * @param releaseFenceIndices are indices into outHandles array, each
-     *        corresponding to an element of layers.
-     */
-    SET_RELEASE_FENCES = 0x104 << OPCODE_SHIFT,
-
-    // display commands
-
-    /**
-     * SET_COLOR_TRANSFORM has this pseudo prototype
-     *
-     *   setColorTransform(float[16] matrix,
-     *                     ColorTransform hint);
-     *
-     * Sets a color transform which will be applied after composition.
-     *
-     * If hint is not ColorTransform::ARBITRARY, then the device may use the
-     * hint to apply the desired color transform instead of using the color
-     * matrix directly.
-     *
-     * If the device is not capable of either using the hint or the matrix to
-     * apply the desired color transform, it must force all layers to client
-     * composition during VALIDATE_DISPLAY.
-     *
-     * If IComposer::Capability::SKIP_CLIENT_COLOR_TRANSFORM is present, then
-     * the client must never apply the color transform during client
-     * composition, even if all layers are being composed by the client.
-     *
-     * The matrix provided is an affine color transformation of the following
-     * form:
-     *
-     * |r.r r.g r.b 0|
-     * |g.r g.g g.b 0|
-     * |b.r b.g b.b 0|
-     * |Tr  Tg  Tb  1|
-     *
-     * This matrix must be provided in row-major form:
-     *
-     * {r.r, r.g, r.b, 0, g.r, ...}.
-     *
-     * Given a matrix of this form and an input color [R_in, G_in, B_in], the
-     * output color [R_out, G_out, B_out] will be:
-     *
-     * R_out = R_in * r.r + G_in * g.r + B_in * b.r + Tr
-     * G_out = R_in * r.g + G_in * g.g + B_in * b.g + Tg
-     * B_out = R_in * r.b + G_in * g.b + B_in * b.b + Tb
-     *
-     * @param matrix is a 4x4 transform matrix (16 floats) as described above.
-     * @param hint is a hint value which may be used instead of the given
-     *        matrix unless it is ColorTransform::ARBITRARY.
-     */
-    SET_COLOR_TRANSFORM = 0x200 << OPCODE_SHIFT,
-
-    /**
-     * SET_CLIENT_TARGET has this pseudo prototype
-     *
-     *   setClientTarget(int targetSlot,
-     *                   int targetIndex,
-     *                   int acquireFenceIndex,
-     *                   android.hardware.graphics.common.Dataspace dataspace,
-     *                   Rect[] damage);
-     *
-     * Sets the buffer handle which will receive the output of client
-     * composition.  Layers marked as Composition::CLIENT must be composited
-     * into this buffer prior to the call to PRESENT_DISPLAY, and layers not
-     * marked as Composition::CLIENT must be composited with this buffer by
-     * the device.
-     *
-     * The buffer handle provided may be empty if no layers are being
-     * composited by the client. This must not result in an error (unless an
-     * invalid display handle is also provided).
-     *
-     * Also provides a file descriptor referring to an acquire sync fence
-     * object, which must be signaled when it is safe to read from the client
-     * target buffer.  If it is already safe to read from this buffer, an
-     * empty handle may be passed instead.
-     *
-     * For more about dataspaces, see SET_LAYER_DATASPACE.
-     *
-     * The damage parameter describes a surface damage region as defined in
-     * the description of SET_LAYER_SURFACE_DAMAGE.
-     *
-     * Will be called before PRESENT_DISPLAY if any of the layers are marked
-     * as Composition::CLIENT. If no layers are so marked, then it is not
-     * necessary to call this function. It is not necessary to call
-     * validateDisplay after changing the target through this function.
-     *
-     * @param targetSlot is the client target buffer slot to use.
-     * @param targetIndex is an index into inHandles for the new target
-     *        buffer.
-     * @param acquireFenceIndex is an index into inHandles for a sync fence
-     *        file descriptor as described above.
-     * @param dataspace is the dataspace of the buffer, as described in
-     *        setLayerDataspace.
-     * @param damage is the surface damage region.
-     *
-     */
-    SET_CLIENT_TARGET = 0x201 << OPCODE_SHIFT,
-
-    /**
-     * SET_OUTPUT_BUFFER has this pseudo prototype
-     *
-     *   setOutputBuffer(int bufferSlot,
-     *                   int bufferIndex,
-     *                   int releaseFenceIndex);
-     *
-     * Sets the output buffer for a virtual display. That is, the buffer to
-     * which the composition result will be written.
-     *
-     * Also provides a file descriptor referring to a release sync fence
-     * object, which must be signaled when it is safe to write to the output
-     * buffer. If it is already safe to write to the output buffer, an empty
-     * handle may be passed instead.
-     *
-     * Must be called at least once before PRESENT_DISPLAY, but does not have
-     * any interaction with layer state or display validation.
-     *
-     * @param bufferSlot is the new output buffer.
-     * @param bufferIndex is the new output buffer.
-     * @param releaseFenceIndex is a sync fence file descriptor as described
-     *        above.
-     */
-    SET_OUTPUT_BUFFER = 0x202 << OPCODE_SHIFT,
-
-    /**
-     * VALIDATE_DISPLAY has this pseudo prototype
-     *
-     *   validateDisplay();
-     *
-     * Instructs the device to inspect all of the layer state and determine if
-     * there are any composition type changes necessary before presenting the
-     * display. Permitted changes are described in the definition of
-     * Composition above.
-     */
-    VALIDATE_DISPLAY = 0x203 << OPCODE_SHIFT,
-
-    /**
-     * ACCEPT_DISPLAY_CHANGES has this pseudo prototype
-     *
-     *   acceptDisplayChanges();
-     *
-     * Accepts the changes required by the device from the previous
-     * validateDisplay call (which may be queried using
-     * getChangedCompositionTypes) and revalidates the display. This function
-     * is equivalent to requesting the changed types from
-     * getChangedCompositionTypes, setting those types on the corresponding
-     * layers, and then calling validateDisplay again.
-     *
-     * After this call it must be valid to present this display. Calling this
-     * after validateDisplay returns 0 changes must succeed with NONE, but
-     * must have no other effect.
-     */
-    ACCEPT_DISPLAY_CHANGES = 0x204 << OPCODE_SHIFT,
-
-    /**
-     * PRESENT_DISPLAY has this pseudo prototype
-     *
-     *   presentDisplay();
-     *
-     * Presents the current display contents on the screen (or in the case of
-     * virtual displays, into the output buffer).
-     *
-     * Prior to calling this function, the display must be successfully
-     * validated with validateDisplay. Note that setLayerBuffer and
-     * setLayerSurfaceDamage specifically do not count as layer state, so if
-     * there are no other changes to the layer state (or to the buffer's
-     * properties as described in setLayerBuffer), then it is safe to call
-     * this function without first validating the display.
-     */
-    PRESENT_DISPLAY = 0x205 << OPCODE_SHIFT,
-
-    /**
-     * PRESENT_OR_VALIDATE_DISPLAY has this pseudo prototype
-     *
-     *   presentOrValidateDisplay();
-     *
-     * Presents the current display contents on the screen (or in the case of
-     * virtual displays, into the output buffer) if validate can be skipped,
-     * or perform a VALIDATE_DISPLAY action instead.
-     */
-    PRESENT_OR_VALIDATE_DISPLAY = 0x206 << OPCODE_SHIFT,
-
-    // layer commands (VALIDATE_DISPLAY not required)
-
-    /**
-     * SET_LAYER_CURSOR_POSITION has this pseudo prototype
-     *
-     *   setLayerCursorPosition(int x, int y);
-     *
-     * Asynchronously sets the position of a cursor layer.
-     *
-     * Prior to validateDisplay, a layer may be marked as Composition::CURSOR.
-     * If validation succeeds (i.e., the device does not request a composition
-     * change for that layer), then once a buffer has been set for the layer
-     * and it has been presented, its position may be set by this function at
-     * any time between presentDisplay and any subsequent validateDisplay
-     * calls for this display.
-     *
-     * Once validateDisplay is called, this function must not be called again
-     * until the validate/present sequence is completed.
-     *
-     * May be called from any thread so long as it is not interleaved with the
-     * validate/present sequence as described above.
-     *
-     * @param layer is the layer to which the position is set.
-     * @param x is the new x coordinate (in pixels from the left of the
-     *        screen).
-     * @param y is the new y coordinate (in pixels from the top of the
-     *        screen).
-     */
-    SET_LAYER_CURSOR_POSITION = 0x300 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_BUFFER has this pseudo prototype
-     *
-     *   setLayerBuffer(int bufferSlot,
-     *                  int bufferIndex,
-     *                  int acquireFenceIndex);
-     *
-     * Sets the buffer handle to be displayed for this layer. If the buffer
-     * properties set at allocation time (width, height, format, and usage)
-     * have not changed since the previous frame, it is not necessary to call
-     * validateDisplay before calling presentDisplay unless new state needs to
-     * be validated in the interim.
-     *
-     * Also provides a file descriptor referring to an acquire sync fence
-     * object, which must be signaled when it is safe to read from the given
-     * buffer. If it is already safe to read from the buffer, an empty handle
-     * may be passed instead.
-     *
-     * This function must return NONE and have no other effect if called for a
-     * layer with a composition type of Composition::SOLID_COLOR (because it
-     * has no buffer) or Composition::SIDEBAND or Composition::CLIENT (because
-     * synchronization and buffer updates for these layers are handled
-     * elsewhere).
-     *
-     * @param layer is the layer to which the buffer is set.
-     * @param bufferSlot is the buffer slot to use.
-     * @param bufferIndex is the buffer handle to set.
-     * @param acquireFenceIndex is a sync fence file descriptor as described above.
-     */
-    SET_LAYER_BUFFER = 0x301 << OPCODE_SHIFT,
-
-    /*
-     * SET_LAYER_SURFACE_DAMAGE has this pseudo prototype
-     *
-     *   setLayerSurfaceDamage(Rect[] damage);
-     *
-     * Provides the region of the source buffer which has been modified since
-     * the last frame. This region does not need to be validated before
-     * calling presentDisplay.
-     *
-     * Once set through this function, the damage region remains the same
-     * until a subsequent call to this function.
-     *
-     * If damage is non-empty, then it may be assumed that any portion of the
-     * source buffer not covered by one of the rects has not been modified
-     * this frame. If damage is empty, then the whole source buffer must be
-     * treated as if it has been modified.
-     *
-     * If the layer's contents are not modified relative to the prior frame,
-     * damage must contain exactly one empty rect([0, 0, 0, 0]).
-     *
-     * The damage rects are relative to the pre-transformed buffer, and their
-     * origin is the top-left corner. They must not exceed the dimensions of
-     * the latched buffer.
-     *
-     * @param layer is the layer to which the damage region is set.
-     * @param damage is the new surface damage region.
-     */
-    SET_LAYER_SURFACE_DAMAGE = 0x302 << OPCODE_SHIFT,
-
-    // layer state commands (VALIDATE_DISPLAY required)
-
-    /**
-     * SET_LAYER_BLEND_MODE has this pseudo prototype
-     *
-     *   setLayerBlendMode(android.hardware.graphics.common.BlendMode mode)
-     *
-     * Sets the blend mode of the given layer.
-     *
-     * @param mode is the new blend mode.
-     */
-    SET_LAYER_BLEND_MODE = 0x400 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_COLOR has this pseudo prototype
-     *
-     *   setLayerColor(Color color);
-     *
-     * Sets the color of the given layer. If the composition type of the layer
-     * is not Composition::SOLID_COLOR, this call must succeed and have no
-     * other effect.
-     *
-     * @param color is the new color.
-     */
-    SET_LAYER_COLOR = 0x401 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_COMPOSITION_TYPE has this pseudo prototype
-     *
-     *   setLayerCompositionType(Composition type);
-     *
-     * Sets the desired composition type of the given layer. During
-     * validateDisplay, the device may request changes to the composition
-     * types of any of the layers as described in the definition of
-     * Composition above.
-     *
-     * @param type is the new composition type.
-     */
-    SET_LAYER_COMPOSITION_TYPE = 0x402 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_DATASPACE has this pseudo prototype
-     *
-     *   setLayerDataspace(android.hardware.graphics.common.Dataspace dataspace);
-     *
-     * Sets the dataspace of the layer.
-     *
-     * The dataspace provides more information about how to interpret the buffer
-     * or solid color, such as the encoding standard and color transform.
-     *
-     * See the values of Dataspace for more information.
-     *
-     * @param dataspace is the new dataspace.
-     */
-    SET_LAYER_DATASPACE = 0x403 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_DISPLAY_FRAME has this pseudo prototype
-     *
-     *   setLayerDisplayFrame(Rect frame);
-     *
-     * Sets the display frame (the portion of the display covered by a layer)
-     * of the given layer. This frame must not exceed the display dimensions.
-     *
-     * @param frame is the new display frame.
-     */
-    SET_LAYER_DISPLAY_FRAME = 0x404 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_PLANE_ALPHA has this pseudo prototype
-     *
-     *   setLayerPlaneAlpha(float alpha);
-     *
-     * Sets an alpha value (a floating point value in the range [0.0, 1.0])
-     * which will be applied to the whole layer. It can be conceptualized as a
-     * preprocessing step which applies the following function:
-     *   if (blendMode == BlendMode::PREMULTIPLIED)
-     *       out.rgb = in.rgb * planeAlpha
-     *   out.a = in.a * planeAlpha
-     *
-     * If the device does not support this operation on a layer which is
-     * marked Composition::DEVICE, it must request a composition type change
-     * to Composition::CLIENT upon the next validateDisplay call.
-     *
-     * @param alpha is the plane alpha value to apply.
-     */
-    SET_LAYER_PLANE_ALPHA = 0x405 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_SIDEBAND_STREAM has this pseudo prototype
-     *
-     *   setLayerSidebandStream(int streamIndex)
-     *
-     * Sets the sideband stream for this layer. If the composition type of the
-     * given layer is not Composition::SIDEBAND, this call must succeed and
-     * have no other effect.
-     *
-     * @param streamIndex is the new sideband stream.
-     */
-    SET_LAYER_SIDEBAND_STREAM = 0x406 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_SOURCE_CROP has this pseudo prototype
-     *
-     *   setLayerSourceCrop(FRect crop);
-     *
-     * Sets the source crop (the portion of the source buffer which will fill
-     * the display frame) of the given layer. This crop rectangle must not
-     * exceed the dimensions of the latched buffer.
-     *
-     * If the device is not capable of supporting a true float source crop
-     * (i.e., it will truncate or round the floats to integers), it must set
-     * this layer to Composition::CLIENT when crop is non-integral for the
-     * most accurate rendering.
-     *
-     * If the device cannot support float source crops, but still wants to
-     * handle the layer, it must use the following code (or similar) to
-     * convert to an integer crop:
-     *   intCrop.left = (int) ceilf(crop.left);
-     *   intCrop.top = (int) ceilf(crop.top);
-     *   intCrop.right = (int) floorf(crop.right);
-     *   intCrop.bottom = (int) floorf(crop.bottom);
-     *
-     * @param crop is the new source crop.
-     */
-    SET_LAYER_SOURCE_CROP = 0x407 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_TRANSFORM has this pseudo prototype
-     *
-     * Sets the transform (rotation/flip) of the given layer.
-     *
-     *   setLayerTransform(Transform transform);
-     *
-     * @param transform is the new transform.
-     */
-    SET_LAYER_TRANSFORM = 0x408 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_VISIBLE_REGION has this pseudo prototype
-     *
-     *   setLayerVisibleRegion(Rect[] visible);
-     *
-     * Specifies the portion of the layer that is visible, including portions
-     * under translucent areas of other layers. The region is in screen space,
-     * and must not exceed the dimensions of the screen.
-     *
-     * @param visible is the new visible region, in screen space.
-     */
-    SET_LAYER_VISIBLE_REGION = 0x409 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_Z_ORDER has this pseudo prototype
-     *
-     *   setLayerZOrder(int z);
-     *
-     * Sets the desired Z order (height) of the given layer. A layer with a
-     * greater Z value occludes a layer with a lesser Z value.
-     *
-     * @param z is the new Z order.
-     */
-    SET_LAYER_Z_ORDER = 0x40a << OPCODE_SHIFT,
-
-    /**
-     * SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT has this pseudo prototype
-     *
-     * setPresentOrValidateDisplayResult(int state);
-     *
-     * Sets the state of PRESENT_OR_VALIDATE_DISPLAY command.
-     * @param state is the state of present or validate
-     *    1 - Present Succeeded
-     *    0 - Validate succeeded
-     */
-    SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT = 0x40b << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_PER_FRAME_METADATA has this pseudo prototype
-     *
-     *   setLayerPerFrameMetadata(long display, long layer,
-     *                            PerFrameMetadata[] data);
-     *
-     * Sets the PerFrameMetadata for the display. This metadata must be used
-     * by the implementation to better tone map content to that display.
-     *
-     * This is a method that may be called every frame. Thus it's
-     * implemented using buffered transport.
-     * SET_LAYER_PER_FRAME_METADATA is the command used by the buffered transport
-     * mechanism.
-     */
-    SET_LAYER_PER_FRAME_METADATA = 0x303 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_FLOAT_COLOR has this pseudo prototype
-     *
-     *   setLayerColor(FloatColor color);
-     *
-     * Sets the color of the given layer. If the composition type of the layer
-     * is not Composition::SOLID_COLOR, this call must succeed and have no
-     * other effect.
-     *
-     * @param color is the new color using float type.
-     */
-    SET_LAYER_FLOAT_COLOR = 0x40c << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_COLOR_TRANSFORM has this pseudo prototype
-     *
-     *   setLayerColorTransform(float[16] matrix);
-     *
-     * This command has the following binary layout in bytes:
-     *
-     *     0 - 16 * 4: matrix
-     *
-     * Sets a matrix for color transform which will be applied on this layer
-     * before composition.
-     *
-     * If the device is not capable of apply the matrix on this layer, it must force
-     * this layer to client composition during VALIDATE_DISPLAY.
-     *
-     * The matrix provided is an affine color transformation of the following
-     * form:
-     *
-     * |r.r r.g r.b 0|
-     * |g.r g.g g.b 0|
-     * |b.r b.g b.b 0|
-     * |Tr  Tg  Tb  1|
-     *
-     * This matrix must be provided in row-major form:
-     *
-     * {r.r, r.g, r.b, 0, g.r, ...}.
-     *
-     * Given a matrix of this form and an input color [R_in, G_in, B_in],
-     * the input color must first be converted to linear space
-     * [R_linear, G_linear, B_linear], then the output linear color
-     * [R_out_linear, G_out_linear, B_out_linear] will be:
-     *
-     * R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
-     * G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
-     * B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
-     *
-     * [R_out_linear, G_out_linear, B_out_linear] must then be converted to
-     * gamma space: [R_out, G_out, B_out] before blending.
-     *
-     * @param matrix is a 4x4 transform matrix (16 floats) as described above.
-     */
-
-    SET_LAYER_COLOR_TRANSFORM = 0x40d << OPCODE_SHIFT,
-    /*
-     * SET_LAYER_PER_FRAME_METADATA_BLOBS has this pseudo prototype
-     *
-     *   setLayerPerFrameMetadataBlobs(long display, long layer,
-     *                                   PerFrameMetadataBlob[] metadata);
-     *
-     *   This command sends metadata that may be used for tone-mapping the
-     *   associated layer.  The metadata structure follows a {key, blob}
-     *   format (see the PerFrameMetadataBlob struct).  All keys must be
-     *   returned by a prior call to getPerFrameMetadataKeys and must
-     *   be part of the list of keys associated with blob-type metadata
-     *   (see PerFrameMetadataKey).
-     *
-     *   This method may be called every frame.
-     */
-    SET_LAYER_PER_FRAME_METADATA_BLOBS = 0x304 << OPCODE_SHIFT,
-
-    /**
-     * SET_CLIENT_TARGET_PROPERTY has this pseudo prototype
-     *
-     * This command has the following binary layout in bytes:
-     *
-     *     0 - 3: clientTargetProperty.pixelFormat
-     *     4 - 7: clientTargetProperty.dataspace
-     *     8 - 11: whitePointNits
-     *
-     * The white point parameter describes the intended white point of the client target buffer.
-     * When client composition blends both HDR and SDR content, the client must composite to the
-     * brightness space as specified by the hardware composer. This is so that adjusting the real
-     * display brightness may be applied atomically with compensating the client target output. For
-     * instance, client-compositing a list of SDR layers requires dimming the brightness space of
-     * the SDR buffers when an HDR layer is simultaneously device-composited.
-     *
-     *   setClientTargetProperty(ClientTargetProperty clientTargetProperty, float whitePointNits);
-     */
-    SET_CLIENT_TARGET_PROPERTY = 0x105 << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_GENERIC_METADATA has this pseudo prototype
-     *
-     *   setLayerGenericMetadata(string key, bool mandatory, byte[] value);
-     *
-     * Sets a piece of generic metadata for the given layer. If this
-     * function is called twice with the same key but different values, the
-     * newer value must override the older one. Calling this function with a
-     * 0-length value must reset that key's metadata as if it had not been
-     * set.
-     *
-     * A given piece of metadata may either be mandatory or a hint
-     * (non-mandatory) as indicated by the second parameter. Mandatory
-     * metadata may affect the composition result, which is to say that it
-     * may cause a visible change in the final image. By contrast, hints may
-     * only affect the composition strategy, such as which layers are
-     * composited by the client, but must not cause a visible change in the
-     * final image. The value of the mandatory flag shall match the value
-     * returned from getLayerGenericMetadataKeys for the given key.
-     *
-     * Only keys which have been returned from getLayerGenericMetadataKeys()
-     * shall be accepted. Any other keys must result in an UNSUPPORTED error.
-     *
-     * The value passed into this function shall be the binary
-     * representation of a HIDL type corresponding to the given key. For
-     * example, a key of 'com.example.V1_3.Foo' shall be paired with a
-     * value of type com.example@1.3::Foo, which would be defined in a
-     * vendor HAL extension.
-     *
-     * This function will be encoded in the command buffer in this order:
-     *   1) The key length, stored as a uint32_t
-     *   2) The key itself, padded to a uint32_t boundary if necessary
-     *   3) The mandatory flag, stored as a uint32_t
-     *   4) The value length in bytes, stored as a uint32_t
-     *   5) The value itself, padded to a uint32_t boundary if necessary
-     *
-     * @param key indicates which metadata value should be set on this layer
-     * @param mandatory indicates whether this particular key represents
-     *        mandatory metadata or a hint (non-mandatory metadata), as
-     *        described above
-     * @param value is a binary representation of a HIDL struct
-     *        corresponding to the key as described above
-     */
-    SET_LAYER_GENERIC_METADATA = 0x40e << OPCODE_SHIFT,
-
-    /**
-     * SET_LAYER_WHITE_POINT_NITS has this pseudo prototype
-     *
-     *   setLayerWhitePointNits(float sdrWhitePointNits);
-     *
-     * Sets the desired white point for the layer. This is intended to be used when presenting
-     * an SDR layer alongside HDR content. The HDR content will be presented at the display
-     * brightness in nits, and accordingly SDR content shall be dimmed to the desired white point
-     * provided.
-     *
-     * @param whitePointNits is the white point in nits.
-     */
-    SET_LAYER_WHITE_POINT_NITS = 0x305 << OPCODE_SHIFT,
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandError.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandError.aidl
new file mode 100644
index 0000000..ea48600
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandError.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable CommandError {
+    /**
+     * The index in the command payload array.
+     */
+    int commandIndex;
+    /**
+     * The error generated by the command. Can be one of the IComposerClient.EX_*
+     */
+    int errorCode;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
new file mode 100644
index 0000000..f2de68e
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.ChangedCompositionTypes;
+import android.hardware.graphics.composer3.ClientTargetPropertyWithNits;
+import android.hardware.graphics.composer3.CommandError;
+import android.hardware.graphics.composer3.DisplayRequest;
+import android.hardware.graphics.composer3.PresentFence;
+import android.hardware.graphics.composer3.PresentOrValidate;
+import android.hardware.graphics.composer3.ReleaseFences;
+
+@VintfStability
+union CommandResultPayload {
+    /**
+     * Indicates an error generated by a command.
+     */
+    CommandError error;
+
+    /**
+     * Sets the layers for which the device requires a different composition
+     * type than had been set prior to the last call to VALIDATE_DISPLAY. The
+     * client must either update its state with these types and call
+     * ACCEPT_DISPLAY_CHANGES, or must set new types and attempt to validate
+     * the display again.
+     */
+    ChangedCompositionTypes changedCompositionTypes;
+
+    /**
+     * Sets the display requests and the layer requests required for the last
+     * validated configuration.
+     *
+     * Display requests provide information about how the client must handle
+     * the client target. Layer requests provide information about how the
+     * client must handle an individual layer.
+     */
+    DisplayRequest displayRequest;
+
+    /**
+     * Sets the present fence as a result of PRESENT_DISPLAY. For physical
+     * displays, this fence must be signaled at the vsync when the result
+     * of composition of this frame starts to appear (for video-mode panels)
+     * or starts to transfer to panel memory (for command-mode panels). For
+     * virtual displays, this fence must be signaled when writes to the output
+     * buffer have completed and it is safe to read from it.
+     */
+    PresentFence presentFence;
+
+    /**
+     * Sets the release fences for device layers on this display which will
+     * receive new buffer contents this frame.
+     *
+     * A release fence is a file descriptor referring to a sync fence object
+     * which must be signaled after the device has finished reading from the
+     * buffer presented in the prior frame. This indicates that it is safe to
+     * start writing to the buffer again. If a given layer's fence is not
+     * returned from this function, it must be assumed that the buffer
+     * presented on the previous frame is ready to be written.
+     *
+     * The fences returned by this function must be unique for each layer
+     * (even if they point to the same underlying sync object).
+     *
+     */
+    ReleaseFences releaseFences;
+
+    /**
+     * Sets the state of PRESENT_OR_VALIDATE_DISPLAY command.
+     */
+    PresentOrValidate presentOrValidateResult;
+
+    /**
+     * The white point parameter describes the intended white point of the client target buffer.
+     * When client composition blends both HDR and SDR content, the client must composite to the
+     * brightness space as specified by the hardware composer. This is so that adjusting the real
+     * display brightness may be applied atomically with compensating the client target output. For
+     * instance, client-compositing a list of SDR layers requires dimming the brightness space of
+     * the SDR buffers when an HDR layer is simultaneously device-composited.
+     */
+    ClientTargetPropertyWithNits clientTargetProperty;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
index ea22af2..803de06 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
@@ -66,11 +66,25 @@
     /**
      * The device must handle the composition of this layer, as well as
      * its buffer updates and content synchronization. Only supported on
-     * devices which provide Capability::SIDEBAND_STREAM.
+     * devices which provide Capability.SIDEBAND_STREAM.
      *
      * Upon validateDisplay, the device may request a change from this
      * type to either DEVICE or CLIENT, but it is unlikely that content
      * will display correctly in these cases.
      */
     SIDEBAND = 5,
+    /**
+     * A display decoration layer contains a buffer which is used to provide
+     * anti-aliasing on the cutout region/rounded corners on the top and
+     * bottom of a display.
+     *
+     * Pixels in the buffer with an alpha of 0 (transparent) will show the
+     * content underneath, and pixels with a max alpha value will be rendered in
+     * black. An alpha in between will show the underlying content blended with
+     * black.
+     *
+     * Upon validateDisplay, the device may request a change from this type
+     * to either DEVICE or CLIENT.
+     */
+    DISPLAY_DECORATION = 6,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayBrightness.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayBrightness.aidl
new file mode 100644
index 0000000..f66b235
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayBrightness.aidl
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable DisplayBrightness {
+    /**
+     * A number between 0.0f (minimum brightness) and 1.0f (maximum brightness), a negative value to
+     * turn the backlight off.
+     */
+    float brightness;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
index 54f09c1..85136c4 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -41,14 +41,15 @@
      */
     SKIP_CLIENT_COLOR_TRANSFORM = 1,
     /**
-     * Indicates that the display supports PowerMode::DOZE and
-     * PowerMode::DOZE_SUSPEND. DOZE_SUSPEND may not provide any benefit
+     * Indicates that the display supports PowerMode.DOZE and
+     * potentially PowerMode.DOZE_SUSPEND if DisplayCapability.SUSPEND is also
+     * supported. DOZE_SUSPEND may not provide any benefit
      * over DOZE (see the definition of PowerMode for more information),
      * but if both DOZE and DOZE_SUSPEND are no different from
-     * PowerMode::ON, the device must not claim support.
+     * PowerMode.ON, the device must not claim support.
      * Must be returned by getDisplayCapabilities when getDozeSupport
-     * indicates the display supports PowerMode::DOZE and
-     * PowerMode::DOZE_SUSPEND.
+     * indicates the display supports PowerMode.DOZE and
+     * PowerMode.DOZE_SUSPEND.
      */
     DOZE = 2,
     /**
@@ -66,4 +67,21 @@
      * support a low latency mode, such as HDMI 2.1 Auto Low Latency Mode.
      */
     AUTO_LOW_LATENCY_MODE = 5,
+    /**
+     * Indicates that the display supports PowerMode.ON_SUSPEND.
+     * If PowerMode.ON_SUSPEND is no different from PowerMode.ON, the device must not
+     * claim support.
+     * If the display supports DisplayCapability.DOZE and DisplayCapability.SUSPEND, then
+     * PowerMode.ON_SUSPEND and PowerMode.DOZE_SUSPEND must be supported.
+     */
+    SUSPEND = 6,
+    /**
+     * Indicates that the display supports Composition.DISPLAY_DECORATION.
+     */
+    DISPLAY_DECORATION = 7,
+    /**
+     * Indicates that the display supports IComposerClient.setIdleTimerEnabled and
+     * IComposerCallback.onVsyncIdle.
+     */
+    DISPLAY_IDLE_TIMER = 8,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
new file mode 100644
index 0000000..f1ce1a7
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -0,0 +1,186 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.Buffer;
+import android.hardware.graphics.composer3.ClientTarget;
+import android.hardware.graphics.composer3.ClockMonotonicTimestamp;
+import android.hardware.graphics.composer3.DisplayBrightness;
+import android.hardware.graphics.composer3.LayerCommand;
+
+@VintfStability
+parcelable DisplayCommand {
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+
+    /**
+     * Sets layer commands for this display.
+     * @see LayerCommand.
+     */
+    LayerCommand[] layers;
+
+    /**
+     * Sets a color transform which will be applied after composition.
+     *
+     * If the device is not capable of either using the matrix to
+     * apply the desired color transform, it must force all layers to client
+     * composition during VALIDATE_DISPLAY.
+     *
+     * If Capability.SKIP_CLIENT_COLOR_TRANSFORM is present, then
+     * the client must never apply the color transform during client
+     * composition, even if all layers are being composed by the client.
+     *
+     * The matrix provided is an affine color transformation of the following
+     * form:
+     *
+     * |r.r r.g r.b 0|
+     * |g.r g.g g.b 0|
+     * |b.r b.g b.b 0|
+     * |Tr  Tg  Tb  1|
+     *
+     * This matrix must be provided in row-major form:
+     *
+     * {r.r, r.g, r.b, 0, g.r, ...}.
+     *
+     * Given a matrix of this form and an input color [R_in, G_in, B_in], the
+     * output color [R_out, G_out, B_out] will be:
+     *
+     * R_out = R_in * r.r + G_in * g.r + B_in * b.r + Tr
+     * G_out = R_in * r.g + G_in * g.g + B_in * b.g + Tg
+     * B_out = R_in * r.b + G_in * g.b + B_in * b.b + Tb
+     *
+     */
+    @nullable float[] colorTransformMatrix;
+
+    /**
+     * Sets the desired brightness of the display.
+     *
+     * Ideally, the brightness of the display will take effect within this frame so that it can be
+     * aligned with color transforms. Some display architectures may take multiple frames to apply
+     * the display brightness, for example when internally switching the display between multiple
+     * power modes to achieve higher luminance. In those cases, the underlying display panel's real
+     * brightness may not be applied atomically; however, layer dimming when mixing HDR and SDR
+     * content must be synchronized.
+     *
+     * As an illustrative example: suppose two layers have white
+     * points of 200 nits and 1000 nits respectively, the old display luminance is 200 nits, and the
+     * new display luminance is 1000 nits. If the new display luminance takes two frames to apply,
+     * then: In the first frame, there must not be any relative dimming of layers (treat both layers
+     * as 200 nits as the maximum luminance of the display is 200 nits). In the second frame, there
+     * dimming should be applied to ensure that the first layer does not become perceptually
+     * brighter during the transition.
+     *
+     * The display luminance must be updated by this command even if there is not pending validate
+     * or present command.
+     */
+    @nullable DisplayBrightness brightness;
+
+    /**
+     * Sets the buffer handle which will receive the output of client
+     * composition.  Layers marked as Composition.CLIENT must be composited
+     * into this buffer prior to the call to PRESENT_DISPLAY, and layers not
+     * marked as Composition.CLIENT must be composited with this buffer by
+     * the device.
+     *
+     * The buffer handle provided may be empty if no layers are being
+     * composited by the client. This must not result in an error (unless an
+     * invalid display handle is also provided).
+     *
+     * Also provides a file descriptor referring to an acquire sync fence
+     * object, which must be signaled when it is safe to read from the client
+     * target buffer.  If it is already safe to read from this buffer, an
+     * empty handle may be passed instead.
+     *
+     * For more about dataspaces, see SET_LAYER_DATASPACE.
+     *
+     * The damage parameter describes a surface damage region as defined in
+     * the description of SET_LAYER_SURFACE_DAMAGE.
+     *
+     * Will be called before PRESENT_DISPLAY if any of the layers are marked
+     * as Composition.CLIENT. If no layers are so marked, then it is not
+     * necessary to call this function. It is not necessary to call
+     * validateDisplay after changing the target through this function.
+     */
+    @nullable ClientTarget clientTarget;
+
+    /**
+     * Sets the output buffer for a virtual display. That is, the buffer to
+     * which the composition result will be written.
+     *
+     * Also provides a file descriptor referring to a release sync fence
+     * object, which must be signaled when it is safe to write to the output
+     * buffer. If it is already safe to write to the output buffer, an empty
+     * handle may be passed instead.
+     *
+     * Must be called at least once before PRESENT_DISPLAY, but does not have
+     * any interaction with layer state or display validation.
+     */
+    @nullable Buffer virtualDisplayOutputBuffer;
+
+    /**
+     * Sets the expected present time to present the current content on screen.
+     * The implementation should try to present the display as close as possible
+     * to the given expectedPresentTime. If expectedPresentTime is 0, the
+     * implementation should present the display as soon as possible.
+     */
+    @nullable ClockMonotonicTimestamp expectedPresentTime;
+
+    /**
+     * Instructs the device to inspect all of the layer state and determine if
+     * there are any composition type changes necessary before presenting the
+     * display. Permitted changes are described in the definition of
+     * Composition above.
+     */
+    boolean validateDisplay;
+
+    /**
+     * Accepts the changes required by the device from the previous
+     * validateDisplay call (which may be queried using
+     * getChangedCompositionTypes) and revalidates the display. This function
+     * is equivalent to requesting the changed types from
+     * getChangedCompositionTypes, setting those types on the corresponding
+     * layers, and then calling validateDisplay again.
+     *
+     * After this call it must be valid to present this display. Calling this
+     * after validateDisplay returns 0 changes must succeed with NONE, but
+     * must have no other effect.
+     */
+    boolean acceptDisplayChanges;
+
+    /**
+     * Presents the current display contents on the screen (or in the case of
+     * virtual displays, into the output buffer).
+     *
+     * Prior to calling this function, the display must be successfully
+     * validated with validateDisplay. Note that setLayerBuffer and
+     * setLayerSurfaceDamage specifically do not count as layer state, so if
+     * there are no other changes to the layer state (or to the buffer's
+     * properties as described in setLayerBuffer), then it is safe to call
+     * this function without first validating the display.
+     */
+    boolean presentDisplay;
+
+    /**
+     * Presents the current display contents on the screen (or in the case of
+     * virtual displays, into the output buffer) if validate can be skipped,
+     * or perform a VALIDATE_DISPLAY action instead.
+     */
+    boolean presentOrValidateDisplay;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl
index 4b3d31a..27fe1e6 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl
@@ -16,22 +16,57 @@
 
 package android.hardware.graphics.composer3;
 
-/**
- * Display requests returned by getDisplayRequests.
- */
 @VintfStability
-@Backing(type="int")
-enum DisplayRequest {
+parcelable DisplayRequest {
     /**
      * Instructs the client to provide a new client target buffer, even if
      * no layers are marked for client composition.
      */
-    FLIP_CLIENT_TARGET = 1 << 0,
+    const int FLIP_CLIENT_TARGET = 1 << 0;
+
     /**
      * Instructs the client to write the result of client composition
      * directly into the virtual display output buffer. If any of the
-     * layers are not marked as Composition::CLIENT or the given display
+     * layers are not marked as Composition.CLIENT or the given display
      * is not a virtual display, this request has no effect.
      */
-    WRITE_CLIENT_TARGET_TO_OUTPUT = 1 << 1,
+    const int WRITE_CLIENT_TARGET_TO_OUTPUT = 1 << 1;
+
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+
+    /**
+     * The display requests for the current validated state. This must be a
+     * bitwise-or of the constants in `DisplayRequest`.
+     */
+    int mask;
+
+    @VintfStability
+    parcelable LayerRequest {
+        /**
+         * The client must clear its target with transparent pixels where
+         * this layer would be. The client may ignore this request if the
+         * layer must be blended.
+         */
+        const int CLEAR_CLIENT_TARGET = 1 << 0;
+
+        /**
+         * The layer which this commands refers to.
+         * @see IComposer.createLayer
+         */
+        long layer;
+        /**
+         * The layer requests for the current validated state. This must be a
+         * bitwise-or of the constants in `LayerRequest`.
+         */
+        int mask;
+    }
+
+    /**
+     * The layer requests for the current validated state.
+     */
+    LayerRequest[] layerRequests;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ExecuteCommandsStatus.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ExecuteCommandsStatus.aidl
deleted file mode 100644
index f67c3ce..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ExecuteCommandsStatus.aidl
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-/**
- * Output parameters for IComposerClient.executeCommands
- */
-@VintfStability
-parcelable ExecuteCommandsStatus {
-    /**
-     * Indicates whether the output command message queue has changed.
-     */
-    boolean queueChanged;
-    /**
-     * Indicates whether the output command message queue has changed.
-     */
-    int length;
-    /**
-     * An array of handles referenced by the output commands.
-     */
-    android.hardware.common.NativeHandle[] handles;
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/FloatColor.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/FloatColor.aidl
deleted file mode 100644
index a0a1d4b..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/FloatColor.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-/**
- * Color representation as a floating point number in the range [0.0 - 1.0]
- */
-
-@VintfStability
-parcelable FloatColor {
-    float r;
-    float g;
-    float b;
-    float a;
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/HandleIndex.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/HandleIndex.aidl
deleted file mode 100644
index 0a93c9e..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/HandleIndex.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-/**
- * Special index values (always negative) for command queue commands.
- */
-@VintfStability
-@Backing(type="int")
-enum HandleIndex {
-    /**
-     * No handle
-     */
-    EMPTY = -1,
-    /**
-     * Use cached handle
-     */
-    CACHED = -2,
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Hidl2AidlAsserts.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/Hidl2AidlAsserts.cpp
new file mode 100644
index 0000000..d2cabff
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Hidl2AidlAsserts.cpp
@@ -0,0 +1,353 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl/android/hardware/graphics/common/BlendMode.h"
+#include "aidl/android/hardware/graphics/common/FRect.h"
+#include "aidl/android/hardware/graphics/common/Rect.h"
+#include "aidl/android/hardware/graphics/composer3/Capability.h"
+#include "aidl/android/hardware/graphics/composer3/ClientTargetProperty.h"
+#include "aidl/android/hardware/graphics/composer3/Color.h"
+#include "aidl/android/hardware/graphics/composer3/Composition.h"
+#include "aidl/android/hardware/graphics/composer3/ContentType.h"
+#include "aidl/android/hardware/graphics/composer3/DisplayAttribute.h"
+#include "aidl/android/hardware/graphics/composer3/DisplayCapability.h"
+#include "aidl/android/hardware/graphics/composer3/DisplayConnectionType.h"
+#include "aidl/android/hardware/graphics/composer3/FormatColorComponent.h"
+#include "aidl/android/hardware/graphics/composer3/IComposer.h"
+#include "aidl/android/hardware/graphics/composer3/PerFrameMetadata.h"
+#include "aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h"
+#include "aidl/android/hardware/graphics/composer3/PerFrameMetadataKey.h"
+#include "aidl/android/hardware/graphics/composer3/PowerMode.h"
+#include "aidl/android/hardware/graphics/composer3/VsyncPeriodChangeConstraints.h"
+#include "aidl/android/hardware/graphics/composer3/VsyncPeriodChangeTimeline.h"
+#include "android/hardware/graphics/composer/2.1/IComposer.h"
+#include "android/hardware/graphics/composer/2.1/IComposerCallback.h"
+#include "android/hardware/graphics/composer/2.1/IComposerClient.h"
+#include "android/hardware/graphics/composer/2.2/IComposerClient.h"
+#include "android/hardware/graphics/composer/2.3/IComposerClient.h"
+#include "android/hardware/graphics/composer/2.4/IComposerClient.h"
+#include "android/hardware/graphics/composer/2.4/types.h"
+
+namespace android::h2a {
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposer::EX_NO_RESOURCES ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::NO_RESOURCES));
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_CONFIG ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_CONFIG));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_DISPLAY ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_DISPLAY));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_LAYER ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_LAYER));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_PARAMETER ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_PARAMETER));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_NO_RESOURCES ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::NO_RESOURCES));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_NOT_VALIDATED ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::NOT_VALIDATED));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_UNSUPPORTED ==
+        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_SEAMLESS_NOT_ALLOWED ==
+        static_cast<int32_t>(
+                ::android::hardware::graphics::composer::V2_4::Error::SEAMLESS_NOT_ALLOWED));
+static_assert(
+        aidl::android::hardware::graphics::composer3::IComposerClient::EX_SEAMLESS_NOT_POSSIBLE ==
+        static_cast<int32_t>(
+                ::android::hardware::graphics::composer::V2_4::Error::SEAMLESS_NOT_POSSIBLE));
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::Capability::INVALID ==
+        static_cast<aidl::android::hardware::graphics::composer3::Capability>(
+                ::android::hardware::graphics::composer::V2_1::IComposer::Capability::INVALID));
+static_assert(aidl::android::hardware::graphics::composer3::Capability::SIDEBAND_STREAM ==
+              static_cast<aidl::android::hardware::graphics::composer3::Capability>(
+                      ::android::hardware::graphics::composer::V2_1::IComposer::Capability::
+                              SIDEBAND_STREAM));
+static_assert(
+        aidl::android::hardware::graphics::composer3::Capability::SKIP_CLIENT_COLOR_TRANSFORM ==
+        static_cast<aidl::android::hardware::graphics::composer3::Capability>(
+                ::android::hardware::graphics::composer::V2_1::IComposer::Capability::
+                        SKIP_CLIENT_COLOR_TRANSFORM));
+static_assert(
+        aidl::android::hardware::graphics::composer3::Capability::PRESENT_FENCE_IS_NOT_RELIABLE ==
+        static_cast<aidl::android::hardware::graphics::composer3::Capability>(
+                ::android::hardware::graphics::composer::V2_1::IComposer::Capability::
+                        PRESENT_FENCE_IS_NOT_RELIABLE));
+// HWC2_CAPABILITY_SKIP_VALIDATE was never defined for HIDL, so we just hardcode its value
+static_assert(aidl::android::hardware::graphics::composer3::Capability::SKIP_VALIDATE ==
+              static_cast<aidl::android::hardware::graphics::composer3::Capability>(4));
+
+static_assert(aidl::android::hardware::graphics::composer3::DisplayRequest::LayerRequest::
+                      CLEAR_CLIENT_TARGET ==
+              static_cast<int>(::android::hardware::graphics::composer::V2_1::IComposerClient::
+                                       LayerRequest::CLEAR_CLIENT_TARGET));
+
+static_assert(aidl::android::hardware::graphics::common::BlendMode::INVALID ==
+              static_cast<aidl::android::hardware::graphics::common::BlendMode>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::
+                              INVALID));
+static_assert(
+        aidl::android::hardware::graphics::common::BlendMode::NONE ==
+        static_cast<aidl::android::hardware::graphics::common::BlendMode>(
+                ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::NONE));
+static_assert(aidl::android::hardware::graphics::common::BlendMode::PREMULTIPLIED ==
+              static_cast<aidl::android::hardware::graphics::common::BlendMode>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::
+                              PREMULTIPLIED));
+static_assert(aidl::android::hardware::graphics::common::BlendMode::COVERAGE ==
+              static_cast<aidl::android::hardware::graphics::common::BlendMode>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::
+                              COVERAGE));
+
+static_assert(aidl::android::hardware::graphics::composer3::Composition::INVALID ==
+              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
+                              INVALID));
+static_assert(aidl::android::hardware::graphics::composer3::Composition::CLIENT ==
+              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
+                              CLIENT));
+static_assert(aidl::android::hardware::graphics::composer3::Composition::DEVICE ==
+              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
+                              DEVICE));
+static_assert(aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR ==
+              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
+                              SOLID_COLOR));
+static_assert(aidl::android::hardware::graphics::composer3::Composition::CURSOR ==
+              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
+                              CURSOR));
+static_assert(aidl::android::hardware::graphics::composer3::Composition::SIDEBAND ==
+              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
+                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
+                              SIDEBAND));
+
+static_assert(aidl::android::hardware::graphics::composer3::DisplayRequest::FLIP_CLIENT_TARGET ==
+              static_cast<int>(::android::hardware::graphics::composer::V2_1::IComposerClient::
+                                       DisplayRequest::FLIP_CLIENT_TARGET));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayRequest::
+                      WRITE_CLIENT_TARGET_TO_OUTPUT ==
+              static_cast<int>(::android::hardware::graphics::composer::V2_1::IComposerClient::
+                                       DisplayRequest::WRITE_CLIENT_TARGET_TO_OUTPUT));
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::PowerMode::OFF ==
+        static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
+                ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::OFF));
+static_assert(
+        aidl::android::hardware::graphics::composer3::PowerMode::DOZE ==
+        static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
+                ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::DOZE));
+static_assert(aidl::android::hardware::graphics::composer3::PowerMode::DOZE_SUSPEND ==
+              static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
+                      ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::
+                              DOZE_SUSPEND));
+static_assert(
+        aidl::android::hardware::graphics::composer3::PowerMode::ON ==
+        static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
+                ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::ON));
+static_assert(aidl::android::hardware::graphics::composer3::PowerMode::ON_SUSPEND ==
+              static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
+                      ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::
+                              ON_SUSPEND));
+
+static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::INVALID ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
+                              DisplayCapability::INVALID));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::
+                      SKIP_CLIENT_COLOR_TRANSFORM ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
+                              DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::DOZE ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
+                              DisplayCapability::DOZE));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::BRIGHTNESS ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
+                              DisplayCapability::BRIGHTNESS));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::PROTECTED_CONTENTS ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
+                              DisplayCapability::PROTECTED_CONTENTS));
+static_assert(
+        aidl::android::hardware::graphics::composer3::DisplayCapability::AUTO_LOW_LATENCY_MODE ==
+        static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
+                ::android::hardware::graphics::composer::V2_4::IComposerClient::DisplayCapability::
+                        AUTO_LOW_LATENCY_MODE));
+
+static_assert(aidl::android::hardware::graphics::composer3::DisplayAttribute::INVALID ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::
+                              INVALID));
+static_assert(
+        aidl::android::hardware::graphics::composer3::DisplayAttribute::WIDTH ==
+        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
+                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::WIDTH));
+static_assert(
+        aidl::android::hardware::graphics::composer3::DisplayAttribute::HEIGHT ==
+        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
+                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::HEIGHT));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayAttribute::VSYNC_PERIOD ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::
+                              VSYNC_PERIOD));
+static_assert(
+        aidl::android::hardware::graphics::composer3::DisplayAttribute::DPI_X ==
+        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
+                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::DPI_X));
+static_assert(
+        aidl::android::hardware::graphics::composer3::DisplayAttribute::DPI_Y ==
+        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
+                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::DPI_Y));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayAttribute::CONFIG_GROUP ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::
+                              CONFIG_GROUP));
+
+static_assert(aidl::android::hardware::graphics::composer3::DisplayConnectionType::INTERNAL ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayConnectionType>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
+                              DisplayConnectionType::INTERNAL));
+static_assert(aidl::android::hardware::graphics::composer3::DisplayConnectionType::EXTERNAL ==
+              static_cast<aidl::android::hardware::graphics::composer3::DisplayConnectionType>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
+                              DisplayConnectionType::EXTERNAL));
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X ==
+        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X));
+static_assert(
+        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y ==
+        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
+                      DISPLAY_GREEN_PRIMARY_X ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
+                      DISPLAY_GREEN_PRIMARY_Y ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y));
+static_assert(
+        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X ==
+        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X));
+static_assert(
+        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y ==
+        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::WHITE_POINT_X ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::WHITE_POINT_X));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::WHITE_POINT_Y ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::WHITE_POINT_Y));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::MAX_LUMINANCE ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::MAX_LUMINANCE));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::MIN_LUMINANCE ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::MIN_LUMINANCE));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
+                      MAX_CONTENT_LIGHT_LEVEL ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
+                      MAX_FRAME_AVERAGE_LIGHT_LEVEL ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL));
+static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::HDR10_PLUS_SEI ==
+              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
+                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                              PerFrameMetadataKey::HDR10_PLUS_SEI));
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_0 ==
+        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        FormatColorComponent::FORMAT_COMPONENT_0));
+static_assert(
+        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_1 ==
+        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        FormatColorComponent::FORMAT_COMPONENT_1));
+static_assert(
+        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_2 ==
+        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        FormatColorComponent::FORMAT_COMPONENT_2));
+static_assert(
+        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_3 ==
+        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
+                ::android::hardware::graphics::composer::V2_3::IComposerClient::
+                        FormatColorComponent::FORMAT_COMPONENT_3));
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::ContentType::NONE ==
+        static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
+                ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::NONE));
+static_assert(aidl::android::hardware::graphics::composer3::ContentType::GRAPHICS ==
+              static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::
+                              GRAPHICS));
+static_assert(aidl::android::hardware::graphics::composer3::ContentType::PHOTO ==
+              static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::
+                              PHOTO));
+static_assert(aidl::android::hardware::graphics::composer3::ContentType::CINEMA ==
+              static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
+                      ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::
+                              CINEMA));
+static_assert(
+        aidl::android::hardware::graphics::composer3::ContentType::GAME ==
+        static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
+                ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::GAME));
+
+static_assert(
+        aidl::android::hardware::graphics::composer3::PresentOrValidate::Result::Presented ==
+        static_cast<aidl::android::hardware::graphics::composer3::PresentOrValidate::Result>(1));
+static_assert(
+        aidl::android::hardware::graphics::composer3::PresentOrValidate::Result::Validated ==
+        static_cast<aidl::android::hardware::graphics::composer3::PresentOrValidate::Result>(0));
+
+}  // namespace android::h2a
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl
index a6a9f73..b8edd80 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl
@@ -27,7 +27,7 @@
     const int EX_NO_RESOURCES = 6;
 
     /**
-     * Creates a v2.4 client of the composer. Supersedes @2.3::createClient.
+     * Creates a client of the composer.
      *
      * @return is the newly created client.
      *
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
index 1709e6d..67954d4 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -26,7 +26,7 @@
      * must trigger at least one hotplug notification, even if it only occurs
      * immediately after callback registration.
      *
-     * Displays which have been connected are assumed to be in PowerMode::OFF,
+     * Displays which have been connected are assumed to be in PowerMode.OFF,
      * and the onVsync callback should not be called for a display until vsync
      * has been enabled with setVsyncEnabled.
      *
@@ -86,4 +86,14 @@
      */
     oneway void onVsyncPeriodTimingChanged(
             long display, in VsyncPeriodChangeTimeline updatedTimeline);
+
+    /**
+     * Notifies the client that the display is idle, the refresh rate changed to a lower setting to
+     * preserve power and vsync cadence changed. When a new frame is queued for presentation, the
+     * client is expected to enable vsync callbacks to learn the new vsync cadence before sending
+     * a new frame.
+     *
+     * @param display is the display whose vsync cadence changed due to panel idle mode.
+     */
+    oneway void onVsyncIdle(long display);
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 230980d..2fe6656 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -16,23 +16,21 @@
 
 package android.hardware.graphics.composer3;
 
-import android.hardware.common.fmq.MQDescriptor;
-import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.graphics.common.Transform;
 import android.hardware.graphics.composer3.ClientTargetProperty;
 import android.hardware.graphics.composer3.ColorMode;
-import android.hardware.graphics.composer3.Command;
+import android.hardware.graphics.composer3.CommandResultPayload;
 import android.hardware.graphics.composer3.ContentType;
 import android.hardware.graphics.composer3.DisplayAttribute;
 import android.hardware.graphics.composer3.DisplayCapability;
+import android.hardware.graphics.composer3.DisplayCommand;
 import android.hardware.graphics.composer3.DisplayConnectionType;
 import android.hardware.graphics.composer3.DisplayContentSample;
 import android.hardware.graphics.composer3.DisplayContentSamplingAttributes;
 import android.hardware.graphics.composer3.DisplayIdentification;
-import android.hardware.graphics.composer3.ExecuteCommandsStatus;
 import android.hardware.graphics.composer3.FormatColorComponent;
 import android.hardware.graphics.composer3.HdrCapabilities;
 import android.hardware.graphics.composer3.IComposerCallback;
-import android.hardware.graphics.composer3.LayerGenericMetadataKey;
 import android.hardware.graphics.composer3.PerFrameMetadataKey;
 import android.hardware.graphics.composer3.PowerMode;
 import android.hardware.graphics.composer3.ReadbackBufferAttributes;
@@ -159,23 +157,13 @@
     void destroyVirtualDisplay(long display);
 
     /**
-     * Executes commands from the input command message queue. Return values
-     * generated by the input commands are written to the output command
-     * message queue in the form of value commands.
+     * Executes commands.
      *
-     * @param inLength is the length of input commands.
-     * @param inHandles is an array of handles referenced by the input
-     *        commands.
+     * @param commands are the commands to be processed.
      *
-     * @return is the status of the command.
-
-     * @exception EX_BAD_PARAMETER when inLength is not equal to the length of
-     *                       commands in the input command message queue.
-     * @exception NO_RESOURCES when the output command message queue was not
-     *                      properly drained.
+     * @return are the command statuses.
      */
-    ExecuteCommandsStatus executeCommands(
-            int inLength, in android.hardware.common.NativeHandle[] inHandles);
+    CommandResultPayload[] executeCommands(in DisplayCommand[] commands);
 
     /**
      * Retrieves which display configuration is currently active.
@@ -197,7 +185,7 @@
     /**
      * Returns the color modes supported on this display.
      *
-     * All devices must support at least ColorMode::NATIVE.
+     * All devices must support at least ColorMode.NATIVE.
      *
      * @param display is the display to query.
      *
@@ -213,7 +201,7 @@
      *
      * When the layer dataspace is a legacy dataspace (see
      * common@1.1::Dataspace) and the display render intent is
-     * RenderIntent::ENHANCE, the pixel values can go through an
+     * RenderIntent.ENHANCE, the pixel values can go through an
      * implementation-defined saturation transform before being mapped to the
      * current color mode colorimetrically.
      *
@@ -259,22 +247,6 @@
     int getDisplayAttribute(long display, int config, DisplayAttribute attribute);
 
     /**
-     * Use getDisplayCapabilities instead. If brightness is supported, must return
-     * DisplayCapability::BRIGHTNESS as one of the display capabilities via getDisplayCapabilities.
-     * Only use getDisplayCapabilities as the source of truth to query brightness support.
-     *
-     * Gets whether brightness operations are supported on a display.
-     *
-     * @param display The display.
-     *
-     * @return Whether brightness operations are supported on the display.
-     *
-     * @exception EX_BAD_DISPLAY   when the display is invalid, or
-     * @exception EX_BAD_PARAMETER when the output parameter is invalid.
-     */
-    boolean getDisplayBrightnessSupport(long display);
-
-    /**
      * Provides a list of supported capabilities (as described in the
      * definition of DisplayCapability above). This list must not change after
      * initialization.
@@ -383,19 +355,21 @@
     DisplayContentSamplingAttributes getDisplayedContentSamplingAttributes(long display);
 
     /**
-     * Returns whether the given display supports PowerMode::DOZE and
-     * PowerMode::DOZE_SUSPEND. DOZE_SUSPEND may not provide any benefit over
-     * DOZE (see the definition of PowerMode for more information), but if
-     * both DOZE and DOZE_SUSPEND are no different from PowerMode::ON, the
-     * device must not claim support.
+     * Queries the physical orientation of a display. Orientation 'Transform::NONE'
+     * represents a display that doesn't require any transformation on layers
+     * to be presented at their natural orientation.
      *
-     * @param display is the display to query.
+     * @param display is the display where the physical orientation is queried.
      *
-     * @return is true only when the display supports doze modes.
+     * @return is one of the below values:
+     *         Transform::NONE
+     *         Transform::ROT_90
+     *         Transform::ROT_180
+     *         Transform::ROT_270
      *
-     * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     * @exception EX_BAD_DISPLAY when an invalid display was passed in.
      */
-    boolean getDozeSupport(long display);
+    Transform getDisplayPhysicalOrientation(long display);
 
     /**
      * Returns the high dynamic range (HDR) capabilities of the given display,
@@ -412,20 +386,6 @@
     HdrCapabilities getHdrCapabilities(long display);
 
     /**
-     * Retrieves the set of keys that may be passed into setLayerGenericMetadata
-     *
-     * Key names must meet the following requirements:
-     * - Must be specified in reverse domain name notation
-     * - Must not start with 'com.android' or 'android'
-     * - Must be unique within the returned vector
-     * - Must correspond to a matching HIDL struct type, which defines the
-     *   structure of its values. For example, the key 'com.example.V1-3.Foo'
-     *   should correspond to a value of type com.example@1.3::Foo, which is
-     *   defined in a vendor HAL extension
-     */
-    LayerGenericMetadataKey[] getLayerGenericMetadataKeys();
-
-    /**
      * Returns the maximum number of virtual displays supported by this device
      * (which may be 0). The client must not attempt to create more than this
      * many virtual displays on this device. This number must not change for
@@ -436,17 +396,6 @@
     int getMaxVirtualDisplayCount();
 
     /**
-     * Gets the output command message queue.
-     *
-     * This function must only be called inside executeCommands closure.
-     *
-     * @return is the descriptor of the output command queue.
-     *
-     * @exception EX_NO_RESOURCES when failed to get the queue temporarily.
-     */
-    MQDescriptor<int, SynchronizedReadWrite> getOutputCommandQueue();
-
-    /**
      * Returns the PerFrameMetadataKeys that are supported by this device.
      *
      * @param display is the display on which to create the layer.
@@ -463,8 +412,8 @@
      *
      * The width and height of this buffer must be those of the currently-active
      * display configuration, and the usage flags must consist of the following:
-     *   BufferUsage::CPU_READ | BufferUsage::GPU_TEXTURE |
-     *   BufferUsage::COMPOSER_OUTPUT
+     *   BufferUsage.CPU_READ | BufferUsage.GPU_TEXTURE |
+     *   BufferUsage.COMPOSER_OUTPUT
      *
      * The format and dataspace provided must be sufficient such that if a
      * correctly-configured buffer is passed into setReadbackBuffer, filled by
@@ -533,14 +482,14 @@
      *   getReadbackBufferAttributes
      *   setReadbackBuffer
      */
-    ParcelFileDescriptor getReadbackBufferFence(long display);
+    @nullable ParcelFileDescriptor getReadbackBufferFence(long display);
 
     /**
      * Returns the render intents supported by the specified display and color
      * mode.
      *
-     * For SDR color modes, RenderIntent::COLORIMETRIC must be supported. For
-     * HDR color modes, RenderIntent::TONE_MAP_COLORIMETRIC must be supported.
+     * For SDR color modes, RenderIntent.COLORIMETRIC must be supported. For
+     * HDR color modes, RenderIntent.TONE_MAP_COLORIMETRIC must be supported.
      *
      * @param display is the display to query.
      * @param mode is the color mode to query.
@@ -554,11 +503,11 @@
 
     /**
      * Provides a list of all the content types supported by this display (any of
-     * ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after
+     * ContentType.{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after
      * initialization.
      *
      * Content types are introduced in HDMI 1.4 and supporting them is optional. The
-     * ContentType::NONE is always supported and will not be returned by this method..
+     * ContentType.NONE is always supported and will not be returned by this method..
      *
      * @return out is a list of supported content types.
      *
@@ -618,6 +567,58 @@
             long display, int config, in VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints);
 
     /**
+     * Sets the display config in which the device boots.
+     *
+     * If the device is unable to boot in this config for any reason (example HDMI display changed),
+     * the implementation should try to find a config which matches the resolution and refresh-rate
+     * of this config. If no such config exists, the implementation's preferred display config
+     * should be used.
+     *
+     * @param display is the display for which the boot config is set.
+     * @param config is the new boot config for the display.
+     *
+     * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     * @exception EX_BAD_CONFIG when an invalid config id was passed in.
+     *
+     * @see getDisplayConfigs
+     * @see clearBootDisplayConfig
+     * @see getPreferredBootDisplayConfig
+     */
+    void setBootDisplayConfig(long display, int config);
+
+    /**
+     * Clears the boot display config.
+     *
+     * The device should boot in the implementation's preferred display config.
+     *
+     * @param display is the display for which the cached boot config is cleared.
+     *
+     * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     *
+     * @see getDisplayConfigs
+     * @see setBootDisplayConfig
+     * @see getPreferredBootDisplayConfig
+     */
+    void clearBootDisplayConfig(long display);
+
+    /**
+     * Returns the implementation's preferred display config.
+     *
+     * This is the display config used by the implementation at boot time, if the boot display
+     * config has not been requested yet, or if it has been previously cleared.
+     *
+     * @param display is the display to which the preferred config is queried.
+     * @return the implementation's preferred display config.
+     *
+     * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     *
+     * @see getDisplayConfigs
+     * @see setBootDisplayConfig
+     * @see clearBootDisplayConfig
+     */
+    int getPreferredBootDisplayConfig(long display);
+
+    /**
      * Requests the display to enable/disable its low latency mode.
      *
      * If the display is connected via HDMI 2.1, then Auto Low Latency Mode should be triggered. If
@@ -625,7 +626,7 @@
      * be triggered.
      *
      * This function should only be called if the display reports support for
-     * DisplayCapability::AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4.
+     * DisplayCapability.AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4.
      *
      * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
      * @exception EX_UNSUPPORTED when AUTO_LOW_LATENCY_MODE is not supported by the composer
@@ -649,8 +650,8 @@
      * The color mode and render intent change must take effect on next
      * presentDisplay.
      *
-     * All devices must support at least ColorMode::NATIVE and
-     * RenderIntent::COLORIMETRIC, and displays are assumed to be in this mode
+     * All devices must support at least ColorMode.NATIVE and
+     * RenderIntent.COLORIMETRIC, and displays are assumed to be in this mode
      * upon hotplug.
      *
      * @param display is the display to which the color mode is set.
@@ -685,25 +686,6 @@
     void setContentType(long display, ContentType type);
 
     /**
-     * Sets the brightness of a display.
-     *
-     * Ideally, the brightness change should take effect in the next frame post (so that it can be
-     * aligned with color transforms).
-     *
-     * @param display
-     *      The display whose brightness is set.
-     * @param brightness
-     *      A number between 0.0f (minimum brightness) and 1.0f (maximum brightness), or -1.0 to
-     *      turn the backlight off.
-     *
-     * @exception EX_BAD_DISPLAY   when the display is invalid, or
-     * @exception EX_UNSUPPORTED   when brightness operations are not supported, or
-     * @exception EX_BAD_PARAMETER when the brightness is invalid, or
-     * @exception EX_NO_RESOURCES  when the brightness cannot be applied.
-     */
-    void setDisplayBrightness(long display, float brightness);
-
-    /**
      * Enables or disables the collection of color content statistics
      * on this display.
      *
@@ -732,20 +714,12 @@
             long display, boolean enable, FormatColorComponent componentMask, long maxFrames);
 
     /**
-     * Sets the input command message queue.
-     *
-     * @param descriptor is the descriptor of the input command message queue.
-     * @exception EX_NO_RESOURCES when failed to set the queue temporarily.
-     */
-    void setInputCommandQueue(in MQDescriptor<int, SynchronizedReadWrite> descriptor);
-
-    /**
      * Sets the power mode of the given display. The transition must be
      * complete when this function returns. It is valid to call this function
      * multiple times with the same power mode.
      *
-     * All displays must support PowerMode::ON and PowerMode::OFF.  Whether a
-     * display supports PowerMode::DOZE or PowerMode::DOZE_SUSPEND may be
+     * All displays must support PowerMode.ON and PowerMode.OFF.  Whether a
+     * display supports PowerMode.DOZE or PowerMode.DOZE_SUSPEND may be
      * queried using getDozeSupport.
      *
      * @param display is the display to which the power mode is set.
@@ -764,13 +738,15 @@
      * This buffer must have been allocated as described in
      * getReadbackBufferAttributes and is in the dataspace provided by the same.
      *
+     * Also provides a file descriptor referring to a release sync fence
+     * object, which must be signaled when it is safe to write to the readback
+     * buffer. If it is already safe to write to the readback buffer, null may be passed instead.
+     *
      * If there is hardware protected content on the display at the time of the next
      * composition, the area of the readback buffer covered by such content must be
      * completely black. Any areas of the buffer not covered by such content may
      * optionally be black as well.
      *
-     * The release fence file descriptor provided works identically to the one
-     * described for setOutputBuffer.
      *
      * This function must not be called between any call to validateDisplay and a
      * subsequent call to presentDisplay.
@@ -778,7 +754,8 @@
      * Parameters:
      * @param display - the display on which to create the layer.
      * @param buffer - the new readback buffer
-     * @param releaseFence - a sync fence file descriptor as described in setOutputBuffer
+     * @param releaseFence - a sync fence file descriptor as described above or null if it is
+     *                       already safe to write to the readback buffer.
      *
      * @exception EX_BAD_DISPLAY - an invalid display handle was passed in
      * @exception EX_BAD_PARAMETER - the new readback buffer handle was invalid
@@ -788,7 +765,7 @@
      *   getReadbackBufferFence
      */
     void setReadbackBuffer(long display, in android.hardware.common.NativeHandle buffer,
-            in ParcelFileDescriptor releaseFence);
+            in @nullable ParcelFileDescriptor releaseFence);
 
     /**
      * Enables or disables the vsync signal for the given display. Virtual
@@ -802,4 +779,25 @@
      * @exception EX_BAD_PARAMETER when enabled was an invalid value.
      */
     void setVsyncEnabled(long display, boolean enabled);
+
+    /**
+     * Enables or disables the idle timer on this display.
+     *
+     * Idle timer is used to allow the display to go into a panel idle mode after some
+     * idle period.
+     *
+     * This function should only be called if the display reports support for
+     * DisplayCapability.DISPLAY_IDLE from getDisplayCapabilities.
+     *
+     * @param display is the display to which the idle timer is set.
+     * @param timeoutMs is the minimum requirements of idle period in milliseconds. Panel
+     *                should not go into the idle state within the minimum requirement after
+     *                idle for a while. 0 means disabled, panel should not go into idle state.
+     *
+     * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     * @exception EX_BAD_PARAMETER when timeout is a negative number.
+     * @exception EX_UNSUPPORTED when idle is not supported on this display.
+     *
+     */
+    void setIdleTimerEnabled(long display, int timeoutMs);
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
new file mode 100644
index 0000000..0a2711b
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -0,0 +1,270 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.graphics.common.FRect;
+import android.hardware.graphics.common.Point;
+import android.hardware.graphics.common.Rect;
+import android.hardware.graphics.composer3.Buffer;
+import android.hardware.graphics.composer3.Color;
+import android.hardware.graphics.composer3.Luminance;
+import android.hardware.graphics.composer3.ParcelableBlendMode;
+import android.hardware.graphics.composer3.ParcelableComposition;
+import android.hardware.graphics.composer3.ParcelableDataspace;
+import android.hardware.graphics.composer3.ParcelableTransform;
+import android.hardware.graphics.composer3.PerFrameMetadata;
+import android.hardware.graphics.composer3.PerFrameMetadataBlob;
+import android.hardware.graphics.composer3.PlaneAlpha;
+import android.hardware.graphics.composer3.ZOrder;
+
+@VintfStability
+parcelable LayerCommand {
+    /**
+     * The layer which this commands refers to.
+     * @see IComposer.createLayer
+     */
+    long layer;
+
+    /**
+     * Asynchronously sets the position of a cursor layer.
+     *
+     * Prior to validateDisplay, a layer may be marked as Composition.CURSOR.
+     * If validation succeeds (i.e., the device does not request a composition
+     * change for that layer), then once a buffer has been set for the layer
+     * and it has been presented, its position may be set by this function at
+     * any time between presentDisplay and any subsequent validateDisplay
+     * calls for this display.
+     *
+     * Once validateDisplay is called, this function must not be called again
+     * until the validate/present sequence is completed.
+     *
+     * May be called from any thread so long as it is not interleaved with the
+     * validate/present sequence as described above.
+     */
+    @nullable Point cursorPosition;
+
+    /**
+     * Sets the buffer handle to be displayed for this layer. If the buffer
+     * properties set at allocation time (width, height, format, and usage)
+     * have not changed since the previous frame, it is not necessary to call
+     * validateDisplay before calling presentDisplay unless new state needs to
+     * be validated in the interim.
+     *
+     * Also provides a file descriptor referring to an acquire sync fence
+     * object, which must be signaled when it is safe to read from the given
+     * buffer. If it is already safe to read from the buffer, an empty handle
+     * may be passed instead.
+     *
+     * This function must return NONE and have no other effect if called for a
+     * layer with a composition type of Composition.SOLID_COLOR (because it
+     * has no buffer) or Composition.SIDEBAND or Composition.CLIENT (because
+     * synchronization and buffer updates for these layers are handled
+     * elsewhere).
+     */
+    @nullable Buffer buffer;
+
+    /**
+     * Provides the region of the source buffer which has been modified since
+     * the last frame. This region does not need to be validated before
+     * calling presentDisplay.
+     *
+     * Once set through this function, the damage region remains the same
+     * until a subsequent call to this function.
+     *
+     * If damage is non-empty, then it may be assumed that any portion of the
+     * source buffer not covered by one of the rects has not been modified
+     * this frame. If damage is empty, then the whole source buffer must be
+     * treated as if it has been modified.
+     *
+     * If the layer's contents are not modified relative to the prior frame,
+     * damage must contain exactly one empty rect([0, 0, 0, 0]).
+     *
+     * The damage rects are relative to the pre-transformed buffer, and their
+     * origin is the top-left corner. They must not exceed the dimensions of
+     * the latched buffer.
+     */
+    @nullable Rect[] damage;
+
+    /**
+     * Sets the blend mode of the given layer.
+     */
+    @nullable ParcelableBlendMode blendMode;
+
+    /**
+     * Sets the color of the given layer. If the composition type of the layer
+     * is not Composition.SOLID_COLOR, this call must succeed and have no
+     * other effect.
+     */
+    @nullable Color color;
+
+    /**
+     * Sets the desired composition type of the given layer. During
+     * validateDisplay, the device may request changes to the composition
+     * types of any of the layers as described in the definition of
+     * Composition above.
+     */
+    @nullable ParcelableComposition composition;
+
+    /**
+     * Sets the dataspace of the layer.
+     *
+     * The dataspace provides more information about how to interpret the buffer
+     * or solid color, such as the encoding standard and color transform.
+     *
+     * See the values of ParcelableDataspace for more information.
+     */
+    @nullable ParcelableDataspace dataspace;
+
+    /**
+     * Sets the display frame (the portion of the display covered by a layer)
+     * of the given layer. This frame must not exceed the display dimensions.
+     */
+    @nullable Rect displayFrame;
+
+    /**
+     * Sets an alpha value (a floating point value in the range [0.0, 1.0])
+     * which will be applied to the whole layer. It can be conceptualized as a
+     * preprocessing step which applies the following function:
+     *   if (blendMode == BlendMode.PREMULTIPLIED)
+     *       out.rgb = in.rgb * planeAlpha
+     *   out.a = in.a * planeAlpha
+     *
+     * If the device does not support this operation on a layer which is
+     * marked Composition.DEVICE, it must request a composition type change
+     * to Composition.CLIENT upon the next validateDisplay call.
+     *
+     */
+    @nullable PlaneAlpha planeAlpha;
+
+    /**
+     * Sets the sideband stream for this layer. If the composition type of the
+     * given layer is not Composition.SIDEBAND, this call must succeed and
+     * have no other effect.
+     */
+    @nullable NativeHandle sidebandStream;
+
+    /**
+     * Sets the source crop (the portion of the source buffer which will fill
+     * the display frame) of the given layer. This crop rectangle must not
+     * exceed the dimensions of the latched buffer.
+     *
+     * If the device is not capable of supporting a true float source crop
+     * (i.e., it will truncate or round the floats to integers), it must set
+     * this layer to Composition.CLIENT when crop is non-integral for the
+     * most accurate rendering.
+     *
+     * If the device cannot support float source crops, but still wants to
+     * handle the layer, it must use the following code (or similar) to
+     * convert to an integer crop:
+     *   intCrop.left = (int) ceilf(crop.left);
+     *   intCrop.top = (int) ceilf(crop.top);
+     *   intCrop.right = (int) floorf(crop.right);
+     *   intCrop.bottom = (int) floorf(crop.bottom);
+     */
+    @nullable FRect sourceCrop;
+
+    /**
+     * Sets the transform (rotation/flip) of the given layer.
+     */
+    @nullable ParcelableTransform transform;
+
+    /**
+     * Specifies the portion of the layer that is visible, including portions
+     * under translucent areas of other layers. The region is in screen space,
+     * and must not exceed the dimensions of the screen.
+     */
+    @nullable Rect[] visibleRegion;
+
+    /**
+     * Sets the desired Z order (height) of the given layer. A layer with a
+     * greater Z value occludes a layer with a lesser Z value.
+     */
+    @nullable ZOrder z;
+
+    /**
+     * Sets a matrix for color transform which will be applied on this layer
+     * before composition.
+     *
+     * If the device is not capable of apply the matrix on this layer, it must force
+     * this layer to client composition during VALIDATE_DISPLAY.
+     *
+     * The matrix provided is an affine color transformation of the following
+     * form:
+     *
+     * |r.r r.g r.b 0|
+     * |g.r g.g g.b 0|
+     * |b.r b.g b.b 0|
+     * |Tr  Tg  Tb  1|
+     *
+     * This matrix must be provided in row-major form:
+     *
+     * {r.r, r.g, r.b, 0, g.r, ...}.
+     *
+     * Given a matrix of this form and an input color [R_in, G_in, B_in],
+     * the input color must first be converted to linear space
+     * [R_linear, G_linear, B_linear], then the output linear color
+     * [R_out_linear, G_out_linear, B_out_linear] will be:
+     *
+     * R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
+     * G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
+     * B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
+     *
+     * [R_out_linear, G_out_linear, B_out_linear] must then be converted to
+     * gamma space: [R_out, G_out, B_out] before blending.
+     */
+    @nullable float[] colorTransform;
+
+    /**
+     * Sets the desired white point for the layer. This is intended to be used when presenting
+     * an SDR layer alongside HDR content. The HDR content will be presented at the display
+     * brightness in nits, and accordingly SDR content shall be dimmed to the desired white point
+     * provided.
+     */
+    @nullable Luminance whitePointNits;
+
+    /**
+     * Sets the PerFrameMetadata for the display. This metadata must be used
+     * by the implementation to better tone map content to that display.
+     *
+     * This is a command that may be called every frame.
+     */
+    @nullable PerFrameMetadata[] perFrameMetadata;
+
+    /**
+     * This command sends metadata that may be used for tone-mapping the
+     * associated layer.  The metadata structure follows a {key, blob}
+     * format (see the PerFrameMetadataBlob struct).  All keys must be
+     * returned by a prior call to getPerFrameMetadataKeys and must
+     * be part of the list of keys associated with blob-type metadata
+     * (see PerFrameMetadataKey).
+     *
+     * This command may be called every frame.
+     */
+    @nullable PerFrameMetadataBlob[] perFrameMetadataBlob;
+
+    /**
+     * Specifies a region of the layer that is transparent and may be skipped
+     * by the DPU, e.g. using a blocking region, in order to save power. This
+     * is only a hint, so the composition of the layer must look the same
+     * whether or not this region is skipped.
+     *
+     * The region is in screen space and must not exceed the dimensions of
+     * the screen.
+     */
+    @nullable Rect[] blockingRegion;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerGenericMetadataKey.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerGenericMetadataKey.aidl
deleted file mode 100644
index 17704b8..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerGenericMetadataKey.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-@VintfStability
-parcelable LayerGenericMetadataKey {
-    /**
-     * Key names must comply with the requirements specified for
-     * getLayerGenericMetadataKeys below
-     */
-    String name;
-    /**
-     * The mandatory flag is defined in the description of
-     * setLayerGenericMetadata above
-     */
-    boolean mandatory;
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerRequest.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerRequest.aidl
deleted file mode 100644
index 10de558..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerRequest.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-/**
- * Layer requests returned from getDisplayRequests.
- */
-@VintfStability
-@Backing(type="int")
-enum LayerRequest {
-    /**
-     * The client must clear its target with transparent pixels where
-     * this layer would be. The client may ignore this request if the
-     * layer must be blended.
-     */
-    CLEAR_CLIENT_TARGET = 1 << 0,
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Luminance.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Luminance.aidl
new file mode 100644
index 0000000..5b1c1b4
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Luminance.aidl
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable Luminance {
+    /**
+     * Photometric measure of luminous intensity per unit area of light.
+     * Units are nits, or cd/m^2.
+     */
+    float nits;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableBlendMode.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableBlendMode.aidl
new file mode 100644
index 0000000..a6c016a
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableBlendMode.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.common.BlendMode;
+
+@VintfStability
+parcelable ParcelableBlendMode {
+    BlendMode blendMode;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableComposition.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableComposition.aidl
new file mode 100644
index 0000000..0946ce7
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableComposition.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.Composition;
+
+@VintfStability
+parcelable ParcelableComposition {
+    Composition composition;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableDataspace.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableDataspace.aidl
new file mode 100644
index 0000000..528cdf9
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableDataspace.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.common.Dataspace;
+
+@VintfStability
+parcelable ParcelableDataspace {
+    Dataspace dataspace;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableTransform.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableTransform.aidl
new file mode 100644
index 0000000..75f9f7e
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ParcelableTransform.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.common.Transform;
+
+@VintfStability
+parcelable ParcelableTransform {
+    Transform transform;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/PerFrameMetadataKey.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/PerFrameMetadataKey.aidl
index b666e6a..3962920 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/PerFrameMetadataKey.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/PerFrameMetadataKey.aidl
@@ -16,8 +16,6 @@
 
 package android.hardware.graphics.composer3;
 
-import android.hardware.graphics.composer3.PerFrameMetadataKey;
-
 /**
  * PerFrameMetadataKey
  *
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/PlaneAlpha.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/PlaneAlpha.aidl
new file mode 100644
index 0000000..347dc19
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/PlaneAlpha.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable PlaneAlpha {
+    /**
+     * An alpha value (a floating point value in the range [0.0, 1.0])
+     * which will be applied to a whole layer.
+     * @see LayerCommand.planeAlpha
+     */
+    float alpha;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/PresentFence.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentFence.aidl
new file mode 100644
index 0000000..244b4e5
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentFence.aidl
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable PresentFence {
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+
+    /**
+     * The present fence for this display.
+     */
+    ParcelFileDescriptor fence;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/PresentOrValidate.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentOrValidate.aidl
new file mode 100644
index 0000000..5ae8940
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentOrValidate.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable PresentOrValidate {
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+
+    /**
+     * Whether PresentOrValidate presented or validated the display.
+     */
+    @VintfStability enum Result { Validated, Presented }
+    Result result;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ReleaseFences.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ReleaseFences.aidl
new file mode 100644
index 0000000..459a042
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ReleaseFences.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable ReleaseFences {
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+    @VintfStability
+    parcelable Layer {
+        /**
+         * The layer which this commands refers to.
+         * @see IComposer.createLayer
+         */
+        long layer;
+
+        /**
+         * The release fence for this layer.
+         */
+        ParcelFileDescriptor fence;
+    }
+
+    /**
+     * The layers which has release fences.
+     */
+    Layer[] layers;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/RenderIntent.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/RenderIntent.aidl
index 043b24d..debf32c 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/RenderIntent.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/RenderIntent.aidl
@@ -25,8 +25,8 @@
  * modes should not affect the mapping.
  *
  * RenderIntent overrides the render intents defined for individual color
- * modes. It is ignored when the color mode is ColorMode::NATIVE, because
- * ColorMode::NATIVE colors are already display colors.
+ * modes. It is ignored when the color mode is ColorMode.NATIVE, because
+ * ColorMode.NATIVE colors are already display colors.
  */
 @VintfStability
 @Backing(type="int")
@@ -36,7 +36,7 @@
      * gamut are hard-clipped.
      *
      * This implies that the display must have been calibrated unless
-     * ColorMode::NATIVE is the only supported color mode.
+     * ColorMode.NATIVE is the only supported color mode.
      */
     COLORIMETRIC = 0,
     /**
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ZOrder.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ZOrder.aidl
new file mode 100644
index 0000000..56cc200
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ZOrder.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable ZOrder {
+    /**
+     * The desired Z order (height) of the given layer. A layer with a
+     * greater Z value occludes a layer with a lesser Z value.
+     * @see LayerCommand.z;
+     */
+    int z;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
deleted file mode 100644
index d59190d..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
+++ /dev/null
@@ -1,615 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android/hardware/graphics/composer3/translate-ndk.h"
-
-namespace android::h2a {
-
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposer::EX_NO_RESOURCES ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::NO_RESOURCES));
-
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_CONFIG ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_CONFIG));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_DISPLAY ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_DISPLAY));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_LAYER ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_LAYER));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_BAD_PARAMETER ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::BAD_PARAMETER));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_NO_RESOURCES ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::NO_RESOURCES));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_NOT_VALIDATED ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::NOT_VALIDATED));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_UNSUPPORTED ==
-        static_cast<int32_t>(::android::hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_SEAMLESS_NOT_ALLOWED ==
-        static_cast<int32_t>(
-                ::android::hardware::graphics::composer::V2_4::Error::SEAMLESS_NOT_ALLOWED));
-static_assert(
-        aidl::android::hardware::graphics::composer3::IComposerClient::EX_SEAMLESS_NOT_POSSIBLE ==
-        static_cast<int32_t>(
-                ::android::hardware::graphics::composer::V2_4::Error::SEAMLESS_NOT_POSSIBLE));
-
-static_assert(
-        aidl::android::hardware::graphics::composer3::Capability::INVALID ==
-        static_cast<aidl::android::hardware::graphics::composer3::Capability>(
-                ::android::hardware::graphics::composer::V2_1::IComposer::Capability::INVALID));
-static_assert(aidl::android::hardware::graphics::composer3::Capability::SIDEBAND_STREAM ==
-              static_cast<aidl::android::hardware::graphics::composer3::Capability>(
-                      ::android::hardware::graphics::composer::V2_1::IComposer::Capability::
-                              SIDEBAND_STREAM));
-static_assert(
-        aidl::android::hardware::graphics::composer3::Capability::SKIP_CLIENT_COLOR_TRANSFORM ==
-        static_cast<aidl::android::hardware::graphics::composer3::Capability>(
-                ::android::hardware::graphics::composer::V2_1::IComposer::Capability::
-                        SKIP_CLIENT_COLOR_TRANSFORM));
-static_assert(
-        aidl::android::hardware::graphics::composer3::Capability::PRESENT_FENCE_IS_NOT_RELIABLE ==
-        static_cast<aidl::android::hardware::graphics::composer3::Capability>(
-                ::android::hardware::graphics::composer::V2_1::IComposer::Capability::
-                        PRESENT_FENCE_IS_NOT_RELIABLE));
-// HWC2_CAPABILITY_SKIP_VALIDATE was never defined for HIDL, so we just hardcode its value
-static_assert(aidl::android::hardware::graphics::composer3::Capability::SKIP_VALIDATE ==
-              static_cast<aidl::android::hardware::graphics::composer3::Capability>(4));
-
-static_assert(aidl::android::hardware::graphics::composer3::LayerRequest::CLEAR_CLIENT_TARGET ==
-              static_cast<aidl::android::hardware::graphics::composer3::LayerRequest>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::LayerRequest::
-                              CLEAR_CLIENT_TARGET));
-
-static_assert(aidl::android::hardware::graphics::composer3::BlendMode::INVALID ==
-              static_cast<aidl::android::hardware::graphics::composer3::BlendMode>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::
-                              INVALID));
-static_assert(
-        aidl::android::hardware::graphics::composer3::BlendMode::NONE ==
-        static_cast<aidl::android::hardware::graphics::composer3::BlendMode>(
-                ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::NONE));
-static_assert(aidl::android::hardware::graphics::composer3::BlendMode::PREMULTIPLIED ==
-              static_cast<aidl::android::hardware::graphics::composer3::BlendMode>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::
-                              PREMULTIPLIED));
-static_assert(aidl::android::hardware::graphics::composer3::BlendMode::COVERAGE ==
-              static_cast<aidl::android::hardware::graphics::composer3::BlendMode>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode::
-                              COVERAGE));
-
-static_assert(aidl::android::hardware::graphics::composer3::Composition::INVALID ==
-              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
-                              INVALID));
-static_assert(aidl::android::hardware::graphics::composer3::Composition::CLIENT ==
-              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
-                              CLIENT));
-static_assert(aidl::android::hardware::graphics::composer3::Composition::DEVICE ==
-              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
-                              DEVICE));
-static_assert(aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR ==
-              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
-                              SOLID_COLOR));
-static_assert(aidl::android::hardware::graphics::composer3::Composition::CURSOR ==
-              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
-                              CURSOR));
-static_assert(aidl::android::hardware::graphics::composer3::Composition::SIDEBAND ==
-              static_cast<aidl::android::hardware::graphics::composer3::Composition>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::Composition::
-                              SIDEBAND));
-
-static_assert(aidl::android::hardware::graphics::composer3::DisplayRequest::FLIP_CLIENT_TARGET ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayRequest>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::
-                              DisplayRequest::FLIP_CLIENT_TARGET));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayRequest::
-                      WRITE_CLIENT_TARGET_TO_OUTPUT ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayRequest>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::
-                              DisplayRequest::WRITE_CLIENT_TARGET_TO_OUTPUT));
-
-static_assert(aidl::android::hardware::graphics::composer3::HandleIndex::EMPTY ==
-              static_cast<aidl::android::hardware::graphics::composer3::HandleIndex>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::HandleIndex::
-                              EMPTY));
-static_assert(aidl::android::hardware::graphics::composer3::HandleIndex::CACHED ==
-              static_cast<aidl::android::hardware::graphics::composer3::HandleIndex>(
-                      ::android::hardware::graphics::composer::V2_1::IComposerClient::HandleIndex::
-                              CACHED));
-
-static_assert(
-        aidl::android::hardware::graphics::composer3::PowerMode::OFF ==
-        static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
-                ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::OFF));
-static_assert(
-        aidl::android::hardware::graphics::composer3::PowerMode::DOZE ==
-        static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
-                ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::DOZE));
-static_assert(aidl::android::hardware::graphics::composer3::PowerMode::DOZE_SUSPEND ==
-              static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
-                      ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::
-                              DOZE_SUSPEND));
-static_assert(
-        aidl::android::hardware::graphics::composer3::PowerMode::ON ==
-        static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
-                ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::ON));
-static_assert(aidl::android::hardware::graphics::composer3::PowerMode::ON_SUSPEND ==
-              static_cast<aidl::android::hardware::graphics::composer3::PowerMode>(
-                      ::android::hardware::graphics::composer::V2_2::IComposerClient::PowerMode::
-                              ON_SUSPEND));
-
-static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::INVALID ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                              DisplayCapability::INVALID));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::
-                      SKIP_CLIENT_COLOR_TRANSFORM ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                              DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::DOZE ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                              DisplayCapability::DOZE));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::BRIGHTNESS ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                              DisplayCapability::BRIGHTNESS));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayCapability::PROTECTED_CONTENTS ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                              DisplayCapability::PROTECTED_CONTENTS));
-static_assert(
-        aidl::android::hardware::graphics::composer3::DisplayCapability::AUTO_LOW_LATENCY_MODE ==
-        static_cast<aidl::android::hardware::graphics::composer3::DisplayCapability>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::DisplayCapability::
-                        AUTO_LOW_LATENCY_MODE));
-
-static_assert(aidl::android::hardware::graphics::composer3::Command::LENGTH_MASK ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              LENGTH_MASK));
-static_assert(aidl::android::hardware::graphics::composer3::Command::OPCODE_SHIFT ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              OPCODE_SHIFT));
-static_assert(aidl::android::hardware::graphics::composer3::Command::OPCODE_MASK ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              OPCODE_MASK));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SELECT_DISPLAY ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SELECT_DISPLAY));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SELECT_LAYER ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SELECT_LAYER));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_ERROR ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_ERROR));
-static_assert(
-        aidl::android::hardware::graphics::composer3::Command::SET_CHANGED_COMPOSITION_TYPES ==
-        static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                        SET_CHANGED_COMPOSITION_TYPES));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_DISPLAY_REQUESTS ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_DISPLAY_REQUESTS));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_PRESENT_FENCE ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_PRESENT_FENCE));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_RELEASE_FENCES ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_RELEASE_FENCES));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_COLOR_TRANSFORM ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_COLOR_TRANSFORM));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_CLIENT_TARGET ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_CLIENT_TARGET));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_OUTPUT_BUFFER ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_OUTPUT_BUFFER));
-static_assert(aidl::android::hardware::graphics::composer3::Command::VALIDATE_DISPLAY ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              VALIDATE_DISPLAY));
-static_assert(aidl::android::hardware::graphics::composer3::Command::ACCEPT_DISPLAY_CHANGES ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              ACCEPT_DISPLAY_CHANGES));
-static_assert(aidl::android::hardware::graphics::composer3::Command::PRESENT_DISPLAY ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              PRESENT_DISPLAY));
-static_assert(aidl::android::hardware::graphics::composer3::Command::PRESENT_OR_VALIDATE_DISPLAY ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              PRESENT_OR_VALIDATE_DISPLAY));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_CURSOR_POSITION ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_CURSOR_POSITION));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_BUFFER ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_BUFFER));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_SURFACE_DAMAGE ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_SURFACE_DAMAGE));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_BLEND_MODE ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_BLEND_MODE));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_COLOR ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_COLOR));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_COMPOSITION_TYPE ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_COMPOSITION_TYPE));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_DATASPACE ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_DATASPACE));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_DISPLAY_FRAME ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_DISPLAY_FRAME));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_PLANE_ALPHA ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_PLANE_ALPHA));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_SIDEBAND_STREAM ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_SIDEBAND_STREAM));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_SOURCE_CROP ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_SOURCE_CROP));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_TRANSFORM ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_TRANSFORM));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_VISIBLE_REGION ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_VISIBLE_REGION));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_Z_ORDER ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_Z_ORDER));
-static_assert(aidl::android::hardware::graphics::composer3::Command::
-                      SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_PER_FRAME_METADATA ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_PER_FRAME_METADATA));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_FLOAT_COLOR ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_FLOAT_COLOR));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_COLOR_TRANSFORM ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_COLOR_TRANSFORM));
-static_assert(
-        aidl::android::hardware::graphics::composer3::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS ==
-        static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                        SET_LAYER_PER_FRAME_METADATA_BLOBS));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_CLIENT_TARGET_PROPERTY ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_CLIENT_TARGET_PROPERTY));
-static_assert(aidl::android::hardware::graphics::composer3::Command::SET_LAYER_GENERIC_METADATA ==
-              static_cast<aidl::android::hardware::graphics::composer3::Command>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Command::
-                              SET_LAYER_GENERIC_METADATA));
-
-static_assert(aidl::android::hardware::graphics::composer3::DisplayAttribute::INVALID ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::
-                              INVALID));
-static_assert(
-        aidl::android::hardware::graphics::composer3::DisplayAttribute::WIDTH ==
-        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::WIDTH));
-static_assert(
-        aidl::android::hardware::graphics::composer3::DisplayAttribute::HEIGHT ==
-        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::HEIGHT));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayAttribute::VSYNC_PERIOD ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::
-                              VSYNC_PERIOD));
-static_assert(
-        aidl::android::hardware::graphics::composer3::DisplayAttribute::DPI_X ==
-        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::DPI_X));
-static_assert(
-        aidl::android::hardware::graphics::composer3::DisplayAttribute::DPI_Y ==
-        static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::DPI_Y));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayAttribute::CONFIG_GROUP ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayAttribute>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::Attribute::
-                              CONFIG_GROUP));
-
-static_assert(aidl::android::hardware::graphics::composer3::DisplayConnectionType::INTERNAL ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayConnectionType>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                              DisplayConnectionType::INTERNAL));
-static_assert(aidl::android::hardware::graphics::composer3::DisplayConnectionType::EXTERNAL ==
-              static_cast<aidl::android::hardware::graphics::composer3::DisplayConnectionType>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                              DisplayConnectionType::EXTERNAL));
-
-static_assert(
-        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X ==
-        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X));
-static_assert(
-        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y ==
-        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
-                      DISPLAY_GREEN_PRIMARY_X ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
-                      DISPLAY_GREEN_PRIMARY_Y ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y));
-static_assert(
-        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X ==
-        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X));
-static_assert(
-        aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y ==
-        static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::WHITE_POINT_X ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::WHITE_POINT_X));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::WHITE_POINT_Y ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::WHITE_POINT_Y));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::MAX_LUMINANCE ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::MAX_LUMINANCE));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::MIN_LUMINANCE ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::MIN_LUMINANCE));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
-                      MAX_CONTENT_LIGHT_LEVEL ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::
-                      MAX_FRAME_AVERAGE_LIGHT_LEVEL ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL));
-static_assert(aidl::android::hardware::graphics::composer3::PerFrameMetadataKey::HDR10_PLUS_SEI ==
-              static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(
-                      ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                              PerFrameMetadataKey::HDR10_PLUS_SEI));
-
-static_assert(
-        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_0 ==
-        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        FormatColorComponent::FORMAT_COMPONENT_0));
-static_assert(
-        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_1 ==
-        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        FormatColorComponent::FORMAT_COMPONENT_1));
-static_assert(
-        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_2 ==
-        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        FormatColorComponent::FORMAT_COMPONENT_2));
-static_assert(
-        aidl::android::hardware::graphics::composer3::FormatColorComponent::FORMAT_COMPONENT_3 ==
-        static_cast<aidl::android::hardware::graphics::composer3::FormatColorComponent>(
-                ::android::hardware::graphics::composer::V2_3::IComposerClient::
-                        FormatColorComponent::FORMAT_COMPONENT_3));
-
-static_assert(
-        aidl::android::hardware::graphics::composer3::ContentType::NONE ==
-        static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::NONE));
-static_assert(aidl::android::hardware::graphics::composer3::ContentType::GRAPHICS ==
-              static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::
-                              GRAPHICS));
-static_assert(aidl::android::hardware::graphics::composer3::ContentType::PHOTO ==
-              static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::
-                              PHOTO));
-static_assert(aidl::android::hardware::graphics::composer3::ContentType::CINEMA ==
-              static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
-                      ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::
-                              CINEMA));
-static_assert(
-        aidl::android::hardware::graphics::composer3::ContentType::GAME ==
-        static_cast<aidl::android::hardware::graphics::composer3::ContentType>(
-                ::android::hardware::graphics::composer::V2_4::IComposerClient::ContentType::GAME));
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::VsyncPeriodChangeTimeline& in,
-        aidl::android::hardware::graphics::composer3::VsyncPeriodChangeTimeline* out) {
-    out->newVsyncAppliedTimeNanos = static_cast<int64_t>(in.newVsyncAppliedTimeNanos);
-    out->refreshRequired = static_cast<bool>(in.refreshRequired);
-    out->refreshTimeNanos = static_cast<int64_t>(in.refreshTimeNanos);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_1::IComposerClient::Rect& in,
-        aidl::android::hardware::graphics::common::Rect* out) {
-    out->left = static_cast<int32_t>(in.left);
-    out->top = static_cast<int32_t>(in.top);
-    out->right = static_cast<int32_t>(in.right);
-    out->bottom = static_cast<int32_t>(in.bottom);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_1::IComposerClient::FRect& in,
-        aidl::android::hardware::graphics::common::FRect* out) {
-    out->left = static_cast<float>(in.left);
-    out->top = static_cast<float>(in.top);
-    out->right = static_cast<float>(in.right);
-    out->bottom = static_cast<float>(in.bottom);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_1::IComposerClient::Color& in,
-        aidl::android::hardware::graphics::composer3::Color* out) {
-    // FIXME This requires conversion between signed and unsigned. Change this if it doesn't suit
-    // your needs.
-    if (in.r > std::numeric_limits<int8_t>::max() || in.r < 0) {
-        return false;
-    }
-    out->r = static_cast<int8_t>(in.r);
-    // FIXME This requires conversion between signed and unsigned. Change this if it doesn't suit
-    // your needs.
-    if (in.g > std::numeric_limits<int8_t>::max() || in.g < 0) {
-        return false;
-    }
-    out->g = static_cast<int8_t>(in.g);
-    // FIXME This requires conversion between signed and unsigned. Change this if it doesn't suit
-    // your needs.
-    if (in.b > std::numeric_limits<int8_t>::max() || in.b < 0) {
-        return false;
-    }
-    out->b = static_cast<int8_t>(in.b);
-    // FIXME This requires conversion between signed and unsigned. Change this if it doesn't suit
-    // your needs.
-    if (in.a > std::numeric_limits<int8_t>::max() || in.a < 0) {
-        return false;
-    }
-    out->a = static_cast<int8_t>(in.a);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_3::IComposerClient::PerFrameMetadata& in,
-        aidl::android::hardware::graphics::composer3::PerFrameMetadata* out) {
-    out->key =
-            static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(in.key);
-    out->value = static_cast<float>(in.value);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_2::IComposerClient::FloatColor& in,
-        aidl::android::hardware::graphics::composer3::FloatColor* out) {
-    out->r = static_cast<float>(in.r);
-    out->g = static_cast<float>(in.g);
-    out->b = static_cast<float>(in.b);
-    out->a = static_cast<float>(in.a);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_3::IComposerClient::PerFrameMetadataBlob&
-                in,
-        aidl::android::hardware::graphics::composer3::PerFrameMetadataBlob* out) {
-    out->key =
-            static_cast<aidl::android::hardware::graphics::composer3::PerFrameMetadataKey>(in.key);
-    {
-        size_t size = in.blob.size();
-        for (size_t i = 0; i < size; i++) {
-            // FIXME This requires conversion between signed and unsigned. Change this if it doesn't
-            // suit your needs.
-            if (in.blob[i] > std::numeric_limits<int8_t>::max() || in.blob[i] < 0) {
-                return false;
-            }
-            out->blob.push_back(static_cast<int8_t>(in.blob[i]));
-        }
-    }
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                VsyncPeriodChangeConstraints& in,
-        aidl::android::hardware::graphics::composer3::VsyncPeriodChangeConstraints* out) {
-    out->desiredTimeNanos = static_cast<int64_t>(in.desiredTimeNanos);
-    out->seamlessRequired = static_cast<bool>(in.seamlessRequired);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::IComposerClient::ClientTargetProperty&
-                in,
-        aidl::android::hardware::graphics::composer3::ClientTargetProperty* out) {
-    out->pixelFormat =
-            static_cast<aidl::android::hardware::graphics::common::PixelFormat>(in.pixelFormat);
-    out->dataspace =
-            static_cast<aidl::android::hardware::graphics::common::Dataspace>(in.dataspace);
-    return true;
-}
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                LayerGenericMetadataKey& in,
-        aidl::android::hardware::graphics::composer3::LayerGenericMetadataKey* out) {
-    out->name = in.name;
-    out->mandatory = static_cast<bool>(in.mandatory);
-    return true;
-}
-
-}  // namespace android::h2a
\ No newline at end of file
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
index c011f73..bd2c3b1 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
@@ -19,7 +19,7 @@
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "hardware_interfaces_license"
     // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
+    // SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
@@ -28,20 +28,29 @@
     defaults: [
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
+        // Needed for librenderengine
+        "skia_deps",
     ],
     srcs: [
         "VtsHalGraphicsComposer3_TargetTest.cpp",
+        "VtsHalGraphicsComposer3_ReadbackTest.cpp",
         "composer-vts/GraphicsComposerCallback.cpp",
-        "composer-vts/TestCommandReader.cpp",
     ],
 
     shared_libs: [
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
         "libbinder_ndk",
         "libbinder",
         "libfmq",
         "libbase",
         "libsync",
         "libui",
+        "libgui",
+        "libhidlbase",
+        "libprocessgroup",
+        "libtinyxml2",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
@@ -69,6 +78,10 @@
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
         "libaidlcommonsupport",
+        "libgtest",
+        "librenderengine",
+        "libshaders",
+        "libtonemap",
     ],
     cflags: [
         "-Wconversion",
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
new file mode 100644
index 0000000..3f1e703
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -0,0 +1,1425 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_composer_aidl_hal_readback_tests@3"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/composer3/IComposer.h>
+#include <android/binder_manager.h>
+#include <composer-vts/include/ReadbackVts.h>
+#include <composer-vts/include/RenderEngineVts.h>
+#include <gtest/gtest.h>
+#include <ui/DisplayId.h>
+#include <ui/DisplayIdentification.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+
+// tinyxml2 does implicit conversions >:(
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include <tinyxml2.h>
+#pragma clang diagnostic pop
+#include "composer-vts/include/GraphicsComposerCallback.h"
+
+namespace aidl::android::hardware::graphics::composer3::vts {
+namespace {
+
+using ::android::Rect;
+using common::Dataspace;
+using common::PixelFormat;
+
+class GraphicsCompositionTestBase : public ::testing::Test {
+  protected:
+    void SetUpBase(const std::string& name) {
+        ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
+        ASSERT_NE(binder, nullptr);
+        ASSERT_NO_FATAL_FAILURE(mComposer = IComposer::fromBinder(binder));
+        ASSERT_NE(mComposer, nullptr);
+        ASSERT_NO_FATAL_FAILURE(mComposer->createClient(&mComposerClient));
+        mComposerCallback = ::ndk::SharedRefBase::make<GraphicsComposerCallback>();
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+
+        ASSERT_NO_FATAL_FAILURE(mInvalidDisplayId = GetInvalidDisplayId());
+
+        int32_t activeConfig;
+        EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &activeConfig).isOk());
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                  DisplayAttribute::WIDTH, &mDisplayWidth)
+                            .isOk());
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                  DisplayAttribute::HEIGHT, &mDisplayHeight)
+                            .isOk());
+
+        setTestColorModes();
+
+        // explicitly disable vsync
+        EXPECT_TRUE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false).isOk());
+        mComposerCallback->setVsyncAllowed(false);
+
+        // set up gralloc
+        mGraphicBuffer = allocate();
+
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
+
+        ASSERT_NO_FATAL_FAILURE(
+                mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
+                        ::android::renderengine::RenderEngineCreationArgs::Builder()
+                                .setPixelFormat(static_cast<int>(common::PixelFormat::RGBA_8888))
+                                .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
+                                .setUseColorManagerment(true)
+                                .setEnableProtectedContext(false)
+                                .setPrecacheToneMapperShaderOnly(false)
+                                .setContextPriority(::android::renderengine::RenderEngine::
+                                                            ContextPriority::HIGH)
+                                .build())));
+
+        ::android::renderengine::DisplaySettings clientCompositionDisplay;
+        clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
+        clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
+
+        mTestRenderEngine->initGraphicBuffer(
+                static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
+                static_cast<uint64_t>(
+                        static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                        static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                        static_cast<uint64_t>(common::BufferUsage::GPU_RENDER_TARGET)));
+        mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF));
+        const auto errors = mReader.takeErrors();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty());
+
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+    }
+
+    ::android::sp<::android::GraphicBuffer> allocate() {
+        const auto width = static_cast<uint32_t>(mDisplayWidth);
+        const auto height = static_cast<uint32_t>(mDisplayHeight);
+        const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                           static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
+
+        return ::android::sp<::android::GraphicBuffer>::make(
+                width, height, ::android::PIXEL_FORMAT_RGBA_8888,
+                /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer3_ReadbackTest");
+    }
+
+    uint64_t getStableDisplayId(int64_t display) {
+        DisplayIdentification identification;
+        const auto error = mComposerClient->getDisplayIdentificationData(display, &identification);
+        EXPECT_TRUE(error.isOk());
+
+        if (const auto info = ::android::parseDisplayIdentificationData(
+                    static_cast<uint8_t>(identification.port), identification.data)) {
+            return info->id.value;
+        }
+
+        return ::android::PhysicalDisplayId::fromPort(static_cast<uint8_t>(identification.port))
+                .value;
+    }
+
+    // Gets the per-display XML config
+    std::unique_ptr<tinyxml2::XMLDocument> getDisplayConfigXml(int64_t display) {
+        std::stringstream pathBuilder;
+        pathBuilder << "/vendor/etc/displayconfig/display_id_" << getStableDisplayId(display)
+                    << ".xml";
+        const std::string path = pathBuilder.str();
+        auto document = std::make_unique<tinyxml2::XMLDocument>();
+        const tinyxml2::XMLError error = document->LoadFile(path.c_str());
+        if (error == tinyxml2::XML_SUCCESS) {
+            return document;
+        } else {
+            return nullptr;
+        }
+    }
+
+    // Gets the max display brightness for this display.
+    // If the display config xml does not exist, then assume that the display is not well-configured
+    // enough to provide a display brightness, so return nullopt.
+    std::optional<float> getMaxDisplayBrightnessNits(int64_t display) {
+        const auto document = getDisplayConfigXml(display);
+        if (!document) {
+            // Assume the device doesn't support display brightness
+            return std::nullopt;
+        }
+
+        const auto root = document->RootElement();
+        if (!root) {
+            // If there's somehow no root element, then this isn't a valid config
+            return std::nullopt;
+        }
+
+        const auto screenBrightnessMap = root->FirstChildElement("screenBrightnessMap");
+        if (!screenBrightnessMap) {
+            // A valid display config must have a screen brightness map
+            return std::nullopt;
+        }
+
+        auto point = screenBrightnessMap->FirstChildElement("point");
+        float maxNits = -1.f;
+        while (point != nullptr) {
+            const auto nits = point->FirstChildElement("nits");
+            if (nits) {
+                maxNits = std::max(maxNits, nits->FloatText(-1.f));
+            }
+            point = point->NextSiblingElement("point");
+        }
+
+        if (maxNits < 0.f) {
+            // If we got here, then there were no point elements containing a nit value, so this
+            // config isn't valid
+            return std::nullopt;
+        }
+
+        return maxNits;
+    }
+
+    void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
+        for (auto layer : layers) {
+            layer->write(mWriter);
+        }
+        execute();
+    }
+
+    void execute() {
+        const auto& commands = mWriter.getPendingCommands();
+        if (commands.empty()) {
+            mWriter.reset();
+            return;
+        }
+
+        std::vector<CommandResultPayload> results;
+        auto status = mComposerClient->executeCommands(commands, &results);
+        ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
+
+        mReader.parse(std::move(results));
+        mWriter.reset();
+    }
+
+    bool getHasReadbackBuffer() {
+        ReadbackBufferAttributes readBackBufferAttributes;
+        const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay,
+                                                                        &readBackBufferAttributes);
+        mPixelFormat = readBackBufferAttributes.format;
+        mDataspace = readBackBufferAttributes.dataspace;
+        return error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace);
+    }
+
+    std::shared_ptr<IComposer> mComposer;
+    std::shared_ptr<IComposerClient> mComposerClient;
+
+    std::shared_ptr<GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    int64_t mPrimaryDisplay;
+    int64_t mInvalidDisplayId;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
+    std::vector<ColorMode> mTestColorModes;
+    ComposerClientWriter mWriter;
+    ComposerClientReader mReader;
+    ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+    std::unique_ptr<TestRenderEngine> mTestRenderEngine;
+
+    common::PixelFormat mPixelFormat;
+    common::Dataspace mDataspace;
+
+    static constexpr uint32_t kClientTargetSlotCount = 64;
+
+  private:
+    int64_t waitForFirstDisplay() {
+        while (true) {
+            std::vector<int64_t> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+            return displays[0];
+        }
+    }
+
+    void setTestColorModes() {
+        mTestColorModes.clear();
+        std::vector<ColorMode> modes;
+        EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &modes).isOk());
+
+        for (ColorMode mode : modes) {
+            if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(),
+                          mode) != ReadbackHelper::colorModes.end()) {
+                mTestColorModes.push_back(mode);
+            }
+        }
+    }
+
+    // returns an invalid display id (one that has not been registered to a
+    // display.  Currently assuming that a device will never have close to
+    // std::numeric_limit<uint64_t>::max() displays registered while running tests
+    int64_t GetInvalidDisplayId() {
+        int64_t id = std::numeric_limits<int64_t>::max();
+        std::vector<int64_t> displays = mComposerCallback->getDisplays();
+        while (id > 0) {
+            if (std::none_of(displays.begin(), displays.end(),
+                             [&](const auto& display) { return id == display; })) {
+                return id;
+            }
+            id--;
+        }
+
+        // Although 0 could be an invalid display, a return value of 0
+        // from GetInvalidDisplayId means all other ids are in use, a condition which
+        // we are assuming a device will never have
+        EXPECT_NE(0, id);
+        return id;
+    }
+};
+
+class GraphicsCompositionTest : public GraphicsCompositionTestBase,
+                                public testing::WithParamInterface<std::string> {
+  public:
+    void SetUp() override { SetUpBase(GetParam()); }
+};
+
+TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        common::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setColor(BLUE);
+        layer->setDisplayFrame(coloredSquare);
+        layer->setZOrder(10);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        // expected color for each pixel
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        // if hwc cannot handle and asks for composition change,
+        // just succeed the test
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBuffer) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+                                       GREEN);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+                                       BLUE);
+
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, common::PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        common::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setColor(BLUE);
+        layer->setDisplayFrame(coloredSquare);
+        layer->setZOrder(10);
+        layer->write(mWriter);
+
+        // This following buffer call should have no effect
+        uint64_t usage =
+                static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                                      static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN));
+
+        mGraphicBuffer->reallocate(static_cast<uint32_t>(mDisplayWidth),
+                                   static_cast<uint32_t>(mDisplayHeight), 1,
+                                   static_cast<uint32_t>(common::PixelFormat::RGBA_8888), usage);
+        mWriter.setLayerBuffer(mPrimaryDisplay, layer->getLayer(), 0, mGraphicBuffer->handle, -1);
+
+        // expected color for each pixel
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetReadbackBuffer) {
+    if (!getHasReadbackBuffer()) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth, mDisplayHeight,
+                                  mPixelFormat, mDataspace);
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+}
+
+TEST_P(GraphicsCompositionTest, SetReadbackBufferBadDisplay) {
+    if (!getHasReadbackBuffer()) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    ASSERT_NE(nullptr, mGraphicBuffer);
+    ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+    aidl::android::hardware::common::NativeHandle bufferHandle =
+            ::android::dupToAidl(mGraphicBuffer->handle);
+    ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
+
+    const auto error = mComposerClient->setReadbackBuffer(mInvalidDisplayId, bufferHandle, fence);
+
+    EXPECT_FALSE(error.isOk());
+    ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsCompositionTest, SetReadbackBufferBadParameter) {
+    if (!getHasReadbackBuffer()) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    aidl::android::hardware::common::NativeHandle bufferHandle;
+    {
+        ::android::sp<::android::GraphicBuffer> buffer = allocate();
+        ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+        ::android::makeToAidl(mGraphicBuffer->handle);
+    }
+
+    ndk::ScopedFileDescriptor releaseFence = ndk::ScopedFileDescriptor(-1);
+    const auto error =
+            mComposerClient->setReadbackBuffer(mPrimaryDisplay, bufferHandle, releaseFence);
+
+    EXPECT_FALSE(error.isOk());
+    ASSERT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsCompositionTest, GetReadbackBufferFenceInactive) {
+    if (!getHasReadbackBuffer()) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    ndk::ScopedFileDescriptor releaseFence;
+    const auto error = mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &releaseFence);
+
+    ASSERT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+    EXPECT_EQ(-1, releaseFence.get());
+}
+
+TEST_P(GraphicsCompositionTest, ClientComposition) {
+    EXPECT_TRUE(mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)
+                        .isOk());
+
+    for (ColorMode mode : mTestColorModes) {
+        EXPECT_TRUE(mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+                                       GREEN);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+                                       BLUE);
+
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_FP16);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+
+        auto changedCompositionTypes = mReader.takeChangedCompositionTypes(mPrimaryDisplay);
+        if (!changedCompositionTypes.empty()) {
+            ASSERT_EQ(1, changedCompositionTypes.size());
+            ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
+
+            PixelFormat clientFormat = PixelFormat::RGBA_8888;
+            auto clientUsage = static_cast<uint32_t>(
+                    static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                    static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                    static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+            Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+            common::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
+
+            // create client target buffer
+            mGraphicBuffer->reallocate(layer->getWidth(), layer->getHeight(),
+                                       static_cast<int32_t>(common::PixelFormat::RGBA_8888),
+                                       layer->getLayerCount(), clientUsage);
+
+            ASSERT_NE(nullptr, mGraphicBuffer->handle);
+
+            void* clientBufData;
+            mGraphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData);
+
+            ASSERT_NO_FATAL_FAILURE(
+                    ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(),
+                                               static_cast<uint32_t>(mGraphicBuffer->stride),
+                                               clientBufData, clientFormat, expectedColors));
+            EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
+
+            ndk::ScopedFileDescriptor fenceHandle;
+            EXPECT_TRUE(
+                    mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fenceHandle).isOk());
+
+            layer->setToClientComposition(mWriter);
+            mWriter.acceptDisplayChanges(mPrimaryDisplay);
+            mWriter.setClientTarget(mPrimaryDisplay, 0, mGraphicBuffer->handle, fenceHandle.get(),
+                                    clientDataspace, std::vector<common::Rect>(1, damage));
+            execute();
+            changedCompositionTypes = mReader.takeChangedCompositionTypes(mPrimaryDisplay);
+            ASSERT_TRUE(changedCompositionTypes.empty());
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) {
+    ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
+
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        auto deviceLayer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight / 2, PixelFormat::RGBA_8888);
+        std::vector<Color> deviceColors(deviceLayer->getWidth() * deviceLayer->getHeight());
+        ReadbackHelper::fillColorsArea(deviceColors, static_cast<int32_t>(deviceLayer->getWidth()),
+                                       {0, 0, static_cast<int32_t>(deviceLayer->getWidth()),
+                                        static_cast<int32_t>(deviceLayer->getHeight())},
+                                       GREEN);
+        deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->getWidth()),
+                                      static_cast<int32_t>(deviceLayer->getHeight())});
+        deviceLayer->setZOrder(10);
+        deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
+        deviceLayer->write(mWriter);
+
+        PixelFormat clientFormat = PixelFormat::RGBA_8888;
+        auto clientUsage = static_cast<uint32_t>(
+                static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+        Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+        int32_t clientWidth = mDisplayWidth;
+        int32_t clientHeight = mDisplayHeight / 2;
+
+        auto clientLayer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, clientWidth,
+                clientHeight, PixelFormat::RGBA_FP16, Composition::DEVICE);
+        common::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+        clientLayer->setDisplayFrame(clientFrame);
+        clientLayer->setZOrder(0);
+        clientLayer->write(mWriter);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+
+        auto changedCompositionTypes = mReader.takeChangedCompositionTypes(mPrimaryDisplay);
+        if (changedCompositionTypes.size() != 1) {
+            continue;
+        }
+        // create client target buffer
+        ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
+        mGraphicBuffer->reallocate(static_cast<uint32_t>(mDisplayWidth),
+                                   static_cast<uint32_t>(mDisplayHeight),
+                                   static_cast<int32_t>(common::PixelFormat::RGBA_8888),
+                                   clientLayer->getLayerCount(), clientUsage);
+        ASSERT_NE(nullptr, mGraphicBuffer->handle);
+
+        void* clientBufData;
+        mGraphicBuffer->lock(clientUsage, {0, 0, mDisplayWidth, mDisplayHeight}, &clientBufData);
+
+        std::vector<Color> clientColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
+        ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
+                static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight),
+                mGraphicBuffer->getStride(), clientBufData, clientFormat, clientColors));
+        EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
+
+        ndk::ScopedFileDescriptor fenceHandle;
+        EXPECT_TRUE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fenceHandle).isOk());
+
+        clientLayer->setToClientComposition(mWriter);
+        mWriter.acceptDisplayChanges(mPrimaryDisplay);
+        mWriter.setClientTarget(mPrimaryDisplay, 0, mGraphicBuffer->handle, fenceHandle.get(),
+                                clientDataspace, std::vector<common::Rect>(1, clientFrame));
+        execute();
+        changedCompositionTypes = mReader.takeChangedCompositionTypes(mPrimaryDisplay);
+        ASSERT_TRUE(changedCompositionTypes.empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerDamage) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        common::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+        // update surface damage and recheck
+        redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
+        ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+        ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
+        layer->setSurfaceDamage(
+                std::vector<common::Rect>(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        layer->setColor(RED);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setAlpha(0);
+        layer->setBlendMode(BlendMode::PREMULTIPLIED);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerSourceCrop) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+                                       BLUE);
+
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
+                              static_cast<float>(mDisplayWidth),
+                              static_cast<float>(mDisplayHeight)});
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        // update expected colors to match crop
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        common::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
+        common::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
+        auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        redLayer->setColor(RED);
+        redLayer->setDisplayFrame(redRect);
+
+        auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        blueLayer->setColor(BLUE);
+        blueLayer->setDisplayFrame(blueRect);
+        blueLayer->setZOrder(5);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+
+        // red in front of blue
+        redLayer->setZOrder(10);
+
+        // fill blue first so that red will overwrite on overlap
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+        redLayer->setZOrder(1);
+        ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerWhitePointDims) {
+    std::vector<DisplayCapability> capabilities;
+    const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
+    ASSERT_TRUE(error.isOk());
+
+    const bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
+                                             DisplayCapability::BRIGHTNESS) != capabilities.end();
+
+    if (!brightnessSupport) {
+        GTEST_SUCCEED() << "Cannot verify dimming behavior without brightness support";
+        return;
+    }
+
+    const std::optional<float> maxBrightnessNitsOptional =
+            getMaxDisplayBrightnessNits(mPrimaryDisplay);
+
+    ASSERT_TRUE(maxBrightnessNitsOptional.has_value());
+
+    const float maxBrightnessNits = *maxBrightnessNitsOptional;
+
+    // Preconditions to successfully run are knowing the max brightness and successfully applying
+    // the max brightness
+    ASSERT_GT(maxBrightnessNits, 0.f);
+    mWriter.setDisplayBrightness(mPrimaryDisplay, 1.f);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace for "
+                               "color mode: "
+                            << toString(mode);
+            continue;
+        }
+        const common::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
+        const common::Rect dimmerRedRect = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+        const auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        redLayer->setColor(RED);
+        redLayer->setDisplayFrame(redRect);
+        redLayer->setWhitePointNits(maxBrightnessNits);
+
+        const auto dimmerRedLayer =
+                std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        dimmerRedLayer->setColor(RED);
+        dimmerRedLayer->setDisplayFrame(dimmerRedRect);
+        // Intentionally use a small dimming ratio as some implementations may be more likely to
+        // kick into GPU composition to apply dithering when the dimming ratio is high.
+        static constexpr float kDimmingRatio = 0.9f;
+        dimmerRedLayer->setWhitePointNits(maxBrightnessNits * kDimmingRatio);
+
+        const std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer};
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, dimmerRedRect, DIM_RED);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED()
+                    << "Readback verification not supported for GPU composition for color mode: "
+                    << toString(mode);
+            continue;
+        }
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+class GraphicsBlendModeCompositionTest
+    : public GraphicsCompositionTestBase,
+      public testing::WithParamInterface<std::tuple<std::string, std::string>> {
+  public:
+    void SetUp() override {
+        SetUpBase(std::get<0>(GetParam()));
+        mBackgroundColor = BLACK;
+        mTopLayerColor = RED;
+    }
+
+    void setBackgroundColor(Color color) { mBackgroundColor = color; }
+
+    void setTopLayerColor(Color color) { mTopLayerColor = color; }
+
+    void setUpLayers(BlendMode blendMode) {
+        mLayers.clear();
+        std::vector<Color> topLayerPixelColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(topLayerPixelColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight}, mTopLayerColor);
+
+        auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        backgroundLayer->setZOrder(0);
+        backgroundLayer->setColor(mBackgroundColor);
+
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(Dataspace::UNKNOWN, mWriter);
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
+
+        layer->setBlendMode(blendMode);
+        layer->setAlpha(std::stof(std::get<1>(GetParam())));
+
+        mLayers.push_back(backgroundLayer);
+        mLayers.push_back(layer);
+    }
+
+    void setExpectedColors(std::vector<Color>& expectedColors) {
+        ASSERT_EQ(2, mLayers.size());
+        ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+
+        auto layer = mLayers[1];
+        BlendMode blendMode = layer->getBlendMode();
+        float alpha = mTopLayerColor.a * layer->getAlpha();
+        if (blendMode == BlendMode::NONE) {
+            for (auto& expectedColor : expectedColors) {
+                expectedColor.r = mTopLayerColor.r * layer->getAlpha();
+                expectedColor.g = mTopLayerColor.g * layer->getAlpha();
+                expectedColor.b = mTopLayerColor.b * layer->getAlpha();
+                expectedColor.a = alpha;
+            }
+        } else if (blendMode == BlendMode::PREMULTIPLIED) {
+            for (auto& expectedColor : expectedColors) {
+                expectedColor.r =
+                        mTopLayerColor.r * layer->getAlpha() + mBackgroundColor.r * (1.0f - alpha);
+                expectedColor.g =
+                        mTopLayerColor.g * layer->getAlpha() + mBackgroundColor.g * (1.0f - alpha);
+                expectedColor.b =
+                        mTopLayerColor.b * layer->getAlpha() + mBackgroundColor.b * (1.0f - alpha);
+                expectedColor.a = alpha + mBackgroundColor.a * (1.0f - alpha);
+            }
+        } else if (blendMode == BlendMode::COVERAGE) {
+            for (auto& expectedColor : expectedColors) {
+                expectedColor.r = mTopLayerColor.r * alpha + mBackgroundColor.r * (1.0f - alpha);
+                expectedColor.g = mTopLayerColor.g * alpha + mBackgroundColor.g * (1.0f - alpha);
+                expectedColor.b = mTopLayerColor.b * alpha + mBackgroundColor.b * (1.0f - alpha);
+                expectedColor.a = mTopLayerColor.a * alpha + mBackgroundColor.a * (1.0f - alpha);
+            }
+        }
+    }
+
+  protected:
+    std::vector<std::shared_ptr<TestLayer>> mLayers;
+    Color mBackgroundColor;
+    Color mTopLayerColor;
+};
+
+TEST_P(GraphicsBlendModeCompositionTest, None) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+
+        setBackgroundColor(BLACK);
+        setTopLayerColor(TRANSLUCENT_RED);
+        setUpLayers(BlendMode::NONE);
+        setExpectedColors(expectedColors);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(mLayers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsBlendModeCompositionTest, Coverage) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+
+        setBackgroundColor(BLACK);
+        setTopLayerColor(TRANSLUCENT_RED);
+
+        setUpLayers(BlendMode::COVERAGE);
+        setExpectedColors(expectedColors);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(mLayers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+
+        setBackgroundColor(BLACK);
+        setTopLayerColor(TRANSLUCENT_RED);
+        setUpLayers(BlendMode::PREMULTIPLIED);
+        setExpectedColors(expectedColors);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(mLayers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+class GraphicsTransformCompositionTest : public GraphicsCompositionTest {
+  protected:
+    void SetUp() override {
+        GraphicsCompositionTest::SetUp();
+
+        auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        backgroundLayer->setColor({0.0f, 0.0f, 0.0f, 0.0f});
+        backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        backgroundLayer->setZOrder(0);
+
+        mSideLength = mDisplayWidth < mDisplayHeight ? mDisplayWidth : mDisplayHeight;
+        common::Rect redRect = {0, 0, mSideLength / 2, mSideLength / 2};
+        common::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength};
+
+        mLayer = std::make_shared<TestBufferLayer>(mComposerClient, mGraphicBuffer,
+                                                   *mTestRenderEngine, mPrimaryDisplay, mSideLength,
+                                                   mSideLength, PixelFormat::RGBA_8888);
+        mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength});
+        mLayer->setZOrder(10);
+
+        std::vector<Color> baseColors(static_cast<size_t>(mSideLength * mSideLength));
+        ReadbackHelper::fillColorsArea(baseColors, mSideLength, redRect, RED);
+        ReadbackHelper::fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
+        ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors));
+        mLayers = {backgroundLayer, mLayer};
+    }
+
+  protected:
+    std::shared_ptr<TestBufferLayer> mLayer;
+    std::vector<std::shared_ptr<TestLayer>> mLayers;
+    int mSideLength;
+};
+
+TEST_P(GraphicsTransformCompositionTest, FLIP_H) {
+    for (ColorMode mode : mTestColorModes) {
+        auto error =
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC);
+        if (!error.isOk() &&
+            (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED ||
+             error.getServiceSpecificError() == IComposerClient::EX_BAD_PARAMETER)) {
+            SUCCEED() << "ColorMode not supported, skip test";
+            return;
+        }
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        mLayer->setTransform(Transform::FLIP_H);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+
+        writeLayers(mLayers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsTransformCompositionTest, FLIP_V) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        mLayer->setTransform(Transform::FLIP_V);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
+
+        writeLayers(mLayers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsTransformCompositionTest, ROT_180) {
+    for (ColorMode mode : mTestColorModes) {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        if (!getHasReadbackBuffer()) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        mLayer->setTransform(Transform::ROT_180);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength},
+                                       RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
+
+        writeLayers(mLayers);
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsCompositionTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsCompositionTest,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+        ::android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsBlendModeCompositionTest);
+INSTANTIATE_TEST_SUITE_P(BlendMode, GraphicsBlendModeCompositionTest,
+                         testing::Combine(testing::ValuesIn(::android::getAidlHalInstanceNames(
+                                                  IComposer::descriptor)),
+                                          testing::Values("0.2", "1.0")));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsTransformCompositionTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsTransformCompositionTest,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+        ::android::PrintInstanceNameToString);
+
+}  // namespace
+}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
index 2d23b08..32a8ea8 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -4,18 +4,20 @@
 
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/graphics/common/BlendMode.h>
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/common/FRect.h>
 #include <aidl/android/hardware/graphics/common/Rect.h>
-#include <aidl/android/hardware/graphics/composer3/BlendMode.h>
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/IComposer.h>
 #include <android-base/properties.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
-#include <android/hardware/graphics/composer3/command-buffer.h>
+#include <android/hardware/graphics/composer3/ComposerClientReader.h>
+#include <android/hardware/graphics/composer3/ComposerClientWriter.h>
 #include <binder/ProcessState.h>
 #include <gtest/gtest.h>
+#include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <algorithm>
@@ -27,7 +29,6 @@
 #include <unordered_set>
 #include <utility>
 #include "composer-vts/include/GraphicsComposerCallback.h"
-#include "composer-vts/include/TestCommandReader.h"
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop  // ignored "-Wconversion
@@ -40,6 +41,9 @@
 
 using namespace std::chrono_literals;
 
+using ::android::GraphicBuffer;
+using ::android::sp;
+
 class VtsDisplay {
   public:
     VtsDisplay(int64_t displayId, int32_t displayWidth, int32_t displayHeight)
@@ -72,41 +76,129 @@
         ASSERT_NE(binder, nullptr);
         ASSERT_NO_FATAL_FAILURE(mComposer = IComposer::fromBinder(binder));
         ASSERT_NE(mComposer, nullptr);
-        ASSERT_NO_FATAL_FAILURE(mComposer->createClient(&mComposerClient));
-        mInvalidDisplayId = GetInvalidDisplayId();
+
+        ndk::ScopedAStatus status;
+        ASSERT_NO_FATAL_FAILURE(status = mComposer->createClient(&mComposerClient));
+        ASSERT_TRUE(status.isOk());
 
         mComposerCallback = ::ndk::SharedRefBase::make<GraphicsComposerCallback>();
         EXPECT_TRUE(mComposerClient->registerCallback(mComposerCallback).isOk());
 
         // assume the first displays are built-in and are never removed
         mDisplays = waitForDisplays();
-
         mPrimaryDisplay = mDisplays[0].get();
+        ASSERT_NO_FATAL_FAILURE(mInvalidDisplayId = GetInvalidDisplayId());
+
+        int32_t activeConfig;
+        EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &activeConfig).isOk());
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                  DisplayAttribute::WIDTH, &mDisplayWidth)
+                            .isOk());
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                  DisplayAttribute::HEIGHT, &mDisplayHeight)
+                            .isOk());
 
         // explicitly disable vsync
         for (const auto& display : mDisplays) {
             EXPECT_TRUE(mComposerClient->setVsyncEnabled(display.get(), false).isOk());
         }
         mComposerCallback->setVsyncAllowed(false);
-
-        mWriter = std::make_unique<CommandWriterBase>(1024);
-        mReader = std::make_unique<TestCommandReader>();
     }
 
     void TearDown() override {
-        ASSERT_EQ(0, mReader->mErrors.size());
-        ASSERT_EQ(0, mReader->mCompositionChanges.size());
-
+        destroyAllLayers();
         if (mComposerCallback != nullptr) {
             EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
-            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidVsyncPeriodChangeCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidSeamlessPossibleCount());
         }
     }
 
+    void Test_setContentTypeForDisplay(const int64_t& display,
+                                       const std::vector<ContentType>& capabilities,
+                                       const ContentType& contentType, const char* contentTypeStr) {
+        const bool contentTypeSupport = std::find(capabilities.begin(), capabilities.end(),
+                                                  contentType) != capabilities.end();
+
+        if (!contentTypeSupport) {
+            EXPECT_EQ(IComposerClient::EX_UNSUPPORTED,
+                      mComposerClient->setContentType(display, contentType)
+                              .getServiceSpecificError());
+            GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
+                            << std::to_string(display) << ", skipping test";
+            return;
+        }
+
+        EXPECT_TRUE(mComposerClient->setContentType(display, contentType).isOk());
+        EXPECT_TRUE(mComposerClient->setContentType(display, ContentType::NONE).isOk());
+    }
+
+    void Test_setContentType(const ContentType& contentType, const char* contentTypeStr) {
+        for (const auto& display : mDisplays) {
+            std::vector<ContentType> supportedContentTypes;
+            const auto error = mComposerClient->getSupportedContentTypes(display.get(),
+                                                                         &supportedContentTypes);
+            EXPECT_TRUE(error.isOk());
+
+            Test_setContentTypeForDisplay(display.get(), supportedContentTypes, contentType,
+                                          contentTypeStr);
+        }
+    }
+
+    int64_t createLayer(const VtsDisplay& display) {
+        int64_t layer;
+        EXPECT_TRUE(mComposerClient->createLayer(display.get(), kBufferSlotCount, &layer).isOk());
+
+        auto resourceIt = mDisplayResources.find(display.get());
+        if (resourceIt == mDisplayResources.end()) {
+            resourceIt = mDisplayResources.insert({display.get(), DisplayResource(false)}).first;
+        }
+
+        EXPECT_TRUE(resourceIt->second.layers.insert(layer).second)
+                << "duplicated layer id " << layer;
+
+        return layer;
+    }
+
+    void destroyAllLayers() {
+        for (const auto& it : mDisplayResources) {
+            auto display = it.first;
+            const DisplayResource& resource = it.second;
+
+            for (auto layer : resource.layers) {
+                const auto error = mComposerClient->destroyLayer(display, layer);
+                EXPECT_TRUE(error.isOk());
+            }
+
+            if (resource.isVirtual) {
+                const auto error = mComposerClient->destroyVirtualDisplay(display);
+                EXPECT_TRUE(error.isOk());
+            }
+        }
+        mDisplayResources.clear();
+    }
+
+    void destroyLayer(const VtsDisplay& display, int64_t layer) {
+        auto const error = mComposerClient->destroyLayer(display.get(), layer);
+        ASSERT_TRUE(error.isOk()) << "failed to destroy layer " << layer;
+
+        auto resourceIt = mDisplayResources.find(display.get());
+        ASSERT_NE(mDisplayResources.end(), resourceIt);
+        resourceIt->second.layers.erase(layer);
+    }
+
+    bool hasCapability(Capability capability) {
+        std::vector<Capability> capabilities;
+        EXPECT_TRUE(mComposer->getCapabilities(&capabilities).isOk());
+        return std::any_of(
+                capabilities.begin(), capabilities.end(),
+                [&](const Capability& activeCapability) { return activeCapability == capability; });
+    }
+
     // returns an invalid display id (one that has not been registered to a
     // display.  Currently assuming that a device will never have close to
     // std::numeric_limit<uint64_t>::max() displays registered while running tests
@@ -120,7 +212,11 @@
             id--;
         }
 
-        return 0;
+        // Although 0 could be an invalid display, a return value of 0
+        // from GetInvalidDisplayId means all other ids are in use, a condition which
+        // we are assuming a device will never have
+        EXPECT_NE(0, id);
+        return id;
     }
 
     std::vector<VtsDisplay> waitForDisplays() {
@@ -179,313 +275,11 @@
         return error;
     }
 
-    void Test_setContentTypeForDisplay(const int64_t& display,
-                                       const std::vector<ContentType>& capabilities,
-                                       const ContentType& contentType, const char* contentTypeStr) {
-        const bool contentTypeSupport = std::find(capabilities.begin(), capabilities.end(),
-                                                  contentType) != capabilities.end();
-
-        if (!contentTypeSupport) {
-            EXPECT_EQ(IComposerClient::EX_UNSUPPORTED,
-                      mComposerClient->setContentType(display, contentType)
-                              .getServiceSpecificError());
-            GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
-                            << std::to_string(display) << ", skipping test";
-            return;
-        }
-
-        EXPECT_TRUE(mComposerClient->setContentType(display, contentType).isOk());
-        EXPECT_TRUE(mComposerClient->setContentType(display, ContentType::NONE).isOk());
-    }
-
-    void Test_setContentType(const ContentType& contentType, const char* contentTypeStr) {
-        for (const auto& display : mDisplays) {
-            std::vector<ContentType> supportedContentTypes;
-            const auto error = mComposerClient->getSupportedContentTypes(display.get(),
-                                                                         &supportedContentTypes);
-            EXPECT_TRUE(error.isOk());
-
-            Test_setContentTypeForDisplay(display.get(), supportedContentTypes, contentType,
-                                          contentTypeStr);
-        }
-    }
-
-    void execute() {
-        TestCommandReader* reader = mReader.get();
-        CommandWriterBase* writer = mWriter.get();
-        bool queueChanged = false;
-        int32_t commandLength = 0;
-        std::vector<NativeHandle> commandHandles;
-        ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
-
-        if (queueChanged) {
-            auto ret = mComposerClient->setInputCommandQueue(writer->getMQDescriptor());
-            ASSERT_TRUE(ret.isOk());
-        }
-
-        ExecuteCommandsStatus commandStatus;
-        EXPECT_TRUE(mComposerClient->executeCommands(commandLength, commandHandles, &commandStatus)
-                            .isOk());
-
-        if (commandStatus.queueChanged) {
-            MQDescriptor<int32_t, SynchronizedReadWrite> outputCommandQueue;
-            ASSERT_TRUE(mComposerClient->getOutputCommandQueue(&outputCommandQueue).isOk());
-            reader->setMQDescriptor(outputCommandQueue);
-        }
-        ASSERT_TRUE(reader->readQueue(commandStatus.length, std::move(commandStatus.handles)));
-        reader->parse();
-        reader->reset();
-        writer->reset();
-    }
-
-    ::android::sp<::android::GraphicBuffer> allocate(uint32_t width, uint32_t height) {
-        ::android::sp<::android::GraphicBuffer> buffer =
-                ::android::sp<::android::GraphicBuffer>::make(
-                        width, height, ::android::PIXEL_FORMAT_RGBA_8888,
-                        /*layerCount*/ 1,
-                        static_cast<uint64_t>(
-                                static_cast<int>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                                static_cast<int>(common::BufferUsage::CPU_READ_OFTEN)),
-                        "VtsHalGraphicsComposer3_TargetTest");
-
-        return buffer;
-    }
-
     struct TestParameters {
         nsecs_t delayForChange;
         bool refreshMiss;
     };
 
-    static inline auto toTimePoint(nsecs_t time) {
-        return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
-    }
-
-    int64_t createLayer(const VtsDisplay& display) {
-        int64_t layer;
-        EXPECT_TRUE(mComposerClient->createLayer(display.get(), kBufferSlotCount, &layer).isOk());
-
-        auto resourceIt = mDisplayResources.find(display.get());
-        if (resourceIt == mDisplayResources.end()) {
-            resourceIt = mDisplayResources.insert({display.get(), DisplayResource(false)}).first;
-        }
-
-        EXPECT_TRUE(resourceIt->second.layers.insert(layer).second)
-                << "duplicated layer id " << layer;
-
-        return layer;
-    }
-
-    void destroyLayer(const VtsDisplay& display, int64_t layer) {
-        auto const error = mComposerClient->destroyLayer(display.get(), layer);
-        ASSERT_TRUE(error.isOk()) << "failed to destroy layer " << layer;
-
-        auto resourceIt = mDisplayResources.find(display.get());
-        ASSERT_NE(mDisplayResources.end(), resourceIt);
-        resourceIt->second.layers.erase(layer);
-    }
-
-    void forEachTwoConfigs(int64_t display, std::function<void(int32_t, int32_t)> func) {
-        std::vector<int32_t> displayConfigs;
-        EXPECT_TRUE(mComposerClient->getDisplayConfigs(display, &displayConfigs).isOk());
-        for (const int32_t config1 : displayConfigs) {
-            for (const int32_t config2 : displayConfigs) {
-                if (config1 != config2) {
-                    func(config1, config2);
-                }
-            }
-        }
-    }
-
-    void setActiveConfig(VtsDisplay& display, int32_t config) {
-        EXPECT_TRUE(mComposerClient->setActiveConfig(display.get(), config).isOk());
-        int32_t displayWidth;
-        EXPECT_TRUE(mComposerClient
-                            ->getDisplayAttribute(display.get(), config, DisplayAttribute::WIDTH,
-                                                  &displayWidth)
-                            .isOk());
-        int32_t displayHeight;
-        EXPECT_TRUE(mComposerClient
-                            ->getDisplayAttribute(display.get(), config, DisplayAttribute::HEIGHT,
-                                                  &displayHeight)
-                            .isOk());
-        display.setDimensions(displayWidth, displayHeight);
-    }
-
-    void sendRefreshFrame(const VtsDisplay& display, const VsyncPeriodChangeTimeline* timeline) {
-        if (timeline != nullptr) {
-            // Refresh time should be before newVsyncAppliedTimeNanos
-            EXPECT_LT(timeline->refreshTimeNanos, timeline->newVsyncAppliedTimeNanos);
-
-            std::this_thread::sleep_until(toTimePoint(timeline->refreshTimeNanos));
-        }
-
-        mWriter->selectDisplay(display.get());
-        EXPECT_TRUE(mComposerClient->setPowerMode(display.get(), PowerMode::ON).isOk());
-        EXPECT_TRUE(
-                mComposerClient
-                        ->setColorMode(display.get(), ColorMode::NATIVE, RenderIntent::COLORIMETRIC)
-                        .isOk());
-
-        FRect displayCrop = display.getCrop();
-        auto displayWidth = static_cast<uint32_t>(std::ceilf(displayCrop.right - displayCrop.left));
-        auto displayHeight =
-                static_cast<uint32_t>(std::ceilf(displayCrop.bottom - displayCrop.top));
-        int64_t layer = 0;
-        ASSERT_NO_FATAL_FAILURE(layer = createLayer(display));
-        {
-            auto buffer = allocate(displayWidth, displayHeight);
-            ASSERT_NE(nullptr, buffer);
-            ASSERT_EQ(::android::OK, buffer->initCheck());
-            ASSERT_NE(nullptr, buffer->handle);
-
-            mWriter->selectLayer(layer);
-            mWriter->setLayerCompositionType(Composition::DEVICE);
-            mWriter->setLayerDisplayFrame(display.getFrameRect());
-            mWriter->setLayerPlaneAlpha(1);
-            mWriter->setLayerSourceCrop(display.getCrop());
-            mWriter->setLayerTransform(static_cast<Transform>(0));
-            mWriter->setLayerVisibleRegion(std::vector<Rect>(1, display.getFrameRect()));
-            mWriter->setLayerZOrder(10);
-            mWriter->setLayerBlendMode(BlendMode::NONE);
-            mWriter->setLayerSurfaceDamage(std::vector<Rect>(1, display.getFrameRect()));
-            mWriter->setLayerBuffer(0, buffer->handle, -1);
-            mWriter->setLayerDataspace(common::Dataspace::UNKNOWN);
-
-            mWriter->validateDisplay();
-            execute();
-            ASSERT_EQ(0, mReader->mErrors.size());
-            mReader->mCompositionChanges.clear();
-
-            mWriter->presentDisplay();
-            execute();
-            ASSERT_EQ(0, mReader->mErrors.size());
-        }
-
-        {
-            auto buffer = allocate(displayWidth, displayHeight);
-            ASSERT_NE(nullptr, buffer->handle);
-
-            mWriter->selectLayer(layer);
-            mWriter->setLayerBuffer(0, buffer->handle, -1);
-            mWriter->setLayerSurfaceDamage(std::vector<Rect>(1, {0, 0, 10, 10}));
-            mWriter->validateDisplay();
-            execute();
-            ASSERT_EQ(0, mReader->mErrors.size());
-            mReader->mCompositionChanges.clear();
-
-            mWriter->presentDisplay();
-            execute();
-        }
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-    }
-
-    void waitForVsyncPeriodChange(int64_t display, const VsyncPeriodChangeTimeline& timeline,
-                                  int64_t desiredTimeNanos, int64_t oldPeriodNanos,
-                                  int64_t newPeriodNanos) {
-        const auto kChangeDeadline = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms;
-        while (std::chrono::steady_clock::now() <= kChangeDeadline) {
-            int32_t vsyncPeriodNanos;
-            EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos).isOk());
-            if (systemTime() <= desiredTimeNanos) {
-                EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos);
-            } else if (vsyncPeriodNanos == newPeriodNanos) {
-                break;
-            }
-            std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos));
-        }
-    }
-
-    void Test_setActiveConfigWithConstraints(const TestParameters& params) {
-        for (VtsDisplay& display : mDisplays) {
-            forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) {
-                setActiveConfig(display, config1);
-                sendRefreshFrame(display, nullptr);
-
-                int32_t vsyncPeriod1;
-                EXPECT_TRUE(mComposerClient
-                                    ->getDisplayAttribute(display.get(), config1,
-                                                          DisplayAttribute::VSYNC_PERIOD,
-                                                          &vsyncPeriod1)
-                                    .isOk());
-                int32_t configGroup1;
-                EXPECT_TRUE(mComposerClient
-                                    ->getDisplayAttribute(display.get(), config1,
-                                                          DisplayAttribute::CONFIG_GROUP,
-                                                          &configGroup1)
-                                    .isOk());
-                int32_t vsyncPeriod2;
-                EXPECT_TRUE(mComposerClient
-                                    ->getDisplayAttribute(display.get(), config2,
-                                                          DisplayAttribute::VSYNC_PERIOD,
-                                                          &vsyncPeriod2)
-                                    .isOk());
-                int32_t configGroup2;
-                EXPECT_TRUE(mComposerClient
-                                    ->getDisplayAttribute(display.get(), config2,
-                                                          DisplayAttribute::CONFIG_GROUP,
-                                                          &configGroup2)
-                                    .isOk());
-
-                if (vsyncPeriod1 == vsyncPeriod2) {
-                    return;  // continue
-                }
-
-                // We don't allow delayed change when changing config groups
-                if (params.delayForChange > 0 && configGroup1 != configGroup2) {
-                    return;  // continue
-                }
-
-                VsyncPeriodChangeTimeline timeline;
-                VsyncPeriodChangeConstraints constraints = {
-                        .desiredTimeNanos = systemTime() + params.delayForChange,
-                        .seamlessRequired = false};
-                EXPECT_TRUE(setActiveConfigWithConstraints(display, config2, constraints, &timeline)
-                                    .isOk());
-
-                EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
-                // Refresh rate should change within a reasonable time
-                constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s;  // 1 second
-                EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
-                            kReasonableTimeForChange.count());
-
-                if (timeline.refreshRequired) {
-                    if (params.refreshMiss) {
-                        // Miss the refresh frame on purpose to make sure the implementation sends a
-                        // callback
-                        std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) +
-                                                      100ms);
-                    }
-                    sendRefreshFrame(display, &timeline);
-                }
-                waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos,
-                                         vsyncPeriod1, vsyncPeriod2);
-
-                // At this point the refresh rate should have changed already, however in rare
-                // cases the implementation might have missed the deadline. In this case a new
-                // timeline should have been provided.
-                auto newTimeline = mComposerCallback->takeLastVsyncPeriodChangeTimeline();
-                if (timeline.refreshRequired && params.refreshMiss) {
-                    EXPECT_TRUE(newTimeline.has_value());
-                }
-
-                if (newTimeline.has_value()) {
-                    if (newTimeline->refreshRequired) {
-                        sendRefreshFrame(display, &newTimeline.value());
-                    }
-                    waitForVsyncPeriodChange(display.get(), newTimeline.value(),
-                                             constraints.desiredTimeNanos, vsyncPeriod1,
-                                             vsyncPeriod2);
-                }
-
-                int32_t vsyncPeriodNanos;
-                EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos)
-                                    .isOk());
-                EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2);
-            });
-        }
-    }
-
     // Keep track of all virtual displays and layers.  When a test fails with
     // ASSERT_*, the destructor will clean up the resources for the test.
     struct DisplayResource {
@@ -501,11 +295,11 @@
     int64_t mPrimaryDisplay;
     std::vector<VtsDisplay> mDisplays;
     std::shared_ptr<GraphicsComposerCallback> mComposerCallback;
-    std::unique_ptr<CommandWriterBase> mWriter;
-    std::unique_ptr<TestCommandReader> mReader;
     // use the slot count usually set by SF
     static constexpr uint32_t kBufferSlotCount = 64;
     std::unordered_map<int64_t, DisplayResource> mDisplayResources;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
 };
 
 TEST_P(GraphicsComposerAidlTest, getDisplayCapabilitiesBadDisplay) {
@@ -524,102 +318,17 @@
     }
 }
 
-TEST_P(GraphicsComposerAidlTest, getDisplayVsyncPeriod) {
-    for (VtsDisplay& display : mDisplays) {
-        std::vector<int32_t> configs;
-        EXPECT_TRUE(mComposerClient->getDisplayConfigs(display.get(), &configs).isOk());
-        for (int32_t config : configs) {
-            int32_t expectedVsyncPeriodNanos = -1;
-            EXPECT_TRUE(mComposerClient
-                                ->getDisplayAttribute(display.get(), config,
-                                                      DisplayAttribute::VSYNC_PERIOD,
-                                                      &expectedVsyncPeriodNanos)
-                                .isOk());
-
-            VsyncPeriodChangeTimeline timeline;
-            VsyncPeriodChangeConstraints constraints;
-
-            constraints.desiredTimeNanos = systemTime();
-            constraints.seamlessRequired = false;
-            EXPECT_TRUE(mComposerClient
-                                ->setActiveConfigWithConstraints(display.get(), config, constraints,
-                                                                 &timeline)
-                                .isOk());
-
-            if (timeline.refreshRequired) {
-                sendRefreshFrame(display, &timeline);
-            }
-            waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos, 0,
-                                     expectedVsyncPeriodNanos);
-
-            int32_t vsyncPeriodNanos;
-            int retryCount = 100;
-            do {
-                std::this_thread::sleep_for(10ms);
-                vsyncPeriodNanos = 0;
-                EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos)
-                                    .isOk());
-                --retryCount;
-            } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0);
-
-            EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
-
-            // Make sure that the vsync period stays the same if the active config is not
-            // changed.
-            auto timeout = 1ms;
-            for (int i = 0; i < 10; i++) {
-                std::this_thread::sleep_for(timeout);
-                timeout *= 2;
-                vsyncPeriodNanos = 0;
-                EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos)
-                                    .isOk());
-                EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
-            }
-        }
-    }
+TEST_P(GraphicsComposerAidlTest, DumpDebugInfo) {
+    std::string debugInfo;
+    EXPECT_TRUE(mComposer->dumpDebugInfo(&debugInfo).isOk());
 }
 
-TEST_P(GraphicsComposerAidlTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
-    VsyncPeriodChangeTimeline timeline;
-    VsyncPeriodChangeConstraints constraints;
+TEST_P(GraphicsComposerAidlTest, CreateClientSingleton) {
+    std::shared_ptr<IComposerClient> composerClient;
+    const auto error = mComposer->createClient(&composerClient);
 
-    constraints.seamlessRequired = true;
-    constraints.desiredTimeNanos = systemTime();
-
-    for (VtsDisplay& display : mDisplays) {
-        forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) {
-            int32_t configGroup1;
-            EXPECT_TRUE(mComposerClient
-                                ->getDisplayAttribute(display.get(), config1,
-                                                      DisplayAttribute::CONFIG_GROUP, &configGroup1)
-                                .isOk());
-            int32_t configGroup2;
-            EXPECT_TRUE(mComposerClient
-                                ->getDisplayAttribute(display.get(), config2,
-                                                      DisplayAttribute::CONFIG_GROUP, &configGroup2)
-                                .isOk());
-            if (configGroup1 != configGroup2) {
-                setActiveConfig(display, config1);
-                sendRefreshFrame(display, nullptr);
-                EXPECT_EQ(IComposerClient::EX_SEAMLESS_NOT_ALLOWED,
-                          setActiveConfigWithConstraints(display, config2, constraints, &timeline)
-                                  .getServiceSpecificError());
-            }
-        });
-    }
-}
-
-TEST_P(GraphicsComposerAidlTest, setActiveConfigWithConstraints) {
-    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = false});
-}
-
-TEST_P(GraphicsComposerAidlTest, setActiveConfigWithConstraints_Delayed) {
-    Test_setActiveConfigWithConstraints({.delayForChange = 300'000'000,  // 300ms
-                                         .refreshMiss = false});
-}
-
-TEST_P(GraphicsComposerAidlTest, setActiveConfigWithConstraints_MissRefresh) {
-    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = true});
+    EXPECT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_NO_RESOURCES, error.getServiceSpecificError());
 }
 
 TEST_P(GraphicsComposerAidlTest, GetDisplayIdentificationData) {
@@ -658,51 +367,6 @@
             << "data is not stable";
 }
 
-TEST_P(GraphicsComposerAidlTest, SET_LAYER_PER_FRAME_METADATA) {
-    int64_t layer;
-    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
-
-    mWriter->selectDisplay(mPrimaryDisplay);
-    mWriter->selectLayer(layer);
-
-    /**
-     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
-     * the D65 white point and the SRGB transfer functions.
-     * Rendering Intent: Colorimetric
-     * Primaries:
-     *                  x       y
-     *  green           0.265   0.690
-     *  blue            0.150   0.060
-     *  red             0.680   0.320
-     *  white (D65)     0.3127  0.3290
-     */
-
-    std::vector<PerFrameMetadata> aidlMetadata;
-    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680f});
-    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320f});
-    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265f});
-    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690f});
-    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150f});
-    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060f});
-    aidlMetadata.push_back({PerFrameMetadataKey::WHITE_POINT_X, 0.3127f});
-    aidlMetadata.push_back({PerFrameMetadataKey::WHITE_POINT_Y, 0.3290f});
-    aidlMetadata.push_back({PerFrameMetadataKey::MAX_LUMINANCE, 100.0f});
-    aidlMetadata.push_back({PerFrameMetadataKey::MIN_LUMINANCE, 0.1f});
-    aidlMetadata.push_back({PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
-    aidlMetadata.push_back({PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
-    mWriter->setLayerPerFrameMetadata(aidlMetadata);
-    execute();
-
-    if (mReader->mErrors.size() == 1 && mReader->mErrors[0].second == EX_UNSUPPORTED_OPERATION) {
-        mReader->mErrors.clear();
-        GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported";
-        EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk());
-        return;
-    }
-
-    EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk());
-}
-
 TEST_P(GraphicsComposerAidlTest, GetHdrCapabilities) {
     HdrCapabilities hdrCapabilities;
     const auto error = mComposerClient->getHdrCapabilities(mPrimaryDisplay, &hdrCapabilities);
@@ -816,11 +480,19 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, SetColorModeBadDisplay) {
-    auto const error = mComposerClient->setColorMode(mInvalidDisplayId, ColorMode::NATIVE,
-                                                     RenderIntent::COLORIMETRIC);
+    std::vector<ColorMode> colorModes;
+    EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &colorModes).isOk());
+    for (auto mode : colorModes) {
+        std::vector<RenderIntent> intents;
+        EXPECT_TRUE(mComposerClient->getRenderIntents(mPrimaryDisplay, mode, &intents).isOk())
+                << "failed to get render intents";
+        for (auto intent : intents) {
+            auto const error = mComposerClient->setColorMode(mInvalidDisplayId, mode, intent);
 
-    EXPECT_FALSE(error.isOk());
-    ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+            EXPECT_FALSE(error.isOk());
+            ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+        }
+    }
 }
 
 TEST_P(GraphicsComposerAidlTest, SetColorModeBadParameter) {
@@ -837,31 +509,6 @@
     EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, renderIntentError.getServiceSpecificError());
 }
 
-TEST_P(GraphicsComposerAidlTest, SetLayerColorTransform) {
-    int64_t layer;
-    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
-    mWriter->selectDisplay(mPrimaryDisplay);
-    mWriter->selectLayer(layer);
-
-    // clang-format off
-    const std::array<float, 16> matrix = {{
-        1.0f, 0.0f, 0.0f, 0.0f,
-        0.0f, 1.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 1.0f, 0.0f,
-        0.0f, 0.0f, 0.0f, 1.0f,
-    }};
-    // clang-format on
-
-    mWriter->setLayerColorTransform(matrix.data());
-    execute();
-
-    if (mReader->mErrors.size() == 1 && mReader->mErrors[0].second == EX_UNSUPPORTED_OPERATION) {
-        mReader->mErrors.clear();
-        GTEST_SUCCEED() << "setLayerColorTransform is not supported";
-        return;
-    }
-}
-
 TEST_P(GraphicsComposerAidlTest, GetDisplayedContentSamplingAttributes) {
     int constexpr invalid = -1;
 
@@ -932,56 +579,6 @@
     }
 }
 
-TEST_P(GraphicsComposerAidlTest, getDisplayCapabilitiesBasic) {
-    std::vector<DisplayCapability> capabilities;
-    const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
-    ASSERT_TRUE(error.isOk());
-    const bool hasDozeSupport = std::find(capabilities.begin(), capabilities.end(),
-                                          DisplayCapability::DOZE) != capabilities.end();
-    bool isDozeSupported = false;
-    EXPECT_TRUE(mComposerClient->getDozeSupport(mPrimaryDisplay, &isDozeSupported).isOk());
-    EXPECT_EQ(hasDozeSupport, isDozeSupported);
-
-    bool hasBrightnessSupport = std::find(capabilities.begin(), capabilities.end(),
-                                          DisplayCapability::BRIGHTNESS) != capabilities.end();
-    bool isBrightnessSupported = false;
-    EXPECT_TRUE(
-            mComposerClient->getDisplayBrightnessSupport(mPrimaryDisplay, &isBrightnessSupported)
-                    .isOk());
-    EXPECT_EQ(isBrightnessSupported, hasBrightnessSupport);
-}
-
-/*
- * Test that if brightness operations are supported, setDisplayBrightness works as expected.
- */
-TEST_P(GraphicsComposerAidlTest, setDisplayBrightness) {
-    std::vector<DisplayCapability> capabilities;
-    auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
-    ASSERT_TRUE(error.isOk());
-    bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
-                                       DisplayCapability::BRIGHTNESS) != capabilities.end();
-    if (!brightnessSupport) {
-        EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.5f)
-                          .getServiceSpecificError(),
-                  IComposerClient::EX_UNSUPPORTED);
-        GTEST_SUCCEED() << "Brightness operations are not supported";
-        return;
-    }
-
-    EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.0f).isOk());
-    EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.5f).isOk());
-    EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 1.0f).isOk());
-    EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -1.0f).isOk());
-
-    error = mComposerClient->setDisplayBrightness(mPrimaryDisplay, +2.0f);
-    EXPECT_FALSE(error.isOk());
-    EXPECT_EQ(error.getServiceSpecificError(), IComposerClient::EX_BAD_PARAMETER);
-
-    error = mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f);
-    EXPECT_FALSE(error.isOk());
-    EXPECT_EQ(error.getServiceSpecificError(), IComposerClient::EX_BAD_PARAMETER);
-}
-
 TEST_P(GraphicsComposerAidlTest, getDisplayConnectionType) {
     DisplayConnectionType type;
     EXPECT_FALSE(mComposerClient->getDisplayConnectionType(mInvalidDisplayId, &type).isOk());
@@ -1130,6 +727,61 @@
     }
 }
 
+TEST_P(GraphicsComposerAidlTest, setBootDisplayConfig_BadDisplay) {
+    int32_t config = 0;
+    auto const error = mComposerClient->setBootDisplayConfig(mInvalidDisplayId, config);
+
+    EXPECT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, setBootDisplayConfig_BadConfig) {
+    for (VtsDisplay& display : mDisplays) {
+        int32_t invalidConfigId = GetInvalidConfigId();
+        const auto error = mComposerClient->setBootDisplayConfig(display.get(), invalidConfigId);
+        EXPECT_FALSE(error.isOk());
+        EXPECT_EQ(IComposerClient::EX_BAD_CONFIG, error.getServiceSpecificError());
+    }
+}
+
+TEST_P(GraphicsComposerAidlTest, setBootDisplayConfig) {
+    std::vector<int32_t> configs;
+    EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk());
+    for (auto config : configs) {
+        EXPECT_TRUE(mComposerClient->setBootDisplayConfig(mPrimaryDisplay, config).isOk());
+    }
+}
+
+TEST_P(GraphicsComposerAidlTest, clearBootDisplayConfig_BadDisplay) {
+    auto const error = mComposerClient->clearBootDisplayConfig(mInvalidDisplayId);
+
+    EXPECT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, clearBootDisplayConfig) {
+    EXPECT_TRUE(mComposerClient->clearBootDisplayConfig(mPrimaryDisplay).isOk());
+}
+
+TEST_P(GraphicsComposerAidlTest, getPreferredBootDisplayConfig_BadDisplay) {
+    int32_t config;
+    auto const error = mComposerClient->getPreferredBootDisplayConfig(mInvalidDisplayId, &config);
+
+    EXPECT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, getPreferredBootDisplayConfig) {
+    int32_t preferredDisplayConfig = 0;
+    auto const error = mComposerClient->getPreferredBootDisplayConfig(mPrimaryDisplay,
+                                                                      &preferredDisplayConfig);
+    EXPECT_TRUE(error.isOk());
+
+    std::vector<int32_t> configs;
+    EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk());
+    EXPECT_NE(configs.end(), std::find(configs.begin(), configs.end(), preferredDisplayConfig));
+}
+
 TEST_P(GraphicsComposerAidlTest, setAutoLowLatencyModeBadDisplay) {
     EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY,
               mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true)
@@ -1224,28 +876,6 @@
     Test_setContentType(ContentType::GAME, "GAME");
 }
 
-TEST_P(GraphicsComposerAidlTest, getLayerGenericMetadataKeys) {
-    std::vector<LayerGenericMetadataKey> keys;
-    EXPECT_TRUE(mComposerClient->getLayerGenericMetadataKeys(&keys).isOk());
-
-    std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$");
-    std::unordered_set<std::string> uniqueNames;
-    for (const auto& key : keys) {
-        std::string name(key.name);
-
-        // Keys must not start with 'android' or 'com.android'
-        EXPECT_FALSE(name.find("android") == 0);
-        EXPECT_FALSE(name.find("com.android") == 0);
-
-        // Keys must be in reverse domain name format
-        EXPECT_TRUE(std::regex_match(name, reverseDomainName));
-
-        // Keys must be unique within this list
-        const auto& [iter, inserted] = uniqueNames.insert(name);
-        EXPECT_TRUE(inserted);
-    }
-}
-
 TEST_P(GraphicsComposerAidlTest, CreateVirtualDisplay) {
     int32_t maxVirtualDisplayCount;
     EXPECT_TRUE(mComposerClient->getMaxVirtualDisplayCount(&maxVirtualDisplayCount).isOk());
@@ -1267,65 +897,268 @@
     EXPECT_TRUE(mComposerClient->destroyVirtualDisplay(virtualDisplay.display).isOk());
 }
 
+TEST_P(GraphicsComposerAidlTest, DestroyVirtualDisplayBadDisplay) {
+    int32_t maxDisplayCount = 0;
+    EXPECT_TRUE(mComposerClient->getMaxVirtualDisplayCount(&maxDisplayCount).isOk());
+    if (maxDisplayCount == 0) {
+        GTEST_SUCCEED() << "no virtual display support";
+        return;
+    }
+    const auto error = mComposerClient->destroyVirtualDisplay(mInvalidDisplayId);
+
+    EXPECT_FALSE(error.isOk());
+    ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, CreateLayer) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk());
+}
+
+TEST_P(GraphicsComposerAidlTest, CreateLayerBadDisplay) {
+    int64_t layer;
+    const auto error = mComposerClient->createLayer(mInvalidDisplayId, kBufferSlotCount, &layer);
+
+    EXPECT_FALSE(error.isOk());
+    ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, DestroyLayerBadDisplay) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    const auto error = mComposerClient->destroyLayer(mInvalidDisplayId, layer);
+
+    EXPECT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+    EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk());
+}
+
+TEST_P(GraphicsComposerAidlTest, DestroyLayerBadLayerError) {
+    // We haven't created any layers yet, so any id should be invalid
+    const auto error = mComposerClient->destroyLayer(mPrimaryDisplay, 1);
+
+    EXPECT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_BAD_LAYER, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, GetActiveConfigBadDisplay) {
+    int32_t config;
+    const auto error = mComposerClient->getActiveConfig(mInvalidDisplayId, &config);
+
+    EXPECT_FALSE(error.isOk());
+    ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, GetDisplayConfig) {
+    std::vector<int32_t> configs;
+    EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk());
+}
+
+TEST_P(GraphicsComposerAidlTest, GetDisplayConfigBadDisplay) {
+    std::vector<int32_t> configs;
+    const auto error = mComposerClient->getDisplayConfigs(mInvalidDisplayId, &configs);
+
+    EXPECT_FALSE(error.isOk());
+    ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, GetDisplayName) {
+    std::string displayName;
+    EXPECT_TRUE(mComposerClient->getDisplayName(mPrimaryDisplay, &displayName).isOk());
+}
+
+TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientationBadDisplay) {
+    Transform displayOrientation;
+    const auto error =
+            mComposerClient->getDisplayPhysicalOrientation(mInvalidDisplayId, &displayOrientation);
+
+    EXPECT_FALSE(error.isOk());
+    ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientation) {
+    const auto allowedDisplayOrientations = std::array<Transform, 4>{
+            Transform::NONE,
+            Transform::ROT_90,
+            Transform::ROT_180,
+            Transform::ROT_270,
+    };
+
+    Transform displayOrientation;
+    const auto error =
+            mComposerClient->getDisplayPhysicalOrientation(mPrimaryDisplay, &displayOrientation);
+
+    EXPECT_TRUE(error.isOk());
+    EXPECT_NE(std::find(allowedDisplayOrientations.begin(), allowedDisplayOrientations.end(),
+                        displayOrientation),
+              allowedDisplayOrientations.end());
+}
+
+TEST_P(GraphicsComposerAidlTest, SetClientTargetSlotCount) {
+    EXPECT_TRUE(
+            mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount).isOk());
+}
+
+TEST_P(GraphicsComposerAidlTest, SetActiveConfig) {
+    std::vector<int32_t> configs;
+    EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk());
+    for (auto config : configs) {
+        EXPECT_TRUE(mComposerClient->setActiveConfig(mPrimaryDisplay, config).isOk());
+        int32_t config1;
+        EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &config1).isOk());
+        EXPECT_EQ(config, config1);
+    }
+}
+
+TEST_P(GraphicsComposerAidlTest, SetActiveConfigPowerCycle) {
+    EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk());
+    EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk());
+
+    std::vector<int32_t> configs;
+    EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk());
+    for (auto config : configs) {
+        EXPECT_TRUE(mComposerClient->setActiveConfig(mPrimaryDisplay, config).isOk());
+        int32_t config1;
+        EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &config1).isOk());
+        EXPECT_EQ(config, config1);
+
+        EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk());
+        EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk());
+        EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &config1).isOk());
+        EXPECT_EQ(config, config1);
+    }
+}
+
+TEST_P(GraphicsComposerAidlTest, SetPowerModeUnsupported) {
+    std::vector<DisplayCapability> capabilities;
+    auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
+    ASSERT_TRUE(error.isOk());
+    const bool isDozeSupported = std::find(capabilities.begin(), capabilities.end(),
+                                           DisplayCapability::DOZE) != capabilities.end();
+    const bool isSuspendSupported = std::find(capabilities.begin(), capabilities.end(),
+                                              DisplayCapability::SUSPEND) != capabilities.end();
+    if (!isDozeSupported) {
+        error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE);
+        EXPECT_FALSE(error.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+
+        error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE_SUSPEND);
+        EXPECT_FALSE(error.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+    }
+
+    if (!isSuspendSupported) {
+        error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON_SUSPEND);
+        EXPECT_FALSE(error.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+
+        error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE_SUSPEND);
+        EXPECT_FALSE(error.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+    }
+}
+
+TEST_P(GraphicsComposerAidlTest, SetVsyncEnabled) {
+    mComposerCallback->setVsyncAllowed(true);
+
+    EXPECT_TRUE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, true).isOk());
+    usleep(60 * 1000);
+    EXPECT_TRUE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false).isOk());
+
+    mComposerCallback->setVsyncAllowed(false);
+}
+
 TEST_P(GraphicsComposerAidlTest, SetPowerMode) {
+    std::vector<DisplayCapability> capabilities;
+    const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
+    ASSERT_TRUE(error.isOk());
+    const bool isDozeSupported = std::find(capabilities.begin(), capabilities.end(),
+                                           DisplayCapability::DOZE) != capabilities.end();
+    const bool isSuspendSupported = std::find(capabilities.begin(), capabilities.end(),
+                                              DisplayCapability::SUSPEND) != capabilities.end();
+
     std::vector<PowerMode> modes;
     modes.push_back(PowerMode::OFF);
-    modes.push_back(PowerMode::ON_SUSPEND);
     modes.push_back(PowerMode::ON);
 
+    if (isSuspendSupported) {
+        modes.push_back(PowerMode::ON_SUSPEND);
+    }
+
+    if (isDozeSupported) {
+        modes.push_back(PowerMode::DOZE);
+    }
+
+    if (isSuspendSupported && isDozeSupported) {
+        modes.push_back(PowerMode::DOZE_SUSPEND);
+    }
+
     for (auto mode : modes) {
         EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
     }
 }
 
 TEST_P(GraphicsComposerAidlTest, SetPowerModeVariations) {
+    std::vector<DisplayCapability> capabilities;
+    const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
+    ASSERT_TRUE(error.isOk());
+    const bool isDozeSupported = std::find(capabilities.begin(), capabilities.end(),
+                                           DisplayCapability::DOZE) != capabilities.end();
+    const bool isSuspendSupported = std::find(capabilities.begin(), capabilities.end(),
+                                              DisplayCapability::SUSPEND) != capabilities.end();
+
     std::vector<PowerMode> modes;
 
     modes.push_back(PowerMode::OFF);
+    modes.push_back(PowerMode::ON);
     modes.push_back(PowerMode::OFF);
-
     for (auto mode : modes) {
         EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
     }
+    modes.clear();
 
+    modes.push_back(PowerMode::OFF);
+    modes.push_back(PowerMode::OFF);
+    for (auto mode : modes) {
+        EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
+    }
     modes.clear();
 
     modes.push_back(PowerMode::ON);
     modes.push_back(PowerMode::ON);
-
     for (auto mode : modes) {
         EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
     }
-
     modes.clear();
 
-    modes.push_back(PowerMode::ON_SUSPEND);
-    modes.push_back(PowerMode::ON_SUSPEND);
-
-    for (auto mode : modes) {
-        EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
+    if (isSuspendSupported) {
+        modes.push_back(PowerMode::ON_SUSPEND);
+        modes.push_back(PowerMode::ON_SUSPEND);
+        for (auto mode : modes) {
+            EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
+        }
+        modes.clear();
     }
 
-    bool isDozeSupported = false;
-    ASSERT_TRUE(mComposerClient->getDozeSupport(mPrimaryDisplay, &isDozeSupported).isOk());
     if (isDozeSupported) {
-        modes.clear();
-
         modes.push_back(PowerMode::DOZE);
         modes.push_back(PowerMode::DOZE);
-
         for (auto mode : modes) {
             EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
         }
-
         modes.clear();
+    }
 
+    if (isSuspendSupported && isDozeSupported) {
         modes.push_back(PowerMode::DOZE_SUSPEND);
         modes.push_back(PowerMode::DOZE_SUSPEND);
-
         for (auto mode : modes) {
             EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk());
         }
+        modes.clear();
     }
 }
 
@@ -1343,20 +1176,6 @@
     ASSERT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError());
 }
 
-TEST_P(GraphicsComposerAidlTest, SetPowerModeUnsupported) {
-    bool isDozeSupported = false;
-    EXPECT_TRUE(mComposerClient->getDozeSupport(mPrimaryDisplay, &isDozeSupported).isOk());
-    if (!isDozeSupported) {
-        auto error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE);
-        EXPECT_FALSE(error.isOk());
-        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
-
-        error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE_SUSPEND);
-        EXPECT_FALSE(error.isOk());
-        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
-    }
-}
-
 TEST_P(GraphicsComposerAidlTest, GetDataspaceSaturationMatrix) {
     std::vector<float> matrix;
     EXPECT_TRUE(
@@ -1379,6 +1198,1055 @@
     EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError());
 }
 
+// Tests for Command.
+class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest {
+  protected:
+    void TearDown() override {
+        const auto errors = mReader.takeErrors();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty());
+
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerAidlTest::TearDown());
+    }
+
+    void execute() {
+        const auto& commands = mWriter.getPendingCommands();
+        if (commands.empty()) {
+            mWriter.reset();
+            return;
+        }
+
+        std::vector<CommandResultPayload> results;
+        const auto status = mComposerClient->executeCommands(commands, &results);
+        ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
+
+        mReader.parse(std::move(results));
+        mWriter.reset();
+    }
+
+    static inline auto toTimePoint(nsecs_t time) {
+        return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
+    }
+
+    void setActiveConfig(VtsDisplay& display, int32_t config) {
+        EXPECT_TRUE(mComposerClient->setActiveConfig(display.get(), config).isOk());
+        int32_t displayWidth;
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(display.get(), config, DisplayAttribute::WIDTH,
+                                                  &displayWidth)
+                            .isOk());
+        int32_t displayHeight;
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(display.get(), config, DisplayAttribute::HEIGHT,
+                                                  &displayHeight)
+                            .isOk());
+        display.setDimensions(displayWidth, displayHeight);
+    }
+
+    void forEachTwoConfigs(int64_t display, std::function<void(int32_t, int32_t)> func) {
+        std::vector<int32_t> displayConfigs;
+        EXPECT_TRUE(mComposerClient->getDisplayConfigs(display, &displayConfigs).isOk());
+        for (const int32_t config1 : displayConfigs) {
+            for (const int32_t config2 : displayConfigs) {
+                if (config1 != config2) {
+                    func(config1, config2);
+                }
+            }
+        }
+    }
+
+    void waitForVsyncPeriodChange(int64_t display, const VsyncPeriodChangeTimeline& timeline,
+                                  int64_t desiredTimeNanos, int64_t oldPeriodNanos,
+                                  int64_t newPeriodNanos) {
+        const auto kChangeDeadline = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms;
+        while (std::chrono::steady_clock::now() <= kChangeDeadline) {
+            int32_t vsyncPeriodNanos;
+            EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos).isOk());
+            if (systemTime() <= desiredTimeNanos) {
+                EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos);
+            } else if (vsyncPeriodNanos == newPeriodNanos) {
+                break;
+            }
+            std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos));
+        }
+    }
+
+    sp<GraphicBuffer> allocate() {
+        return sp<GraphicBuffer>::make(
+                static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight),
+                ::android::PIXEL_FORMAT_RGBA_8888,
+                /*layerCount*/ 1,
+                (static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                 static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                 static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY)),
+                "VtsHalGraphicsComposer3_TargetTest");
+    }
+
+    void sendRefreshFrame(const VtsDisplay& display, const VsyncPeriodChangeTimeline* timeline) {
+        if (timeline != nullptr) {
+            // Refresh time should be before newVsyncAppliedTimeNanos
+            EXPECT_LT(timeline->refreshTimeNanos, timeline->newVsyncAppliedTimeNanos);
+
+            std::this_thread::sleep_until(toTimePoint(timeline->refreshTimeNanos));
+        }
+
+        EXPECT_TRUE(mComposerClient->setPowerMode(display.get(), PowerMode::ON).isOk());
+        EXPECT_TRUE(
+                mComposerClient
+                        ->setColorMode(display.get(), ColorMode::NATIVE, RenderIntent::COLORIMETRIC)
+                        .isOk());
+
+        int64_t layer = 0;
+        ASSERT_NO_FATAL_FAILURE(layer = createLayer(display));
+        {
+            const auto buffer = allocate();
+            ASSERT_NE(nullptr, buffer);
+            ASSERT_EQ(::android::OK, buffer->initCheck());
+            ASSERT_NE(nullptr, buffer->handle);
+
+            mWriter.setLayerCompositionType(display.get(), layer, Composition::DEVICE);
+            mWriter.setLayerDisplayFrame(display.get(), layer, display.getFrameRect());
+            mWriter.setLayerPlaneAlpha(display.get(), layer, 1);
+            mWriter.setLayerSourceCrop(display.get(), layer, display.getCrop());
+            mWriter.setLayerTransform(display.get(), layer, static_cast<Transform>(0));
+            mWriter.setLayerVisibleRegion(display.get(), layer,
+                                          std::vector<Rect>(1, display.getFrameRect()));
+            mWriter.setLayerZOrder(display.get(), layer, 10);
+            mWriter.setLayerBlendMode(display.get(), layer, BlendMode::NONE);
+            mWriter.setLayerSurfaceDamage(display.get(), layer,
+                                          std::vector<Rect>(1, display.getFrameRect()));
+            mWriter.setLayerBuffer(display.get(), layer, 0, buffer->handle, -1);
+            mWriter.setLayerDataspace(display.get(), layer, common::Dataspace::UNKNOWN);
+
+            mWriter.validateDisplay(display.get(), ComposerClientWriter::kNoTimestamp);
+            execute();
+            ASSERT_TRUE(mReader.takeErrors().empty());
+
+            mWriter.presentDisplay(display.get());
+            execute();
+            ASSERT_TRUE(mReader.takeErrors().empty());
+        }
+
+        {
+            const auto buffer = allocate();
+            ASSERT_NE(nullptr, buffer->handle);
+
+            mWriter.setLayerBuffer(display.get(), layer, 0, buffer->handle, -1);
+            mWriter.setLayerSurfaceDamage(display.get(), layer,
+                                          std::vector<Rect>(1, {0, 0, 10, 10}));
+            mWriter.validateDisplay(display.get(), ComposerClientWriter::kNoTimestamp);
+            execute();
+            ASSERT_TRUE(mReader.takeErrors().empty());
+
+            mWriter.presentDisplay(display.get());
+            execute();
+        }
+
+        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+    }
+
+    sp<::android::Fence> presentAndGetFence(
+            std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+        mWriter.validateDisplay(mPrimaryDisplay, expectedPresentTime);
+        execute();
+        EXPECT_TRUE(mReader.takeErrors().empty());
+
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        EXPECT_TRUE(mReader.takeErrors().empty());
+
+        auto presentFence = mReader.takePresentFence(mPrimaryDisplay);
+        // take ownership
+        const int fenceOwner = presentFence.get();
+        *presentFence.getR() = -1;
+        EXPECT_NE(-1, fenceOwner);
+        return sp<::android::Fence>::make(fenceOwner);
+    }
+
+    int32_t getVsyncPeriod() {
+        int32_t activeConfig;
+        EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &activeConfig).isOk());
+
+        int32_t vsyncPeriod;
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                  DisplayAttribute::VSYNC_PERIOD, &vsyncPeriod)
+                            .isOk());
+        return vsyncPeriod;
+    }
+
+    int64_t createOnScreenLayer() {
+        const int64_t layer = createLayer(mDisplays[0]);
+        mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::DEVICE);
+        mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, {0, 0, mDisplayWidth, mDisplayHeight});
+        mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1);
+        mWriter.setLayerSourceCrop(
+                mPrimaryDisplay, layer,
+                {0, 0, static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)});
+        mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0));
+        mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer,
+                                      std::vector<Rect>(1, {0, 0, mDisplayWidth, mDisplayHeight}));
+        mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10);
+        mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE);
+        mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer,
+                                      std::vector<Rect>(1, {0, 0, mDisplayWidth, mDisplayHeight}));
+        mWriter.setLayerDataspace(mPrimaryDisplay, layer, common::Dataspace::UNKNOWN);
+        return layer;
+    }
+
+    bool hasDisplayCapability(int64_t display, DisplayCapability cap) {
+        std::vector<DisplayCapability> capabilities;
+        const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities);
+        EXPECT_TRUE(error.isOk());
+
+        return std::find(capabilities.begin(), capabilities.end(), cap) != capabilities.end();
+    }
+
+    void Test_setActiveConfigWithConstraints(const TestParameters& params) {
+        for (VtsDisplay& display : mDisplays) {
+            forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) {
+                setActiveConfig(display, config1);
+                sendRefreshFrame(display, nullptr);
+
+                int32_t vsyncPeriod1;
+                EXPECT_TRUE(mComposerClient
+                                    ->getDisplayAttribute(display.get(), config1,
+                                                          DisplayAttribute::VSYNC_PERIOD,
+                                                          &vsyncPeriod1)
+                                    .isOk());
+                int32_t configGroup1;
+                EXPECT_TRUE(mComposerClient
+                                    ->getDisplayAttribute(display.get(), config1,
+                                                          DisplayAttribute::CONFIG_GROUP,
+                                                          &configGroup1)
+                                    .isOk());
+                int32_t vsyncPeriod2;
+                EXPECT_TRUE(mComposerClient
+                                    ->getDisplayAttribute(display.get(), config2,
+                                                          DisplayAttribute::VSYNC_PERIOD,
+                                                          &vsyncPeriod2)
+                                    .isOk());
+                int32_t configGroup2;
+                EXPECT_TRUE(mComposerClient
+                                    ->getDisplayAttribute(display.get(), config2,
+                                                          DisplayAttribute::CONFIG_GROUP,
+                                                          &configGroup2)
+                                    .isOk());
+
+                if (vsyncPeriod1 == vsyncPeriod2) {
+                    return;  // continue
+                }
+
+                // We don't allow delayed change when changing config groups
+                if (params.delayForChange > 0 && configGroup1 != configGroup2) {
+                    return;  // continue
+                }
+
+                VsyncPeriodChangeTimeline timeline;
+                VsyncPeriodChangeConstraints constraints = {
+                        .desiredTimeNanos = systemTime() + params.delayForChange,
+                        .seamlessRequired = false};
+                EXPECT_TRUE(setActiveConfigWithConstraints(display, config2, constraints, &timeline)
+                                    .isOk());
+
+                EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
+                // Refresh rate should change within a reasonable time
+                constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s;  // 1 second
+                EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
+                            kReasonableTimeForChange.count());
+
+                if (timeline.refreshRequired) {
+                    if (params.refreshMiss) {
+                        // Miss the refresh frame on purpose to make sure the implementation sends a
+                        // callback
+                        std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) +
+                                                      100ms);
+                    }
+                    sendRefreshFrame(display, &timeline);
+                }
+                waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos,
+                                         vsyncPeriod1, vsyncPeriod2);
+
+                // At this point the refresh rate should have changed already, however in rare
+                // cases the implementation might have missed the deadline. In this case a new
+                // timeline should have been provided.
+                auto newTimeline = mComposerCallback->takeLastVsyncPeriodChangeTimeline();
+                if (timeline.refreshRequired && params.refreshMiss) {
+                    EXPECT_TRUE(newTimeline.has_value());
+                }
+
+                if (newTimeline.has_value()) {
+                    if (newTimeline->refreshRequired) {
+                        sendRefreshFrame(display, &newTimeline.value());
+                    }
+                    waitForVsyncPeriodChange(display.get(), newTimeline.value(),
+                                             constraints.desiredTimeNanos, vsyncPeriod1,
+                                             vsyncPeriod2);
+                }
+
+                int32_t vsyncPeriodNanos;
+                EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos)
+                                    .isOk());
+                EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2);
+            });
+        }
+    }
+
+    void Test_expectedPresentTime(std::optional<int> framesDelay) {
+        if (hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
+            GTEST_SUCCEED() << "Device has unreliable present fences capability, skipping";
+            return;
+        }
+
+        ASSERT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk());
+
+        const auto vsyncPeriod = getVsyncPeriod();
+
+        const auto buffer1 = allocate();
+        const auto buffer2 = allocate();
+        ASSERT_NE(nullptr, buffer1);
+        ASSERT_NE(nullptr, buffer2);
+
+        const auto layer = createOnScreenLayer();
+        mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, buffer1->handle, -1);
+        const sp<::android::Fence> presentFence1 =
+                presentAndGetFence(ComposerClientWriter::kNoTimestamp);
+        presentFence1->waitForever(LOG_TAG);
+
+        auto expectedPresentTime = presentFence1->getSignalTime() + vsyncPeriod;
+        if (framesDelay.has_value()) {
+            expectedPresentTime += *framesDelay * vsyncPeriod;
+        }
+
+        mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, buffer2->handle, -1);
+        const auto setExpectedPresentTime = [&]() -> std::optional<ClockMonotonicTimestamp> {
+            if (!framesDelay.has_value()) {
+                return ComposerClientWriter::kNoTimestamp;
+            } else if (*framesDelay == 0) {
+                return ClockMonotonicTimestamp{0};
+            }
+            return ClockMonotonicTimestamp{expectedPresentTime};
+        }();
+
+        const sp<::android::Fence> presentFence2 = presentAndGetFence(setExpectedPresentTime);
+        presentFence2->waitForever(LOG_TAG);
+
+        const auto actualPresentTime = presentFence2->getSignalTime();
+        EXPECT_GE(actualPresentTime, expectedPresentTime - vsyncPeriod / 2);
+
+        ASSERT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk());
+    }
+
+    // clang-format off
+    const std::array<float, 16> kIdentity = {{
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f,
+    }};
+    // clang-format on
+
+    ComposerClientWriter mWriter;
+    ComposerClientReader mReader;
+};
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_COLOR_TRANSFORM) {
+    mWriter.setColorTransform(mPrimaryDisplay, kIdentity.data());
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SetLayerColorTransform) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+    mWriter.setLayerColorTransform(mPrimaryDisplay, layer, kIdentity.data());
+    execute();
+
+    const auto errors = mReader.takeErrors();
+    if (errors.size() == 1 && errors[0].errorCode == IComposerClient::EX_UNSUPPORTED) {
+        GTEST_SUCCEED() << "setLayerColorTransform is not supported";
+        return;
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SetDisplayBrightness) {
+    std::vector<DisplayCapability> capabilities;
+    auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
+    ASSERT_TRUE(error.isOk());
+    bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
+                                       DisplayCapability::BRIGHTNESS) != capabilities.end();
+    if (!brightnessSupport) {
+        mWriter.setDisplayBrightness(mPrimaryDisplay, 0.5f);
+        execute();
+        const auto errors = mReader.takeErrors();
+        EXPECT_EQ(1, errors.size());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errors[0].errorCode);
+        GTEST_SUCCEED() << "SetDisplayBrightness is not supported";
+        return;
+    }
+
+    mWriter.setDisplayBrightness(mPrimaryDisplay, 0.0f);
+    execute();
+    EXPECT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setDisplayBrightness(mPrimaryDisplay, 0.5f);
+    execute();
+    EXPECT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setDisplayBrightness(mPrimaryDisplay, 1.0f);
+    execute();
+    EXPECT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setDisplayBrightness(mPrimaryDisplay, -1.0f);
+    execute();
+    EXPECT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setDisplayBrightness(mPrimaryDisplay, 2.0f);
+    execute();
+    {
+        const auto errors = mReader.takeErrors();
+        ASSERT_EQ(1, errors.size());
+        EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
+    }
+
+    mWriter.setDisplayBrightness(mPrimaryDisplay, -2.0f);
+    execute();
+    {
+        const auto errors = mReader.takeErrors();
+        ASSERT_EQ(1, errors.size());
+        EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_CLIENT_TARGET) {
+    EXPECT_TRUE(
+            mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount).isOk());
+
+    mWriter.setClientTarget(mPrimaryDisplay, 0, nullptr, -1, Dataspace::UNKNOWN,
+                            std::vector<Rect>());
+
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_OUTPUT_BUFFER) {
+    int32_t virtualDisplayCount;
+    EXPECT_TRUE(mComposerClient->getMaxVirtualDisplayCount(&virtualDisplayCount).isOk());
+    if (virtualDisplayCount == 0) {
+        GTEST_SUCCEED() << "no virtual display support";
+        return;
+    }
+
+    VirtualDisplay display;
+    EXPECT_TRUE(mComposerClient
+                        ->createVirtualDisplay(64, 64, common::PixelFormat::IMPLEMENTATION_DEFINED,
+                                               kBufferSlotCount, &display)
+                        .isOk());
+
+    const auto buffer = allocate();
+    const auto handle = buffer->handle;
+    mWriter.setOutputBuffer(display.display, 0, handle, -1);
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, VALIDATE_DISPLAY) {
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+    mWriter.acceptDisplayChanges(mPrimaryDisplay);
+    execute();
+}
+
+// TODO(b/208441745) fix the test failure
+TEST_P(GraphicsComposerAidlCommandTest, PRESENT_DISPLAY) {
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+    mWriter.presentDisplay(mPrimaryDisplay);
+    execute();
+}
+
+/**
+ * Test IComposerClient::Command::PRESENT_DISPLAY
+ *
+ * Test that IComposerClient::Command::PRESENT_DISPLAY works without
+ * additional call to validateDisplay when only the layer buffer handle and
+ * surface damage have been set
+ */
+// TODO(b/208441745) fix the test failure
+TEST_P(GraphicsComposerAidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+    if (!hasCapability(Capability::SKIP_VALIDATE)) {
+        GTEST_SUCCEED() << "Device does not have skip validate capability, skipping";
+        return;
+    }
+    mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON);
+
+    std::vector<RenderIntent> renderIntents;
+    mComposerClient->getRenderIntents(mPrimaryDisplay, ColorMode::NATIVE, &renderIntents);
+    for (auto intent : renderIntents) {
+        mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE, intent);
+
+        const auto buffer = allocate();
+        const auto handle = buffer->handle;
+        ASSERT_NE(nullptr, handle);
+
+        Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+
+        int64_t layer;
+        EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+        mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::DEVICE);
+        mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, displayFrame);
+        mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1);
+        mWriter.setLayerSourceCrop(mPrimaryDisplay, layer,
+                                   {0, 0, (float)mDisplayWidth, (float)mDisplayHeight});
+        mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0));
+        mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame));
+        mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10);
+        mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE);
+        mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame));
+        mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle, -1);
+        mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN);
+
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+            GTEST_SUCCEED() << "Composition change requested, skipping test";
+            return;
+        }
+
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+
+        const auto buffer2 = allocate();
+        const auto handle2 = buffer2->handle;
+        ASSERT_NE(nullptr, handle2);
+        mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle2, -1);
+        mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, {0, 0, 10, 10}));
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+    }
+}
+
+// TODO(b/208441745) fix the test failure
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_CURSOR_POSITION) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    const auto buffer = allocate();
+    const auto handle = buffer->handle;
+    ASSERT_NE(nullptr, handle);
+    Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+
+    mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle, -1);
+    mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::CURSOR);
+    mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, displayFrame);
+    mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1);
+    mWriter.setLayerSourceCrop(mPrimaryDisplay, layer,
+                               {0, 0, (float)mDisplayWidth, (float)mDisplayHeight});
+    mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0));
+    mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame));
+    mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10);
+    mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE);
+    mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame));
+    mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN);
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+
+    execute();
+
+    if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+        GTEST_SUCCEED() << "Composition change requested, skipping test";
+        return;
+    }
+    mWriter.presentDisplay(mPrimaryDisplay);
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerCursorPosition(mPrimaryDisplay, layer, 1, 1);
+    execute();
+
+    mWriter.setLayerCursorPosition(mPrimaryDisplay, layer, 0, 0);
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+    mWriter.presentDisplay(mPrimaryDisplay);
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_BUFFER) {
+    const auto buffer = allocate();
+    const auto handle = buffer->handle;
+    ASSERT_NE(nullptr, handle);
+
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+    mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle, -1);
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    Rect empty{0, 0, 0, 0};
+    Rect unit{0, 0, 1, 1};
+
+    mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, empty));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, unit));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>());
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_BLOCKING_REGION) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    Rect empty{0, 0, 0, 0};
+    Rect unit{0, 0, 1, 1};
+
+    mWriter.setLayerBlockingRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, empty));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerBlockingRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, unit));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerBlockingRegion(mPrimaryDisplay, layer, std::vector<Rect>());
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_BLEND_MODE) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::PREMULTIPLIED);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::COVERAGE);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_COLOR) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerColor(mPrimaryDisplay, layer, Color{1.0f, 1.0f, 1.0f, 1.0f});
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerColor(mPrimaryDisplay, layer, Color{0.0f, 0.0f, 0.0f, 0.0f});
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::CLIENT);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::DEVICE);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::SOLID_COLOR);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::CURSOR);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_DATASPACE) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN);
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, Rect{0, 0, 1, 1});
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_PLANE_ALPHA) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 0.0f);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1.0f);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
+    if (!hasCapability(Capability::SIDEBAND_STREAM)) {
+        GTEST_SUCCEED() << "no sideband stream support";
+        return;
+    }
+
+    const auto buffer = allocate();
+    const auto handle = buffer->handle;
+    ASSERT_NE(nullptr, handle);
+
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerSidebandStream(mPrimaryDisplay, layer, handle);
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_SOURCE_CROP) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerSourceCrop(mPrimaryDisplay, layer, FRect{0.0f, 0.0f, 1.0f, 1.0f});
+    execute();
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_TRANSFORM) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::FLIP_H);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::FLIP_V);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::ROT_90);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::ROT_180);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::ROT_270);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer,
+                              static_cast<Transform>(static_cast<int>(Transform::FLIP_H) |
+                                                     static_cast<int>(Transform::ROT_90)));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerTransform(mPrimaryDisplay, layer,
+                              static_cast<Transform>(static_cast<int>(Transform::FLIP_V) |
+                                                     static_cast<int>(Transform::ROT_90)));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_VISIBLE_REGION) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    Rect empty{0, 0, 0, 0};
+    Rect unit{0, 0, 1, 1};
+
+    mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, empty));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, unit));
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>());
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_Z_ORDER) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerZOrder(mPrimaryDisplay, layer, 0);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    /**
+     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+     * the D65 white point and the SRGB transfer functions.
+     * Rendering Intent: Colorimetric
+     * Primaries:
+     *                  x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+
+    std::vector<PerFrameMetadata> aidlMetadata;
+    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680f});
+    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320f});
+    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265f});
+    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690f});
+    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150f});
+    aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060f});
+    aidlMetadata.push_back({PerFrameMetadataKey::WHITE_POINT_X, 0.3127f});
+    aidlMetadata.push_back({PerFrameMetadataKey::WHITE_POINT_Y, 0.3290f});
+    aidlMetadata.push_back({PerFrameMetadataKey::MAX_LUMINANCE, 100.0f});
+    aidlMetadata.push_back({PerFrameMetadataKey::MIN_LUMINANCE, 0.1f});
+    aidlMetadata.push_back({PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
+    aidlMetadata.push_back({PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
+    mWriter.setLayerPerFrameMetadata(mPrimaryDisplay, layer, aidlMetadata);
+    execute();
+
+    const auto errors = mReader.takeErrors();
+    if (errors.size() == 1 && errors[0].errorCode == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported";
+        EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk());
+        return;
+    }
+
+    EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setLayerWhitePointNits) {
+    int64_t layer;
+    EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+    mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, 200.f);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, 1000.f);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, 0.f);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, -1.f);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints) {
+    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = false});
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints_Delayed) {
+    Test_setActiveConfigWithConstraints({.delayForChange = 300'000'000,  // 300ms
+                                         .refreshMiss = false});
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints_MissRefresh) {
+    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = true});
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, getDisplayVsyncPeriod) {
+    for (VtsDisplay& display : mDisplays) {
+        std::vector<int32_t> configs;
+        EXPECT_TRUE(mComposerClient->getDisplayConfigs(display.get(), &configs).isOk());
+        for (int32_t config : configs) {
+            int32_t expectedVsyncPeriodNanos = -1;
+            EXPECT_TRUE(mComposerClient
+                                ->getDisplayAttribute(display.get(), config,
+                                                      DisplayAttribute::VSYNC_PERIOD,
+                                                      &expectedVsyncPeriodNanos)
+                                .isOk());
+
+            VsyncPeriodChangeTimeline timeline;
+            VsyncPeriodChangeConstraints constraints;
+
+            constraints.desiredTimeNanos = systemTime();
+            constraints.seamlessRequired = false;
+            EXPECT_TRUE(mComposerClient
+                                ->setActiveConfigWithConstraints(display.get(), config, constraints,
+                                                                 &timeline)
+                                .isOk());
+
+            if (timeline.refreshRequired) {
+                sendRefreshFrame(display, &timeline);
+            }
+            waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos, 0,
+                                     expectedVsyncPeriodNanos);
+
+            int32_t vsyncPeriodNanos;
+            int retryCount = 100;
+            do {
+                std::this_thread::sleep_for(10ms);
+                vsyncPeriodNanos = 0;
+                EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos)
+                                    .isOk());
+                --retryCount;
+            } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0);
+
+            EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
+
+            // Make sure that the vsync period stays the same if the active config is not
+            // changed.
+            auto timeout = 1ms;
+            for (int i = 0; i < 10; i++) {
+                std::this_thread::sleep_for(timeout);
+                timeout *= 2;
+                vsyncPeriodNanos = 0;
+                EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos)
+                                    .isOk());
+                EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
+            }
+        }
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
+    VsyncPeriodChangeTimeline timeline;
+    VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = true;
+    constraints.desiredTimeNanos = systemTime();
+
+    for (VtsDisplay& display : mDisplays) {
+        forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) {
+            int32_t configGroup1;
+            EXPECT_TRUE(mComposerClient
+                                ->getDisplayAttribute(display.get(), config1,
+                                                      DisplayAttribute::CONFIG_GROUP, &configGroup1)
+                                .isOk());
+            int32_t configGroup2;
+            EXPECT_TRUE(mComposerClient
+                                ->getDisplayAttribute(display.get(), config2,
+                                                      DisplayAttribute::CONFIG_GROUP, &configGroup2)
+                                .isOk());
+            if (configGroup1 != configGroup2) {
+                setActiveConfig(display, config1);
+                sendRefreshFrame(display, nullptr);
+                EXPECT_EQ(IComposerClient::EX_SEAMLESS_NOT_ALLOWED,
+                          setActiveConfigWithConstraints(display, config2, constraints, &timeline)
+                                  .getServiceSpecificError());
+            }
+        });
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, expectedPresentTime_NoTimestamp) {
+    ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(std::nullopt));
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, expectedPresentTime_0) {
+    ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(0));
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, expectedPresentTime_5) {
+    ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(5));
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_Unsupported) {
+    const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+                                        DisplayCapability::DISPLAY_IDLE_TIMER);
+    if (!hasDisplayIdleTimerSupport) {
+        const auto error = mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 0);
+        EXPECT_FALSE(error.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_BadParameter) {
+    const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+                                        DisplayCapability::DISPLAY_IDLE_TIMER);
+    if (!hasDisplayIdleTimerSupport) {
+        GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
+        return;
+    }
+
+    const auto error = mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, -1);
+    EXPECT_FALSE(error.isOk());
+    EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_Disable) {
+    const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+                                        DisplayCapability::DISPLAY_IDLE_TIMER);
+    if (!hasDisplayIdleTimerSupport) {
+        GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
+        return;
+    }
+
+    EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 0).isOk());
+    std::this_thread::sleep_for(1s);
+    EXPECT_EQ(0, mComposerCallback->getVsyncIdleCount());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_Timeout_2) {
+    const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+                                        DisplayCapability::DISPLAY_IDLE_TIMER);
+    if (!hasDisplayIdleTimerSupport) {
+        GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
+        return;
+    }
+
+    EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk());
+    EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 0).isOk());
+
+    const auto buffer = allocate();
+    ASSERT_NE(nullptr, buffer->handle);
+
+    const auto layer = createOnScreenLayer();
+    mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, buffer->handle, -1);
+    int32_t vsyncIdleCount = mComposerCallback->getVsyncIdleCount();
+    auto earlyVsyncIdleTime = systemTime() + std::chrono::nanoseconds(2s).count();
+    EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 2000).isOk());
+
+    const sp<::android::Fence> presentFence =
+        presentAndGetFence(ComposerClientWriter::kNoTimestamp);
+    presentFence->waitForever(LOG_TAG);
+
+    std::this_thread::sleep_for(3s);
+    if (vsyncIdleCount < mComposerCallback->getVsyncIdleCount()) {
+        EXPECT_GE(mComposerCallback->getVsyncIdleTime(), earlyVsyncIdleTime);
+    }
+
+    EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerAidlCommandTest,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+        ::android::PrintInstanceNameToString);
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerAidlTest,
@@ -1395,5 +2263,41 @@
         ALOGE("Failed to stop init.svc.surfaceflinger");
         return -1;
     }
+
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+
+    // The binder threadpool we start will inherit sched policy and priority
+    // of (this) creating thread. We want the binder thread pool to have
+    // SCHED_FIFO policy and priority 1 (lowest RT priority)
+    // Once the pool is created we reset this thread's priority back to
+    // original.
+    // This thread policy is based on what we do in the SurfaceFlinger while starting
+    // the thread pool and we need to replicate that for the VTS tests.
+    int newPriority = 0;
+    int origPolicy = sched_getscheduler(0);
+    struct sched_param origSchedParam;
+
+    int errorInPriorityModification = sched_getparam(0, &origSchedParam);
+    if (errorInPriorityModification == 0) {
+        int policy = SCHED_FIFO;
+        newPriority = sched_get_priority_min(policy);
+
+        struct sched_param param;
+        param.sched_priority = newPriority;
+
+        errorInPriorityModification = sched_setscheduler(0, policy, &param);
+    }
+
+    // start the thread pool
+    android::ProcessState::self()->startThreadPool();
+
+    // Reset current thread's policy and priority
+    if (errorInPriorityModification == 0) {
+        errorInPriorityModification = sched_setscheduler(0, origPolicy, &origSchedParam);
+    } else {
+        ALOGE("Failed to set VtsHalGraphicsComposer3_TargetTest binder threadpool priority to "
+              "SCHED_FIFO");
+    }
+
     return RUN_ALL_TESTS();
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp
index 00ea4f3..df038db 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp
@@ -28,7 +28,8 @@
     defaults: ["hidl_defaults"],
     srcs: [
         "GraphicsComposerCallback.cpp",
-        "TestCommandReader.cpp",
+        "ReadbackVts.cpp",
+        "RenderEngineVts.cpp",
     ],
     header_libs: [
         "android.hardware.graphics.composer3-command-buffer",
@@ -38,20 +39,32 @@
         "android.hardware.graphics.common-V3-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
+        "libarect",
         "libgtest",
         "libbase",
         "libfmq",
         "libsync",
+        "libmath",
         "libaidlcommonsupport",
+        "libnativewindow",
+        "librenderengine",
+        "libshaders",
+        "libtonemap",
         "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
     ],
     shared_libs: [
         "libbinder_ndk",
         "libhidlbase",
+        "libui",
         "android.hardware.graphics.composer3-V1-ndk",
     ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.mapper@2.1-vts",
+        "librenderengine",
+    ],
     cflags: [
         "-O0",
         "-g",
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
index 307fe15..22b5d79 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
@@ -16,6 +16,7 @@
 
 #include "include/GraphicsComposerCallback.h"
 #include <log/log_main.h>
+#include <utils/Timers.h>
 
 #pragma push_macro("LOG_TAG")
 #undef LOG_TAG
@@ -58,6 +59,16 @@
     return mInvalidSeamlessPossibleCount;
 }
 
+int32_t GraphicsComposerCallback::getVsyncIdleCount() const {
+    std::scoped_lock lock(mMutex);
+    return mVsyncIdleCount;
+}
+
+int64_t GraphicsComposerCallback::getVsyncIdleTime() const {
+    std::scoped_lock lock(mMutex);
+    return mVsyncIdleTime;
+}
+
 std::optional<VsyncPeriodChangeTimeline>
 GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() {
     std::scoped_lock lock(mMutex);
@@ -125,4 +136,13 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus GraphicsComposerCallback::onVsyncIdle(int64_t in_display) {
+    std::scoped_lock lock(mMutex);
+    if (mDisplays.count(in_display)) {
+        mVsyncIdleCount++;
+        mVsyncIdleTime = systemTime();
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
new file mode 100644
index 0000000..587c523
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
@@ -0,0 +1,358 @@
+/**
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "include/ReadbackVts.h"
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include "include/RenderEngineVts.h"
+#include "renderengine/ExternalTexture.h"
+#include "renderengine/impl/ExternalTexture.h"
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop  // ignored "-Wconversion
+
+namespace aidl::android::hardware::graphics::composer3::vts {
+
+const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
+const std::vector<Dataspace> ReadbackHelper::dataspaces = {common::Dataspace::SRGB,
+                                                           common::Dataspace::DISPLAY_P3};
+
+void TestLayer::write(ComposerClientWriter& writer) {
+    writer.setLayerDisplayFrame(mDisplay, mLayer, mDisplayFrame);
+    writer.setLayerSourceCrop(mDisplay, mLayer, mSourceCrop);
+    writer.setLayerZOrder(mDisplay, mLayer, mZOrder);
+    writer.setLayerSurfaceDamage(mDisplay, mLayer, mSurfaceDamage);
+    writer.setLayerTransform(mDisplay, mLayer, mTransform);
+    writer.setLayerPlaneAlpha(mDisplay, mLayer, mAlpha);
+    writer.setLayerBlendMode(mDisplay, mLayer, mBlendMode);
+    writer.setLayerWhitePointNits(mDisplay, mLayer, mWhitePointNits);
+}
+
+std::string ReadbackHelper::getColorModeString(ColorMode mode) {
+    switch (mode) {
+        case ColorMode::SRGB:
+            return {"SRGB"};
+        case ColorMode::DISPLAY_P3:
+            return {"DISPLAY_P3"};
+        default:
+            return {"Unsupported color mode for readback"};
+    }
+}
+
+std::string ReadbackHelper::getDataspaceString(common::Dataspace dataspace) {
+    switch (dataspace) {
+        case common::Dataspace::SRGB:
+            return {"SRGB"};
+        case common::Dataspace::DISPLAY_P3:
+            return {"DISPLAY_P3"};
+        case common::Dataspace::UNKNOWN:
+            return {"UNKNOWN"};
+        default:
+            return {"Unsupported dataspace for readback"};
+    }
+}
+
+Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) {
+    switch (mode) {
+        case ColorMode::DISPLAY_P3:
+            return Dataspace::DISPLAY_P3;
+        case ColorMode::SRGB:
+        default:
+            return common::Dataspace::UNKNOWN;
+    }
+}
+
+LayerSettings TestLayer::toRenderEngineLayerSettings() {
+    LayerSettings layerSettings;
+
+    layerSettings.alpha = ::android::half(mAlpha);
+    layerSettings.disableBlending = mBlendMode == BlendMode::NONE;
+    layerSettings.geometry.boundaries = ::android::FloatRect(
+            static_cast<float>(mDisplayFrame.left), static_cast<float>(mDisplayFrame.top),
+            static_cast<float>(mDisplayFrame.right), static_cast<float>(mDisplayFrame.bottom));
+
+    const ::android::mat4 translation = ::android::mat4::translate(::android::vec4(
+            (static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_H)
+                     ? static_cast<float>(-mDisplayFrame.right)
+                     : 0.0f),
+            (static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_V)
+                     ? static_cast<float>(-mDisplayFrame.bottom)
+                     : 0.0f),
+            0.0f, 1.0f));
+
+    const ::android::mat4 scale = ::android::mat4::scale(::android::vec4(
+            static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_H) ? -1.0f
+                                                                                         : 1.0f,
+            static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_V) ? -1.0f
+                                                                                         : 1.0f,
+            1.0f, 1.0f));
+
+    layerSettings.geometry.positionTransform = scale * translation;
+    layerSettings.whitePointNits = mWhitePointNits;
+
+    return layerSettings;
+}
+
+int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
+    switch (pixelFormat) {
+        case common::PixelFormat::RGBA_8888:
+            return 4;
+        case common::PixelFormat::RGB_888:
+            return 3;
+        default:
+            return -1;
+    }
+}
+
+void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
+                                common::PixelFormat pixelFormat,
+                                std::vector<Color> desiredPixelColors) {
+    ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 ||
+                pixelFormat == common::PixelFormat::RGBA_8888);
+    int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+    ASSERT_NE(-1, bytesPerPixel);
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            auto pixel = row * static_cast<int32_t>(width) + col;
+            Color srcColor = desiredPixelColors[static_cast<size_t>(pixel)];
+
+            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
+            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+            pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * srcColor.r));
+            pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * srcColor.g));
+            pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * srcColor.b));
+
+            if (bytesPerPixel == 4) {
+                pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * srcColor.a));
+            }
+        }
+    }
+}
+
+void ReadbackHelper::clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+                                 int32_t displayWidth) {
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            int pixel = row * displayWidth + col;
+            expectedColors[static_cast<size_t>(pixel)] = BLACK;
+        }
+    }
+}
+
+void ReadbackHelper::fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
+                                    Color color) {
+    for (int row = area.top; row < area.bottom; row++) {
+        for (int col = area.left; col < area.right; col++) {
+            int pixel = row * stride + col;
+            expectedColors[static_cast<size_t>(pixel)] = color;
+        }
+    }
+}
+
+bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
+                                       const common::Dataspace& dataspace) {
+    if (pixelFormat != common::PixelFormat::RGB_888 &&
+        pixelFormat != common::PixelFormat::RGBA_8888) {
+        return false;
+    }
+    if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
+        return false;
+    }
+    return true;
+}
+
+void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
+                                         const uint32_t stride, const uint32_t width,
+                                         const uint32_t height, common::PixelFormat pixelFormat) {
+    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+    ASSERT_NE(-1, bytesPerPixel);
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            auto pixel = row * static_cast<int32_t>(width) + col;
+            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
+            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+            const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
+            ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
+            ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
+            ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
+        }
+    }
+}
+
+ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr<IComposerClient>& client,
+                               int32_t width, int32_t height, common::PixelFormat pixelFormat,
+                               common::Dataspace dataspace) {
+    mDisplay = display;
+
+    mComposerClient = client;
+
+    mPixelFormat = pixelFormat;
+    mDataspace = dataspace;
+
+    mWidth = static_cast<uint32_t>(width);
+    mHeight = static_cast<uint32_t>(height);
+    mLayerCount = 1;
+    mUsage = static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                                   static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
+
+    mAccessRegion.top = 0;
+    mAccessRegion.left = 0;
+    mAccessRegion.right = static_cast<int32_t>(width);
+    mAccessRegion.bottom = static_cast<int32_t>(height);
+}
+
+::android::sp<::android::GraphicBuffer> ReadbackBuffer::allocate() {
+    return ::android::sp<::android::GraphicBuffer>::make(
+            mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
+            "ReadbackVts");
+}
+
+void ReadbackBuffer::setReadbackBuffer() {
+    mGraphicBuffer = allocate();
+    ASSERT_NE(nullptr, mGraphicBuffer);
+    ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+    aidl::android::hardware::common::NativeHandle bufferHandle =
+            ::android::dupToAidl(mGraphicBuffer->handle);
+    ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
+    EXPECT_TRUE(mComposerClient->setReadbackBuffer(mDisplay, bufferHandle, fence).isOk());
+}
+
+void ReadbackBuffer::checkReadbackBuffer(std::vector<Color> expectedColors) {
+    ASSERT_NE(nullptr, mGraphicBuffer);
+    // lock buffer for reading
+    ndk::ScopedFileDescriptor fenceHandle;
+    EXPECT_TRUE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle).isOk());
+
+    int bytesPerPixel = -1;
+    int bytesPerStride = -1;
+    void* bufData = nullptr;
+
+    auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(fenceHandle.get()),
+                                            &bytesPerPixel, &bytesPerStride);
+    EXPECT_EQ(::android::OK, status);
+    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                    : mGraphicBuffer->getStride();
+    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
+                                        mPixelFormat);
+    status = mGraphicBuffer->unlock();
+    EXPECT_EQ(::android::OK, status);
+}
+
+void TestColorLayer::write(ComposerClientWriter& writer) {
+    TestLayer::write(writer);
+    writer.setLayerCompositionType(mDisplay, mLayer, Composition::SOLID_COLOR);
+    writer.setLayerColor(mDisplay, mLayer, mColor);
+}
+
+LayerSettings TestColorLayer::toRenderEngineLayerSettings() {
+    LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+
+    layerSettings.source.solidColor = ::android::half3(mColor.r, mColor.g, mColor.b);
+    layerSettings.alpha = mAlpha * mColor.a;
+    return layerSettings;
+}
+
+TestBufferLayer::TestBufferLayer(const std::shared_ptr<IComposerClient>& client,
+                                 const ::android::sp<::android::GraphicBuffer>& graphicBuffer,
+                                 TestRenderEngine& renderEngine, int64_t display, uint32_t width,
+                                 uint32_t height, common::PixelFormat format,
+                                 Composition composition)
+    : TestLayer{client, display}, mRenderEngine(renderEngine) {
+    mGraphicBuffer = graphicBuffer;
+    mComposition = composition;
+    mWidth = width;
+    mHeight = height;
+    mLayerCount = 1;
+    mPixelFormat = format;
+    mUsage = (static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+              static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+              static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY) |
+              static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
+
+    mAccessRegion.top = 0;
+    mAccessRegion.left = 0;
+    mAccessRegion.right = static_cast<int32_t>(width);
+    mAccessRegion.bottom = static_cast<int32_t>(height);
+
+    setSourceCrop({0, 0, (float)width, (float)height});
+}
+
+void TestBufferLayer::write(ComposerClientWriter& writer) {
+    TestLayer::write(writer);
+    writer.setLayerCompositionType(mDisplay, mLayer, mComposition);
+    writer.setLayerVisibleRegion(mDisplay, mLayer, std::vector<Rect>(1, mDisplayFrame));
+    if (mGraphicBuffer->handle != nullptr)
+        writer.setLayerBuffer(mDisplay, mLayer, 0, mGraphicBuffer->handle, mFillFence);
+}
+
+LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
+    LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+    layerSettings.source.buffer.buffer =
+            std::make_shared<::android::renderengine::impl::ExternalTexture>(
+                    mGraphicBuffer, mRenderEngine.getInternalRenderEngine(),
+                    ::android::renderengine::impl::ExternalTexture::Usage::READABLE);
+
+    layerSettings.source.buffer.usePremultipliedAlpha = mBlendMode == BlendMode::PREMULTIPLIED;
+
+    const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (static_cast<float>(mWidth));
+    const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (static_cast<float>(mHeight));
+    const float translateX = mSourceCrop.left / (static_cast<float>(mWidth));
+    const float translateY = mSourceCrop.top / (static_cast<float>(mHeight));
+
+    layerSettings.source.buffer.textureTransform =
+            ::android::mat4::translate(::android::vec4(translateX, translateY, 0, 1.0)) *
+            ::android::mat4::scale(::android::vec4(scaleX, scaleY, 1.0, 1.0));
+
+    return layerSettings;
+}
+
+void TestBufferLayer::fillBuffer(std::vector<Color>& expectedColors) {
+    void* bufData;
+    int32_t bytesPerPixel = -1;
+    int32_t bytesPerStride = -1;
+    auto status = mGraphicBuffer->lock(mUsage, &bufData, &bytesPerPixel, &bytesPerStride);
+    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                    : mGraphicBuffer->getStride();
+    EXPECT_EQ(::android::OK, status);
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
+                                                       mPixelFormat, expectedColors));
+    EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
+}
+
+void TestBufferLayer::setBuffer(std::vector<Color> colors) {
+    mGraphicBuffer->reallocate(mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat),
+                               mLayerCount, mUsage);
+    ASSERT_NE(nullptr, mGraphicBuffer);
+    ASSERT_NE(nullptr, mGraphicBuffer->handle);
+    ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+    ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+}
+
+void TestBufferLayer::setDataspace(common::Dataspace dataspace, ComposerClientWriter& writer) {
+    writer.setLayerDataspace(mDisplay, mLayer, dataspace);
+}
+
+void TestBufferLayer::setToClientComposition(ComposerClientWriter& writer) {
+    writer.setLayerCompositionType(mDisplay, mLayer, Composition::CLIENT);
+}
+
+}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp
new file mode 100644
index 0000000..0a55484
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/RenderEngineVts.h"
+#include "renderengine/impl/ExternalTexture.h"
+
+namespace aidl::android::hardware::graphics::composer3::vts {
+
+using ::android::hardware::graphics::mapper::V2_1::IMapper;
+using ::android::renderengine::DisplaySettings;
+using ::android::renderengine::LayerSettings;
+using ::android::renderengine::RenderEngineCreationArgs;
+
+TestRenderEngine::TestRenderEngine(const RenderEngineCreationArgs& args) {
+    mFormat = static_cast<common::PixelFormat>(args.pixelFormat);
+    mRenderEngine = ::android::renderengine::RenderEngine::create(args);
+}
+
+TestRenderEngine::~TestRenderEngine() {
+    mRenderEngine.release();
+}
+
+void TestRenderEngine::setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers) {
+    sort(layers.begin(), layers.end(),
+         [](const std::shared_ptr<TestLayer>& lhs, const std::shared_ptr<TestLayer>& rhs) -> bool {
+             return lhs->getZOrder() < rhs->getZOrder();
+         });
+
+    if (!mCompositionLayers.empty()) {
+        mCompositionLayers.clear();
+    }
+    for (auto& layer : layers) {
+        LayerSettings settings = layer->toRenderEngineLayerSettings();
+        mCompositionLayers.push_back(settings);
+    }
+}
+
+void TestRenderEngine::initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
+                                         uint64_t usage) {
+    mGraphicBuffer = ::android::sp<::android::GraphicBuffer>::make(
+            width, height, static_cast<int32_t>(mFormat), layerCount, usage);
+}
+
+void TestRenderEngine::drawLayers() {
+    ::android::base::unique_fd bufferFence;
+
+    std::vector<::android::renderengine::LayerSettings> compositionLayers;
+    compositionLayers.reserve(mCompositionLayers.size());
+    std::transform(mCompositionLayers.begin(), mCompositionLayers.end(),
+                   std::back_insert_iterator(compositionLayers),
+                   [](::android::renderengine::LayerSettings& settings)
+                           -> ::android::renderengine::LayerSettings { return settings; });
+    auto texture = std::make_shared<::android::renderengine::impl::ExternalTexture>(
+            mGraphicBuffer, *mRenderEngine,
+            ::android::renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+    auto [status, readyFence] = mRenderEngine
+                                        ->drawLayers(mDisplaySettings, compositionLayers, texture,
+                                                     true, std::move(bufferFence))
+                                        .get();
+    int fd = readyFence.release();
+    if (fd != -1) {
+        ASSERT_EQ(0, sync_wait(fd, -1));
+        ASSERT_EQ(0, close(fd));
+    }
+}
+
+void TestRenderEngine::checkColorBuffer(const std::vector<Color>& expectedColors) {
+    void* bufferData;
+    int32_t bytesPerPixel = -1;
+    int32_t bytesPerStride = -1;
+    ASSERT_EQ(0, mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()),
+                                      &bufferData, &bytesPerPixel, &bytesPerStride));
+    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                    : mGraphicBuffer->getStride();
+    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
+                                        mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
+                                        mFormat);
+    ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
+}
+
+}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/TestCommandReader.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/TestCommandReader.cpp
deleted file mode 100644
index a5a84d9..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/TestCommandReader.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "include/TestCommandReader.h"
-#include <gtest/gtest.h>
-
-namespace aidl::android::hardware::graphics::composer3::vts {
-
-void TestCommandReader::parse() {
-    mErrors.clear();
-    mCompositionChanges.clear();
-    while (!isEmpty()) {
-        int32_t command;
-        uint16_t length;
-        ASSERT_TRUE(beginCommand(&command, &length));
-
-        parseSingleCommand(command, length);
-
-        endCommand();
-    }
-}
-
-void TestCommandReader::parseSingleCommand(int32_t commandRaw, uint16_t length) {
-    auto command = static_cast<Command>(commandRaw);
-
-    switch (command) {
-        case Command::SET_CLIENT_TARGET_PROPERTY: {
-            ASSERT_EQ(2, length);
-            read();
-            close(readFence());
-        } break;
-        case Command::SELECT_DISPLAY: {
-            ASSERT_EQ(2, length);
-            read64();  // display
-        } break;
-        case Command::SET_ERROR: {
-            ASSERT_EQ(2, length);
-            auto loc = read();
-            auto err = readSigned();
-            std::pair<uint32_t, uint32_t> error(loc, err);
-            mErrors.push_back(error);
-        } break;
-        case Command::SET_CHANGED_COMPOSITION_TYPES: {
-            ASSERT_EQ(0, length % 3);
-            for (uint16_t count = 0; count < length / 3; ++count) {
-                uint64_t layerId = read64();
-                uint32_t composition = read();
-
-                std::pair<uint64_t, uint32_t> compositionChange(layerId, composition);
-                mCompositionChanges.push_back(compositionChange);
-            }
-        } break;
-        case Command::SET_DISPLAY_REQUESTS: {
-            ASSERT_EQ(1, length % 3);
-            read();  // displayRequests, ignored for now
-            for (uint16_t count = 0; count < (length - 1) / 3; ++count) {
-                read64();  // layer
-                // silently eat requests to clear the client target, since we won't be testing
-                // client composition anyway
-                ASSERT_EQ(1u, read());
-            }
-        } break;
-        case Command::SET_PRESENT_FENCE: {
-            ASSERT_EQ(1, length);
-            close(readFence());
-        } break;
-        case Command::SET_RELEASE_FENCES: {
-            ASSERT_EQ(0, length % 3);
-            for (uint16_t count = 0; count < length / 3; ++count) {
-                read64();
-                close(readFence());
-            }
-        } break;
-        default:
-            GTEST_FAIL() << "unexpected return command " << std::hex << static_cast<int>(command);
-            break;
-    }
-}
-}  // namespace aidl::android::hardware::graphics::composer3::vts
\ No newline at end of file
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
index c359d5e..f25f36d 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
@@ -45,6 +45,10 @@
 
     int32_t getInvalidSeamlessPossibleCount() const;
 
+    int32_t getVsyncIdleCount() const;
+
+    int64_t getVsyncIdleTime() const;
+
     std::optional<VsyncPeriodChangeTimeline> takeLastVsyncPeriodChangeTimeline();
 
   private:
@@ -57,6 +61,7 @@
             int64_t in_display,
             const ::aidl::android::hardware::graphics::composer3::VsyncPeriodChangeTimeline&
                     in_updatedTimeline) override;
+    virtual ::ndk::ScopedAStatus onVsyncIdle(int64_t in_display) override;
 
     mutable std::mutex mMutex;
     // the set of all currently connected displays
@@ -66,6 +71,9 @@
 
     std::optional<VsyncPeriodChangeTimeline> mTimeline GUARDED_BY(mMutex);
 
+    int32_t mVsyncIdleCount GUARDED_BY(mMutex) = 0;
+    int64_t mVsyncIdleTime GUARDED_BY(mMutex) = 0;
+
     // track invalid callbacks
     int32_t mInvalidHotplugCount GUARDED_BY(mMutex) = 0;
     int32_t mInvalidRefreshCount GUARDED_BY(mMutex) = 0;
@@ -74,4 +82,4 @@
     int32_t mInvalidSeamlessPossibleCount GUARDED_BY(mMutex) = 0;
 };
 
-}  // namespace aidl::android::hardware::graphics::composer3::vts
\ No newline at end of file
+}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
new file mode 100644
index 0000000..a3ce795
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
@@ -0,0 +1,221 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <GraphicsComposerCallback.h>
+#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer3/ComposerClientReader.h>
+#include <android/hardware/graphics/composer3/ComposerClientWriter.h>
+#include <mapper-vts/2.1/MapperVts.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+
+#include <memory>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop  // ignored "-Wconversion
+
+namespace aidl::android::hardware::graphics::composer3::vts {
+
+using ::android::renderengine::LayerSettings;
+using common::Dataspace;
+using common::PixelFormat;
+using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
+
+static const Color BLACK = {0.0f, 0.0f, 0.0f, 1.0f};
+static const Color RED = {1.0f, 0.0f, 0.0f, 1.0f};
+// DIM_RED is 90% dimmed from RED in linear space
+// hard-code as value 243 in 8-bit space here, as calculating it requires
+// oetf(eotf(value) * .9), which is a complex non-linear transformation
+static const Color DIM_RED = {243.f / 255.f, 0.0f, 0.0f, 1.0f};
+static const Color TRANSLUCENT_RED = {1.0f, 0.0f, 0.0f, 0.3f};
+static const Color GREEN = {0.0f, 1.0f, 0.0f, 1.0f};
+static const Color BLUE = {0.0f, 0.0f, 1.0f, 1.0f};
+static const Color WHITE = {1.0f, 1.0f, 1.0f, 1.0f};
+
+class TestRenderEngine;
+
+class TestLayer {
+  public:
+    TestLayer(const std::shared_ptr<IComposerClient>& client, int64_t display)
+        : mDisplay(display), mComposerClient(client) {
+        client->createLayer(display, kBufferSlotCount, &mLayer);
+    }
+
+    // ComposerClient will take care of destroying layers, no need to explicitly
+    // call destroyLayers here
+    virtual ~TestLayer(){};
+
+    virtual void write(ComposerClientWriter& writer);
+    virtual LayerSettings toRenderEngineLayerSettings();
+
+    void setDisplayFrame(Rect frame) { mDisplayFrame = frame; }
+    void setSourceCrop(FRect crop) { mSourceCrop = crop; }
+    void setZOrder(uint32_t z) { mZOrder = z; }
+    void setWhitePointNits(float whitePointNits) { mWhitePointNits = whitePointNits; }
+
+    void setSurfaceDamage(std::vector<Rect> surfaceDamage) {
+        mSurfaceDamage = std::move(surfaceDamage);
+    }
+
+    void setTransform(Transform transform) { mTransform = transform; }
+    void setAlpha(float alpha) { mAlpha = alpha; }
+    void setBlendMode(BlendMode blendMode) { mBlendMode = blendMode; }
+
+    BlendMode getBlendMode() const { return mBlendMode; }
+
+    uint32_t getZOrder() const { return mZOrder; }
+
+    float getAlpha() const { return mAlpha; }
+
+    int64_t getLayer() const { return mLayer; }
+
+    float getWhitePointNits() const { return mWhitePointNits; }
+
+  protected:
+    int64_t mDisplay;
+    int64_t mLayer;
+    Rect mDisplayFrame = {0, 0, 0, 0};
+    float mWhitePointNits = -1.f;
+    std::vector<Rect> mSurfaceDamage;
+    Transform mTransform = static_cast<Transform>(0);
+    FRect mSourceCrop = {0, 0, 0, 0};
+    static constexpr uint32_t kBufferSlotCount = 64;
+    float mAlpha = 1.0;
+    BlendMode mBlendMode = BlendMode::NONE;
+    uint32_t mZOrder = 0;
+
+  private:
+    std::shared_ptr<IComposerClient> const mComposerClient;
+};
+
+class TestColorLayer : public TestLayer {
+  public:
+    TestColorLayer(const std::shared_ptr<IComposerClient>& client, int64_t display)
+        : TestLayer{client, display} {}
+
+    void write(ComposerClientWriter& writer) override;
+
+    LayerSettings toRenderEngineLayerSettings() override;
+
+    void setColor(Color color) { mColor = color; }
+
+  private:
+    Color mColor = WHITE;
+};
+
+class TestBufferLayer : public TestLayer {
+  public:
+    TestBufferLayer(const std::shared_ptr<IComposerClient>& client,
+                    const ::android::sp<::android::GraphicBuffer>& graphicBuffer,
+                    TestRenderEngine& renderEngine, int64_t display, uint32_t width,
+                    uint32_t height, common::PixelFormat format,
+                    Composition composition = Composition::DEVICE);
+
+    void write(ComposerClientWriter& writer) override;
+
+    LayerSettings toRenderEngineLayerSettings() override;
+
+    void fillBuffer(std::vector<Color>& expectedColors);
+
+    void setBuffer(std::vector<Color> colors);
+
+    void setDataspace(Dataspace dataspace, ComposerClientWriter& writer);
+
+    void setToClientComposition(ComposerClientWriter& writer);
+
+    uint32_t getWidth() const { return mWidth; }
+
+    uint32_t getHeight() const { return mHeight; }
+
+    ::android::Rect getAccessRegion() const { return mAccessRegion; }
+
+    uint32_t getLayerCount() const { return mLayerCount; }
+
+  protected:
+    Composition mComposition;
+    ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+    TestRenderEngine& mRenderEngine;
+    int32_t mFillFence;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mLayerCount;
+    PixelFormat mPixelFormat;
+    uint32_t mUsage;
+    ::android::Rect mAccessRegion;
+};
+
+class ReadbackHelper {
+  public:
+    static std::string getColorModeString(ColorMode mode);
+
+    static std::string getDataspaceString(Dataspace dataspace);
+
+    static Dataspace getDataspaceForColorMode(ColorMode mode);
+
+    static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+
+    static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
+                           PixelFormat pixelFormat, std::vector<Color> desiredPixelColors);
+
+    static void clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+                            int32_t displayWidth);
+
+    static void fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
+                               Color color);
+
+    static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace);
+
+    static const std::vector<ColorMode> colorModes;
+    static const std::vector<Dataspace> dataspaces;
+
+    static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
+                                    const uint32_t stride, const uint32_t width,
+                                    const uint32_t height, PixelFormat pixelFormat);
+};
+
+class ReadbackBuffer {
+  public:
+    ReadbackBuffer(int64_t display, const std::shared_ptr<IComposerClient>& client, int32_t width,
+                   int32_t height, common::PixelFormat pixelFormat, common::Dataspace dataspace);
+
+    void setReadbackBuffer();
+
+    void checkReadbackBuffer(std::vector<Color> expectedColors);
+
+    ::android::sp<::android::GraphicBuffer> allocate();
+
+  protected:
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mLayerCount;
+    uint32_t mUsage;
+    PixelFormat mPixelFormat;
+    Dataspace mDataspace;
+    int64_t mDisplay;
+    ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+    std::shared_ptr<IComposerClient> mComposerClient;
+    ::android::Rect mAccessRegion;
+    native_handle_t mBufferHandle;
+};
+
+}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h
new file mode 100644
index 0000000..a776a27
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h
@@ -0,0 +1,71 @@
+/**
+ * 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.
+ */
+#pragma once
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <ReadbackVts.h>
+#include <mapper-vts/2.1/MapperVts.h>
+#include <math/half.h>
+#include <math/vec3.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop  // ignored "-Wconversion
+
+namespace aidl::android::hardware::graphics::composer3::vts {
+
+using ::android::hardware::graphics::mapper::V2_1::IMapper;
+using ::android::renderengine::DisplaySettings;
+using ::android::renderengine::ExternalTexture;
+using ::android::renderengine::RenderEngineCreationArgs;
+
+class TestRenderEngine {
+  public:
+    static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2;
+
+    TestRenderEngine(const RenderEngineCreationArgs& args);
+    ~TestRenderEngine();
+
+    void setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers);
+    void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage);
+    void setDisplaySettings(DisplaySettings& displaySettings) {
+        mDisplaySettings = displaySettings;
+    };
+    void drawLayers();
+    void checkColorBuffer(const std::vector<Color>& expectedColors);
+
+    ::android::renderengine::RenderEngine& getInternalRenderEngine() { return *mRenderEngine; }
+
+  private:
+    common::PixelFormat mFormat;
+    std::vector<::android::renderengine::LayerSettings> mCompositionLayers;
+    std::unique_ptr<::android::renderengine::RenderEngine> mRenderEngine;
+    std::vector<::android::renderengine::LayerSettings> mRenderLayers;
+    ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+
+    DisplaySettings mDisplaySettings;
+};
+
+}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/TestCommandReader.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/TestCommandReader.h
deleted file mode 100644
index 852a56e..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/TestCommandReader.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#include <android/hardware/graphics/composer3/command-buffer.h>
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop  // ignored "-Wconversion
-
-namespace aidl::android::hardware::graphics::composer3::vts {
-
-class TestCommandReader : public CommandReaderBase {
-  public:
-    virtual ~TestCommandReader() = default;
-
-    std::vector<std::pair<uint32_t, uint32_t>> mErrors;
-    std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges;
-
-    // Parse all commands in the return command queue.  Call GTEST_FAIL() for
-    // unexpected errors or commands.
-    void parse();
-    virtual void parseSingleCommand(int32_t commandRaw, uint16_t length);
-};
-}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
new file mode 100644
index 0000000..f9e35e9
--- /dev/null
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <aidl/android/hardware/graphics/composer3/ClientTargetProperty.h>
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/CommandResultPayload.h>
+
+
+#include <log/log.h>
+#include <sync/sync.h>
+
+
+using aidl::android::hardware::graphics::common::Dataspace;
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+class ComposerClientReader {
+  public:
+    ~ComposerClientReader() { resetData(); }
+
+    // Parse and execute commands from the command queue.  The commands are
+    // actually return values from the server and will be saved in ReturnData.
+    void parse(std::vector<CommandResultPayload>&& results) {
+        resetData();
+
+        for (auto& result : results) {
+            switch (result.getTag()) {
+                case CommandResultPayload::Tag::error:
+                    parseSetError(std::move(result.get<CommandResultPayload::Tag::error>()));
+                    break;
+                case CommandResultPayload::Tag::changedCompositionTypes:
+                    parseSetChangedCompositionTypes(std::move(
+                            result.get<CommandResultPayload::Tag::changedCompositionTypes>()));
+                    break;
+                case CommandResultPayload::Tag::displayRequest:
+                    parseSetDisplayRequests(
+                            std::move(result.get<CommandResultPayload::Tag::displayRequest>()));
+                    break;
+                case CommandResultPayload::Tag::presentFence:
+                    parseSetPresentFence(
+                            std::move(result.get<CommandResultPayload::Tag::presentFence>()));
+                    break;
+                case CommandResultPayload::Tag::releaseFences:
+                    parseSetReleaseFences(
+                            std::move(result.get<CommandResultPayload::Tag::releaseFences>()));
+                    break;
+                case CommandResultPayload::Tag::presentOrValidateResult:
+                    parseSetPresentOrValidateDisplayResult(std::move(
+                            result.get<CommandResultPayload::Tag::presentOrValidateResult>()));
+                    break;
+                case CommandResultPayload::Tag::clientTargetProperty:
+                    parseSetClientTargetProperty(std::move(
+                            result.get<CommandResultPayload::Tag::clientTargetProperty>()));
+                    break;
+            }
+        }
+    }
+
+    std::vector<CommandError> takeErrors() { return std::move(mErrors); }
+
+    void hasChanges(int64_t display, uint32_t* outNumChangedCompositionTypes,
+                    uint32_t* outNumLayerRequestMasks) const {
+        auto found = mReturnData.find(display);
+        if (found == mReturnData.end()) {
+            *outNumChangedCompositionTypes = 0;
+            *outNumLayerRequestMasks = 0;
+            return;
+        }
+
+        const ReturnData& data = found->second;
+
+        *outNumChangedCompositionTypes = static_cast<uint32_t>(data.changedLayers.size());
+        *outNumLayerRequestMasks = static_cast<uint32_t>(data.displayRequests.layerRequests.size());
+    }
+
+    // Get and clear saved changed composition types.
+    std::vector<ChangedCompositionLayer> takeChangedCompositionTypes(int64_t display) {
+        auto found = mReturnData.find(display);
+        if (found == mReturnData.end()) {
+            return {};
+        }
+
+        ReturnData& data = found->second;
+        return std::move(data.changedLayers);
+    }
+
+    // Get and clear saved display requests.
+    DisplayRequest takeDisplayRequests(int64_t display) {
+        auto found = mReturnData.find(display);
+        if (found == mReturnData.end()) {
+            return {};
+        }
+
+        ReturnData& data = found->second;
+        return std::move(data.displayRequests);
+    }
+
+    // Get and clear saved release fences.
+    std::vector<ReleaseFences::Layer> takeReleaseFences(int64_t display) {
+        auto found = mReturnData.find(display);
+        if (found == mReturnData.end()) {
+            return {};
+        }
+
+        ReturnData& data = found->second;
+        return std::move(data.releasedLayers);
+    }
+
+    // Get and clear saved present fence.
+    ndk::ScopedFileDescriptor takePresentFence(int64_t display) {
+        auto found = mReturnData.find(display);
+        if (found == mReturnData.end()) {
+            return {};
+        }
+
+        ReturnData& data = found->second;
+        return std::move(data.presentFence);
+    }
+
+    // Get what stage succeeded during PresentOrValidate: Present or Validate
+    std::optional<PresentOrValidate::Result> takePresentOrValidateStage(int64_t display) {
+        auto found = mReturnData.find(display);
+        if (found == mReturnData.end()) {
+            return std::nullopt;
+        }
+        ReturnData& data = found->second;
+        return data.presentOrValidateState;
+    }
+
+    // Get the client target properties requested by hardware composer.
+    ClientTargetPropertyWithNits takeClientTargetProperty(int64_t display) {
+        auto found = mReturnData.find(display);
+
+        // If not found, return the default values.
+        if (found == mReturnData.end()) {
+            return ClientTargetPropertyWithNits{
+                    .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN},
+                    .whitePointNits = -1.f,
+            };
+        }
+
+        ReturnData& data = found->second;
+        return std::move(data.clientTargetProperty);
+    }
+
+  private:
+    void resetData() {
+        mErrors.clear();
+        mReturnData.clear();
+    }
+
+    void parseSetError(CommandError&& error) { mErrors.emplace_back(error); }
+
+    void parseSetChangedCompositionTypes(ChangedCompositionTypes&& changedCompositionTypes) {
+        auto& data = mReturnData[changedCompositionTypes.display];
+        data.changedLayers = std::move(changedCompositionTypes.layers);
+    }
+
+    void parseSetDisplayRequests(DisplayRequest&& displayRequest) {
+        auto& data = mReturnData[displayRequest.display];
+        data.displayRequests = std::move(displayRequest);
+    }
+
+    void parseSetPresentFence(PresentFence&& presentFence) {
+        auto& data = mReturnData[presentFence.display];
+        data.presentFence = std::move(presentFence.fence);
+    }
+
+    void parseSetReleaseFences(ReleaseFences&& releaseFences) {
+        auto& data = mReturnData[releaseFences.display];
+        data.releasedLayers = std::move(releaseFences.layers);
+    }
+
+    void parseSetPresentOrValidateDisplayResult(const PresentOrValidate&& presentOrValidate) {
+        auto& data = mReturnData[presentOrValidate.display];
+        data.presentOrValidateState = std::move(presentOrValidate.result);
+    }
+
+    void parseSetClientTargetProperty(const ClientTargetPropertyWithNits&& clientTargetProperty) {
+        auto& data = mReturnData[clientTargetProperty.display];
+        data.clientTargetProperty = std::move(clientTargetProperty);
+    }
+
+    struct ReturnData {
+        DisplayRequest displayRequests;
+        std::vector<ChangedCompositionLayer> changedLayers;
+        ndk::ScopedFileDescriptor presentFence;
+        std::vector<ReleaseFences::Layer> releasedLayers;
+        PresentOrValidate::Result presentOrValidateState;
+
+        ClientTargetPropertyWithNits clientTargetProperty = {
+                .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN},
+                .whitePointNits = -1.f,
+        };
+    };
+
+    std::vector<CommandError> mErrors;
+    std::unordered_map<int64_t, ReturnData> mReturnData;
+};
+
+}  // namespace aidl::android::hardware::graphics::composer3
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
new file mode 100644
index 0000000..d3266e7
--- /dev/null
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/composer3/Color.h>
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayBrightness.h>
+#include <aidl/android/hardware/graphics/composer3/Luminance.h>
+#include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
+#include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
+
+#include <aidl/android/hardware/graphics/composer3/DisplayCommand.h>
+
+#include <aidl/android/hardware/graphics/common/ColorTransform.h>
+#include <aidl/android/hardware/graphics/common/FRect.h>
+#include <aidl/android/hardware/graphics/common/Rect.h>
+#include <aidl/android/hardware/graphics/common/Transform.h>
+
+#include <log/log.h>
+#include <sync/sync.h>
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+using aidl::android::hardware::graphics::common::BlendMode;
+using aidl::android::hardware::graphics::common::ColorTransform;
+using aidl::android::hardware::graphics::common::Dataspace;
+using aidl::android::hardware::graphics::common::FRect;
+using aidl::android::hardware::graphics::common::Rect;
+using aidl::android::hardware::graphics::common::Transform;
+
+using namespace aidl::android::hardware::graphics::composer3;
+
+using aidl::android::hardware::common::NativeHandle;
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+class ComposerClientWriter {
+  public:
+    static constexpr std::optional<ClockMonotonicTimestamp> kNoTimestamp = std::nullopt;
+
+    ComposerClientWriter() { reset(); }
+
+    virtual ~ComposerClientWriter() { reset(); }
+
+    void reset() {
+        mDisplayCommand.reset();
+        mLayerCommand.reset();
+        mCommands.clear();
+    }
+
+    void setColorTransform(int64_t display, const float* matrix) {
+        std::vector<float> matVec;
+        matVec.reserve(16);
+        matVec.assign(matrix, matrix + 16);
+        getDisplayCommand(display).colorTransformMatrix.emplace(std::move(matVec));
+    }
+
+    void setDisplayBrightness(int64_t display, float brightness) {
+        getDisplayCommand(display).brightness.emplace(DisplayBrightness{.brightness = brightness});
+    }
+
+    void setClientTarget(int64_t display, uint32_t slot, const native_handle_t* target,
+                         int acquireFence, Dataspace dataspace, const std::vector<Rect>& damage) {
+        ClientTarget clientTargetCommand;
+        clientTargetCommand.buffer = getBuffer(slot, target, acquireFence);
+        clientTargetCommand.dataspace = dataspace;
+        clientTargetCommand.damage.assign(damage.begin(), damage.end());
+        getDisplayCommand(display).clientTarget.emplace(std::move(clientTargetCommand));
+    }
+
+    void setOutputBuffer(int64_t display, uint32_t slot, const native_handle_t* buffer,
+                         int releaseFence) {
+        getDisplayCommand(display).virtualDisplayOutputBuffer.emplace(
+                getBuffer(slot, buffer, releaseFence));
+    }
+
+    void validateDisplay(int64_t display,
+                         std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+        auto& command = getDisplayCommand(display);
+        command.expectedPresentTime = expectedPresentTime;
+        command.validateDisplay = true;
+    }
+
+    void presentOrvalidateDisplay(int64_t display,
+                                  std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+        auto& command = getDisplayCommand(display);
+        command.expectedPresentTime = expectedPresentTime;
+        command.presentOrValidateDisplay = true;
+    }
+
+    void acceptDisplayChanges(int64_t display) {
+        getDisplayCommand(display).acceptDisplayChanges = true;
+    }
+
+    void presentDisplay(int64_t display) { getDisplayCommand(display).presentDisplay = true; }
+
+    void setLayerCursorPosition(int64_t display, int64_t layer, int32_t x, int32_t y) {
+        common::Point cursorPosition;
+        cursorPosition.x = x;
+        cursorPosition.y = y;
+        getLayerCommand(display, layer).cursorPosition.emplace(std::move(cursorPosition));
+    }
+
+    void setLayerBuffer(int64_t display, int64_t layer, uint32_t slot,
+                        const native_handle_t* buffer, int acquireFence) {
+        getLayerCommand(display, layer).buffer = getBuffer(slot, buffer, acquireFence);
+    }
+
+    void setLayerSurfaceDamage(int64_t display, int64_t layer, const std::vector<Rect>& damage) {
+        getLayerCommand(display, layer).damage.emplace(damage.begin(), damage.end());
+    }
+
+    void setLayerBlendMode(int64_t display, int64_t layer, BlendMode mode) {
+        ParcelableBlendMode parcelableBlendMode;
+        parcelableBlendMode.blendMode = mode;
+        getLayerCommand(display, layer).blendMode.emplace(std::move(parcelableBlendMode));
+    }
+
+    void setLayerColor(int64_t display, int64_t layer, Color color) {
+        getLayerCommand(display, layer).color.emplace(std::move(color));
+    }
+
+    void setLayerCompositionType(int64_t display, int64_t layer, Composition type) {
+        ParcelableComposition compositionPayload;
+        compositionPayload.composition = type;
+        getLayerCommand(display, layer).composition.emplace(std::move(compositionPayload));
+    }
+
+    void setLayerDataspace(int64_t display, int64_t layer, Dataspace dataspace) {
+        ParcelableDataspace dataspacePayload;
+        dataspacePayload.dataspace = dataspace;
+        getLayerCommand(display, layer).dataspace.emplace(std::move(dataspacePayload));
+    }
+
+    void setLayerDisplayFrame(int64_t display, int64_t layer, const Rect& frame) {
+        getLayerCommand(display, layer).displayFrame.emplace(frame);
+    }
+
+    void setLayerPlaneAlpha(int64_t display, int64_t layer, float alpha) {
+        PlaneAlpha planeAlpha;
+        planeAlpha.alpha = alpha;
+        getLayerCommand(display, layer).planeAlpha.emplace(std::move(planeAlpha));
+    }
+
+    void setLayerSidebandStream(int64_t display, int64_t layer, const native_handle_t* stream) {
+        NativeHandle handle;
+        if (stream) handle = ::android::dupToAidl(stream);
+        getLayerCommand(display, layer).sidebandStream.emplace(std::move(handle));
+    }
+
+    void setLayerSourceCrop(int64_t display, int64_t layer, const FRect& crop) {
+        getLayerCommand(display, layer).sourceCrop.emplace(crop);
+    }
+
+    void setLayerTransform(int64_t display, int64_t layer, Transform transform) {
+        ParcelableTransform transformPayload;
+        transformPayload.transform = transform;
+        getLayerCommand(display, layer).transform.emplace(std::move(transformPayload));
+    }
+
+    void setLayerVisibleRegion(int64_t display, int64_t layer, const std::vector<Rect>& visible) {
+        getLayerCommand(display, layer).visibleRegion.emplace(visible.begin(), visible.end());
+    }
+
+    void setLayerZOrder(int64_t display, int64_t layer, uint32_t z) {
+        ZOrder zorder;
+        zorder.z = z;
+        getLayerCommand(display, layer).z.emplace(std::move(zorder));
+    }
+
+    void setLayerPerFrameMetadata(int64_t display, int64_t layer,
+                                  const std::vector<PerFrameMetadata>& metadataVec) {
+        getLayerCommand(display, layer)
+                .perFrameMetadata.emplace(metadataVec.begin(), metadataVec.end());
+    }
+
+    void setLayerColorTransform(int64_t display, int64_t layer, const float* matrix) {
+        getLayerCommand(display, layer).colorTransform.emplace(matrix, matrix + 16);
+    }
+
+    void setLayerPerFrameMetadataBlobs(int64_t display, int64_t layer,
+                                       const std::vector<PerFrameMetadataBlob>& metadata) {
+        getLayerCommand(display, layer)
+                .perFrameMetadataBlob.emplace(metadata.begin(), metadata.end());
+    }
+
+    void setLayerWhitePointNits(int64_t display, int64_t layer, float whitePointNits) {
+        getLayerCommand(display, layer).whitePointNits.emplace(Luminance{.nits = whitePointNits});
+    }
+
+    void setLayerBlockingRegion(int64_t display, int64_t layer, const std::vector<Rect>& blocking) {
+        getLayerCommand(display, layer).blockingRegion.emplace(blocking.begin(), blocking.end());
+    }
+
+    const std::vector<DisplayCommand>& getPendingCommands() {
+        flushLayerCommand();
+        flushDisplayCommand();
+        return mCommands;
+    }
+
+  private:
+    std::optional<DisplayCommand> mDisplayCommand;
+    std::optional<LayerCommand> mLayerCommand;
+    std::vector<DisplayCommand> mCommands;
+
+    Buffer getBuffer(int slot, const native_handle_t* bufferHandle, int fence) {
+        Buffer bufferCommand;
+        bufferCommand.slot = slot;
+        if (bufferHandle) bufferCommand.handle.emplace(::android::dupToAidl(bufferHandle));
+        if (fence > 0) bufferCommand.fence = ::ndk::ScopedFileDescriptor(fence);
+        return bufferCommand;
+    }
+
+    void flushLayerCommand() {
+        if (mLayerCommand.has_value()) {
+            mDisplayCommand->layers.emplace_back(std::move(*mLayerCommand));
+            mLayerCommand.reset();
+        }
+    }
+
+    void flushDisplayCommand() {
+        if (mDisplayCommand.has_value()) {
+            mCommands.emplace_back(std::move(*mDisplayCommand));
+            mDisplayCommand.reset();
+        }
+    }
+
+    DisplayCommand& getDisplayCommand(int64_t display) {
+        if (!mDisplayCommand.has_value() || mDisplayCommand->display != display) {
+            flushLayerCommand();
+            flushDisplayCommand();
+            mDisplayCommand.emplace();
+            mDisplayCommand->display = display;
+        }
+        return *mDisplayCommand;
+    }
+
+    LayerCommand& getLayerCommand(int64_t display, int64_t layer) {
+        getDisplayCommand(display);
+        if (!mLayerCommand.has_value() || mLayerCommand->layer != layer) {
+            flushLayerCommand();
+            mLayerCommand.emplace();
+            mLayerCommand->layer = layer;
+        }
+        return *mLayerCommand;
+    }
+};
+
+}  // namespace aidl::android::hardware::graphics::composer3
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h
deleted file mode 100644
index d02cf9c..0000000
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-#include <vector>
-
-#include <inttypes.h>
-#include <string.h>
-
-#include <aidl/android/hardware/graphics/composer3/BlendMode.h>
-#include <aidl/android/hardware/graphics/composer3/ClientTargetProperty.h>
-#include <aidl/android/hardware/graphics/composer3/Color.h>
-#include <aidl/android/hardware/graphics/composer3/Command.h>
-#include <aidl/android/hardware/graphics/composer3/Composition.h>
-#include <aidl/android/hardware/graphics/composer3/FloatColor.h>
-#include <aidl/android/hardware/graphics/composer3/HandleIndex.h>
-#include <aidl/android/hardware/graphics/composer3/IComposer.h>
-#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
-#include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
-#include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
-
-#include <aidl/android/hardware/graphics/common/ColorTransform.h>
-#include <aidl/android/hardware/graphics/common/FRect.h>
-#include <aidl/android/hardware/graphics/common/Rect.h>
-#include <aidl/android/hardware/graphics/common/Transform.h>
-
-#include <fmq/AidlMessageQueue.h>
-#include <log/log.h>
-#include <sync/sync.h>
-
-#include <aidlcommonsupport/NativeHandle.h>
-
-using aidl::android::hardware::graphics::common::ColorTransform;
-using aidl::android::hardware::graphics::common::Dataspace;
-using aidl::android::hardware::graphics::common::FRect;
-using aidl::android::hardware::graphics::common::Rect;
-using aidl::android::hardware::graphics::common::Transform;
-
-using aidl::android::hardware::graphics::composer3::BlendMode;
-using aidl::android::hardware::graphics::composer3::ClientTargetProperty;
-using aidl::android::hardware::graphics::composer3::Color;
-using aidl::android::hardware::graphics::composer3::Command;
-using aidl::android::hardware::graphics::composer3::Composition;
-using aidl::android::hardware::graphics::composer3::FloatColor;
-using aidl::android::hardware::graphics::composer3::HandleIndex;
-using aidl::android::hardware::graphics::composer3::PerFrameMetadata;
-using aidl::android::hardware::graphics::composer3::PerFrameMetadataBlob;
-
-using aidl::android::hardware::common::NativeHandle;
-using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
-using android::AidlMessageQueue;
-using CommandQueueType = AidlMessageQueue<int32_t, SynchronizedReadWrite>;
-using aidl::android::hardware::common::fmq::MQDescriptor;
-using DescriptorType = MQDescriptor<int32_t, SynchronizedReadWrite>;
-
-namespace aidl::android::hardware::graphics::composer3 {
-
-// This class helps build a command queue.  Note that all sizes/lengths are in
-// units of uint32_t's.
-class CommandWriterBase {
-  public:
-    CommandWriterBase(uint32_t initialMaxSize) : mDataMaxSize(initialMaxSize) {
-        mData = std::make_unique<int32_t[]>(mDataMaxSize);
-        reset();
-    }
-
-    virtual ~CommandWriterBase() { reset(); }
-
-    void reset() {
-        mDataWritten = 0;
-        mCommandEnd = 0;
-
-        // handles in mDataHandles are owned by the caller
-        mDataHandles.clear();
-
-        // handles in mTemporaryHandles are owned by the writer
-        for (auto handle : mTemporaryHandles) {
-            native_handle_close(handle);
-            native_handle_delete(handle);
-        }
-        mTemporaryHandles.clear();
-    }
-
-    Command getCommand(uint32_t offset) {
-        uint32_t val = (offset < mDataWritten) ? mData[offset] : 0;
-        return static_cast<Command>(val & static_cast<uint32_t>(Command::OPCODE_MASK));
-    }
-
-    bool writeQueue(bool* outQueueChanged, int32_t* outCommandLength,
-                    std::vector<NativeHandle>* outCommandHandles) {
-        if (mDataWritten == 0) {
-            *outQueueChanged = false;
-            *outCommandLength = 0;
-            outCommandHandles->clear();
-            return true;
-        }
-
-        // After data are written to the queue, it may not be read by the
-        // remote reader when
-        //
-        //  - the writer does not send them (because of other errors)
-        //  - the hwbinder transaction fails
-        //  - the reader does not read them (because of other errors)
-        //
-        // Discard the stale data here.
-        size_t staleDataSize = mQueue ? mQueue->availableToRead() : 0;
-        if (staleDataSize > 0) {
-            ALOGW("discarding stale data from message queue");
-            CommandQueueType::MemTransaction tx;
-            if (mQueue->beginRead(staleDataSize, &tx)) {
-                mQueue->commitRead(staleDataSize);
-            }
-        }
-
-        // write data to queue, optionally resizing it
-        if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) {
-            if (!mQueue->write(mData.get(), mDataWritten)) {
-                ALOGE("failed to write commands to message queue");
-                return false;
-            }
-
-            *outQueueChanged = false;
-        } else {
-            auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize);
-            if (!newQueue->isValid() || !newQueue->write(mData.get(), mDataWritten)) {
-                ALOGE("failed to prepare a new message queue ");
-                return false;
-            }
-
-            mQueue = std::move(newQueue);
-            *outQueueChanged = true;
-        }
-
-        *outCommandLength = mDataWritten;
-        *outCommandHandles = std::move(mDataHandles);
-
-        return true;
-    }
-
-    DescriptorType getMQDescriptor() const {
-        return (mQueue) ? mQueue->dupeDesc() : DescriptorType{};
-    }
-
-    static constexpr uint16_t kSelectDisplayLength = 2;
-    void selectDisplay(int64_t display) {
-        beginCommand(Command::SELECT_DISPLAY, kSelectDisplayLength);
-        write64(display);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSelectLayerLength = 2;
-    void selectLayer(int64_t layer) {
-        beginCommand(Command::SELECT_LAYER, kSelectLayerLength);
-        write64(layer);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetErrorLength = 2;
-    void setError(uint32_t location, int32_t error) {
-        beginCommand(Command::SET_ERROR, kSetErrorLength);
-        write(location);
-        writeSigned(error);
-        endCommand();
-    }
-
-    static constexpr uint32_t kPresentOrValidateDisplayResultLength = 1;
-    void setPresentOrValidateResult(uint32_t state) {
-        beginCommand(Command::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT,
-                     kPresentOrValidateDisplayResultLength);
-        write(state);
-        endCommand();
-    }
-
-    void setChangedCompositionTypes(const std::vector<int64_t>& layers,
-                                    const std::vector<Composition>& types) {
-        size_t totalLayers = std::min(layers.size(), types.size());
-        size_t currentLayer = 0;
-
-        while (currentLayer < totalLayers) {
-            size_t count =
-                    std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
-
-            beginCommand(Command::SET_CHANGED_COMPOSITION_TYPES, count * 3);
-            for (size_t i = 0; i < count; i++) {
-                write64(layers[currentLayer + i]);
-                writeSigned(static_cast<int32_t>(types[currentLayer + i]));
-            }
-            endCommand();
-
-            currentLayer += count;
-        }
-    }
-
-    void setDisplayRequests(uint32_t displayRequestMask, const std::vector<int64_t>& layers,
-                            const std::vector<uint32_t>& layerRequestMasks) {
-        size_t totalLayers = std::min(layers.size(), layerRequestMasks.size());
-        size_t currentLayer = 0;
-
-        while (currentLayer < totalLayers) {
-            size_t count =
-                    std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength - 1) / 3);
-
-            beginCommand(Command::SET_DISPLAY_REQUESTS, 1 + count * 3);
-            write(displayRequestMask);
-            for (size_t i = 0; i < count; i++) {
-                write64(layers[currentLayer + i]);
-                write(static_cast<int32_t>(layerRequestMasks[currentLayer + i]));
-            }
-            endCommand();
-
-            currentLayer += count;
-        }
-    }
-
-    static constexpr uint16_t kSetPresentFenceLength = 1;
-    void setPresentFence(int presentFence) {
-        beginCommand(Command::SET_PRESENT_FENCE, kSetPresentFenceLength);
-        writeFence(presentFence);
-        endCommand();
-    }
-
-    void setReleaseFences(const std::vector<int64_t>& layers,
-                          const std::vector<int>& releaseFences) {
-        size_t totalLayers = std::min(layers.size(), releaseFences.size());
-        size_t currentLayer = 0;
-
-        while (currentLayer < totalLayers) {
-            size_t count =
-                    std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
-
-            beginCommand(Command::SET_RELEASE_FENCES, count * 3);
-            for (size_t i = 0; i < count; i++) {
-                write64(layers[currentLayer + i]);
-                writeFence(releaseFences[currentLayer + i]);
-            }
-            endCommand();
-
-            currentLayer += count;
-        }
-    }
-
-    static constexpr uint16_t kSetColorTransformLength = 17;
-    void setColorTransform(const float* matrix, ColorTransform hint) {
-        beginCommand(Command::SET_COLOR_TRANSFORM, kSetColorTransformLength);
-        for (int i = 0; i < 16; i++) {
-            writeFloat(matrix[i]);
-        }
-        writeSigned(static_cast<int32_t>(hint));
-        endCommand();
-    }
-
-    void setClientTarget(uint32_t slot, const native_handle_t* target, int acquireFence,
-                         Dataspace dataspace, const std::vector<Rect>& damage) {
-        setClientTargetInternal(slot, target, acquireFence, static_cast<int32_t>(dataspace),
-                                damage);
-    }
-
-    static constexpr uint16_t kSetOutputBufferLength = 3;
-    void setOutputBuffer(uint32_t slot, const native_handle_t* buffer, int releaseFence) {
-        beginCommand(Command::SET_OUTPUT_BUFFER, kSetOutputBufferLength);
-        write(slot);
-        writeHandle(buffer, true);
-        writeFence(releaseFence);
-        endCommand();
-    }
-
-    static constexpr uint16_t kValidateDisplayLength = 0;
-    void validateDisplay() {
-        beginCommand(Command::VALIDATE_DISPLAY, kValidateDisplayLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kPresentOrValidateDisplayLength = 0;
-    void presentOrvalidateDisplay() {
-        beginCommand(Command::PRESENT_OR_VALIDATE_DISPLAY, kPresentOrValidateDisplayLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kAcceptDisplayChangesLength = 0;
-    void acceptDisplayChanges() {
-        beginCommand(Command::ACCEPT_DISPLAY_CHANGES, kAcceptDisplayChangesLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kPresentDisplayLength = 0;
-    void presentDisplay() {
-        beginCommand(Command::PRESENT_DISPLAY, kPresentDisplayLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerCursorPositionLength = 2;
-    void setLayerCursorPosition(int32_t x, int32_t y) {
-        beginCommand(Command::SET_LAYER_CURSOR_POSITION, kSetLayerCursorPositionLength);
-        writeSigned(x);
-        writeSigned(y);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerBufferLength = 3;
-    void setLayerBuffer(uint32_t slot, const native_handle_t* buffer, int acquireFence) {
-        beginCommand(Command::SET_LAYER_BUFFER, kSetLayerBufferLength);
-        write(slot);
-        writeHandle(buffer, true);
-        writeFence(acquireFence);
-        endCommand();
-    }
-
-    void setLayerSurfaceDamage(const std::vector<Rect>& damage) {
-        bool doWrite = (damage.size() <= kMaxLength / 4);
-        size_t length = (doWrite) ? damage.size() * 4 : 0;
-
-        beginCommand(Command::SET_LAYER_SURFACE_DAMAGE, length);
-        // When there are too many rectangles in the damage region and doWrite
-        // is false, we write no rectangle at all which means the entire
-        // layer is damaged.
-        if (doWrite) {
-            writeRegion(damage);
-        }
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerBlendModeLength = 1;
-    void setLayerBlendMode(BlendMode mode) {
-        beginCommand(Command::SET_LAYER_BLEND_MODE, kSetLayerBlendModeLength);
-        writeSigned(static_cast<int32_t>(mode));
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerColorLength = 1;
-    void setLayerColor(Color color) {
-        beginCommand(Command::SET_LAYER_COLOR, kSetLayerColorLength);
-        writeColor(color);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerCompositionTypeLength = 1;
-    void setLayerCompositionType(Composition type) {
-        beginCommand(Command::SET_LAYER_COMPOSITION_TYPE, kSetLayerCompositionTypeLength);
-        writeSigned(static_cast<int32_t>(type));
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerDataspaceLength = 1;
-    void setLayerDataspace(Dataspace dataspace) {
-        setLayerDataspaceInternal(static_cast<int32_t>(dataspace));
-    }
-
-    static constexpr uint16_t kSetLayerDisplayFrameLength = 4;
-    void setLayerDisplayFrame(const Rect& frame) {
-        beginCommand(Command::SET_LAYER_DISPLAY_FRAME, kSetLayerDisplayFrameLength);
-        writeRect(frame);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerPlaneAlphaLength = 1;
-    void setLayerPlaneAlpha(float alpha) {
-        beginCommand(Command::SET_LAYER_PLANE_ALPHA, kSetLayerPlaneAlphaLength);
-        writeFloat(alpha);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerSidebandStreamLength = 1;
-    void setLayerSidebandStream(const native_handle_t* stream) {
-        beginCommand(Command::SET_LAYER_SIDEBAND_STREAM, kSetLayerSidebandStreamLength);
-        writeHandle(stream);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerSourceCropLength = 4;
-    void setLayerSourceCrop(const FRect& crop) {
-        beginCommand(Command::SET_LAYER_SOURCE_CROP, kSetLayerSourceCropLength);
-        writeFRect(crop);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerTransformLength = 1;
-    void setLayerTransform(Transform transform) {
-        beginCommand(Command::SET_LAYER_TRANSFORM, kSetLayerTransformLength);
-        writeSigned(static_cast<int32_t>(transform));
-        endCommand();
-    }
-
-    void setLayerVisibleRegion(const std::vector<Rect>& visible) {
-        bool doWrite = (visible.size() <= kMaxLength / 4);
-        size_t length = (doWrite) ? visible.size() * 4 : 0;
-
-        beginCommand(Command::SET_LAYER_VISIBLE_REGION, length);
-        // When there are too many rectangles in the visible region and
-        // doWrite is false, we write no rectangle at all which means the
-        // entire layer is visible.
-        if (doWrite) {
-            writeRegion(visible);
-        }
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerZOrderLength = 1;
-    void setLayerZOrder(uint32_t z) {
-        beginCommand(Command::SET_LAYER_Z_ORDER, kSetLayerZOrderLength);
-        write(z);
-        endCommand();
-    }
-
-    void setLayerPerFrameMetadata(const std::vector<PerFrameMetadata>& metadataVec) {
-        beginCommand(Command::SET_LAYER_PER_FRAME_METADATA, metadataVec.size() * 2);
-        for (const auto& metadata : metadataVec) {
-            writeSigned(static_cast<int32_t>(metadata.key));
-            writeFloat(metadata.value);
-        }
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerColorTransformLength = 16;
-    void setLayerColorTransform(const float* matrix) {
-        beginCommand(Command::SET_LAYER_COLOR_TRANSFORM, kSetLayerColorTransformLength);
-        for (int i = 0; i < 16; i++) {
-            writeFloat(matrix[i]);
-        }
-        endCommand();
-    }
-
-    void setLayerPerFrameMetadataBlobs(const std::vector<PerFrameMetadataBlob>& metadata) {
-        // in units of uint32_t's
-        size_t commandLength = 0;
-
-        if (metadata.size() > std::numeric_limits<uint32_t>::max()) {
-            LOG_FATAL("too many metadata blobs - dynamic metadata size is too large");
-            return;
-        }
-
-        // space for numElements
-        commandLength += 1;
-
-        for (auto metadataBlob : metadata) {
-            commandLength += 1;  // key of metadata blob
-            commandLength += 1;  // size information of metadata blob
-
-            // metadata content size
-            size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t);
-            commandLength += metadataSize;
-            commandLength +=
-                    (metadataBlob.blob.size() - (metadataSize * sizeof(uint32_t)) > 0) ? 1 : 0;
-        }
-
-        if (commandLength > std::numeric_limits<uint16_t>::max()) {
-            LOG_FATAL("dynamic metadata size is too large");
-            return;
-        }
-
-        // Blobs are written as:
-        // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...}
-        uint16_t length = static_cast<uint16_t>(commandLength);
-        beginCommand(Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
-        write(static_cast<uint32_t>(metadata.size()));
-        for (auto metadataBlob : metadata) {
-            writeSigned(static_cast<int32_t>(metadataBlob.key));
-            write(static_cast<uint32_t>(metadataBlob.blob.size()));
-            writeBlob(static_cast<uint32_t>(metadataBlob.blob.size()), metadataBlob.blob.data());
-        }
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerFloatColorLength = 4;
-    void setLayerFloatColor(FloatColor color) {
-        beginCommand(Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength);
-        writeFloatColor(color);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetClientTargetPropertyLength = 2;
-    void setClientTargetProperty(const ClientTargetProperty& clientTargetProperty) {
-        beginCommand(Command::SET_CLIENT_TARGET_PROPERTY, kSetClientTargetPropertyLength);
-        writeSigned(static_cast<int32_t>(clientTargetProperty.pixelFormat));
-        writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
-        endCommand();
-    }
-
-    void setLayerGenericMetadata(const std::string& key, const bool mandatory,
-                                 const std::vector<uint8_t>& value) {
-        const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
-        if (commandSize > std::numeric_limits<uint16_t>::max()) {
-            LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
-            return;
-        }
-
-        beginCommand(Command::SET_LAYER_GENERIC_METADATA, static_cast<uint16_t>(commandSize));
-        write(key.size());
-        writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
-        write(mandatory);
-        write(value.size());
-        writeBlob(value.size(), value.data());
-        endCommand();
-    }
-
-  protected:
-    template <typename T>
-    void beginCommand(T command, uint16_t length) {
-        beginCommandBase(static_cast<Command>(command), length);
-    }
-
-    void setClientTargetInternal(uint32_t slot, const native_handle_t* target, int acquireFence,
-                                 int32_t dataspace, const std::vector<Rect>& damage) {
-        bool doWrite = (damage.size() <= (kMaxLength - 4) / 4);
-        size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0);
-
-        beginCommand(Command::SET_CLIENT_TARGET, length);
-        write(slot);
-        writeHandle(target, true);
-        writeFence(acquireFence);
-        writeSigned(dataspace);
-        // When there are too many rectangles in the damage region and doWrite
-        // is false, we write no rectangle at all which means the entire
-        // client target is damaged.
-        if (doWrite) {
-            writeRegion(damage);
-        }
-        endCommand();
-    }
-
-    void setLayerDataspaceInternal(int32_t dataspace) {
-        beginCommand(Command::SET_LAYER_DATASPACE, kSetLayerDataspaceLength);
-        writeSigned(dataspace);
-        endCommand();
-    }
-
-    void beginCommandBase(Command command, uint16_t length) {
-        if (mCommandEnd) {
-            LOG_FATAL("endCommand was not called before command 0x%x", command);
-        }
-
-        growData(1 + length);
-        write(static_cast<uint32_t>(command) | length);
-
-        mCommandEnd = mDataWritten + length;
-    }
-
-    void endCommand() {
-        if (!mCommandEnd) {
-            LOG_FATAL("beginCommand was not called");
-        } else if (mDataWritten > mCommandEnd) {
-            LOG_FATAL("too much data written");
-            mDataWritten = mCommandEnd;
-        } else if (mDataWritten < mCommandEnd) {
-            LOG_FATAL("too little data written");
-            while (mDataWritten < mCommandEnd) {
-                write(0);
-            }
-        }
-
-        mCommandEnd = 0;
-    }
-
-    void write(uint32_t val) { mData[mDataWritten++] = val; }
-
-    void writeSigned(int32_t val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
-
-    void writeFloat(float val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
-
-    void write64(uint64_t val) {
-        uint32_t lo = static_cast<uint32_t>(val & 0xffffffff);
-        uint32_t hi = static_cast<uint32_t>(val >> 32);
-        write(lo);
-        write(hi);
-    }
-
-    void writeRect(const Rect& rect) {
-        writeSigned(rect.left);
-        writeSigned(rect.top);
-        writeSigned(rect.right);
-        writeSigned(rect.bottom);
-    }
-
-    void writeRegion(const std::vector<Rect>& region) {
-        for (const auto& rect : region) {
-            writeRect(rect);
-        }
-    }
-
-    void writeFRect(const FRect& rect) {
-        writeFloat(rect.left);
-        writeFloat(rect.top);
-        writeFloat(rect.right);
-        writeFloat(rect.bottom);
-    }
-
-    void writeColor(const Color& color) {
-        write((color.r << 0) | (color.g << 8) | (color.b << 16) | (color.a << 24));
-    }
-
-    void writeFloatColor(const FloatColor& color) {
-        writeFloat(color.r);
-        writeFloat(color.g);
-        writeFloat(color.b);
-        writeFloat(color.a);
-    }
-
-    void writeBlob(uint32_t length, const unsigned char* blob) {
-        memcpy(&mData[mDataWritten], blob, length);
-        uint32_t numElements = length / 4;
-        mDataWritten += numElements;
-        mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0;
-    }
-
-    // ownership of handle is not transferred
-    void writeHandle(const native_handle_t* handle, bool useCache) {
-        if (!handle) {
-            writeSigned(
-                    static_cast<int32_t>((useCache) ? HandleIndex::CACHED : HandleIndex::EMPTY));
-            return;
-        }
-
-        mDataHandles.push_back(::android::dupToAidl(handle));
-        writeSigned(mDataHandles.size() - 1);
-    }
-
-    void writeHandle(const native_handle_t* handle) { writeHandle(handle, false); }
-
-    // ownership of fence is transferred
-    void writeFence(int fence) {
-        native_handle_t* handle = nullptr;
-        if (fence >= 0) {
-            handle = getTemporaryHandle(1, 0);
-            if (handle) {
-                handle->data[0] = fence;
-            } else {
-                ALOGW("failed to get temporary handle for fence %d", fence);
-                sync_wait(fence, -1);
-                close(fence);
-            }
-        }
-
-        writeHandle(handle);
-    }
-
-    native_handle_t* getTemporaryHandle(int numFds, int numInts) {
-        native_handle_t* handle = native_handle_create(numFds, numInts);
-        if (handle) {
-            mTemporaryHandles.push_back(handle);
-        }
-        return handle;
-    }
-
-    static constexpr uint16_t kMaxLength = std::numeric_limits<uint16_t>::max();
-
-    std::unique_ptr<int32_t[]> mData;
-    uint32_t mDataWritten;
-
-  private:
-    void growData(uint32_t grow) {
-        uint32_t newWritten = mDataWritten + grow;
-        if (newWritten < mDataWritten) {
-            LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32 ", growing by %" PRIu32,
-                             mDataWritten, grow);
-        }
-
-        if (newWritten <= mDataMaxSize) {
-            return;
-        }
-
-        uint32_t newMaxSize = mDataMaxSize << 1;
-        if (newMaxSize < newWritten) {
-            newMaxSize = newWritten;
-        }
-
-        auto newData = std::make_unique<int32_t[]>(newMaxSize);
-        std::copy_n(mData.get(), mDataWritten, newData.get());
-        mDataMaxSize = newMaxSize;
-        mData = std::move(newData);
-    }
-
-    uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
-
-    uint32_t mDataMaxSize;
-    // end offset of the current command
-    uint32_t mCommandEnd;
-
-    std::vector<NativeHandle> mDataHandles;
-    std::vector<native_handle_t*> mTemporaryHandles;
-
-    std::unique_ptr<CommandQueueType> mQueue;
-};
-
-// This class helps parse a command queue.  Note that all sizes/lengths are in
-// units of uint32_t's.
-class CommandReaderBase {
-  public:
-    CommandReaderBase() : mDataMaxSize(0) { reset(); }
-
-    bool setMQDescriptor(const DescriptorType& descriptor) {
-        mQueue = std::make_unique<CommandQueueType>(descriptor, false);
-        if (mQueue->isValid()) {
-            return true;
-        } else {
-            mQueue = nullptr;
-            return false;
-        }
-    }
-
-    bool readQueue(int32_t commandLength, std::vector<NativeHandle> commandHandles) {
-        if (!mQueue) {
-            return false;
-        }
-
-        auto quantumCount = mQueue->getQuantumCount();
-        if (mDataMaxSize < quantumCount) {
-            mDataMaxSize = quantumCount;
-            mData = std::make_unique<int32_t[]>(mDataMaxSize);
-        }
-
-        if (commandLength > mDataMaxSize || !mQueue->read(mData.get(), commandLength)) {
-            ALOGE("failed to read commands from message queue");
-            return false;
-        }
-
-        mDataSize = commandLength;
-        mDataRead = 0;
-        mCommandBegin = 0;
-        mCommandEnd = 0;
-        mDataHandles = std::move(commandHandles);
-        return true;
-    }
-
-    void reset() {
-        mDataSize = 0;
-        mDataRead = 0;
-        mCommandBegin = 0;
-        mCommandEnd = 0;
-        mDataHandles.clear();
-    }
-
-  protected:
-    template <typename T>
-    bool beginCommand(T* outCommand, uint16_t* outLength) {
-        return beginCommandBase(reinterpret_cast<Command*>(outCommand), outLength);
-    }
-
-    bool isEmpty() const { return (mDataRead >= mDataSize); }
-
-    bool beginCommandBase(Command* outCommand, uint16_t* outLength) {
-        if (mCommandEnd) {
-            LOG_FATAL("endCommand was not called for last command");
-        }
-
-        constexpr uint32_t opcode_mask = static_cast<uint32_t>(Command::OPCODE_MASK);
-        constexpr uint32_t length_mask = static_cast<uint32_t>(Command::LENGTH_MASK);
-
-        uint32_t val = read();
-        *outCommand = static_cast<Command>(val & opcode_mask);
-        *outLength = static_cast<uint16_t>(val & length_mask);
-
-        if (mDataRead + *outLength > mDataSize) {
-            ALOGE("command 0x%x has invalid command length %" PRIu16, *outCommand, *outLength);
-            // undo the read() above
-            mDataRead--;
-            return false;
-        }
-
-        mCommandEnd = mDataRead + *outLength;
-
-        return true;
-    }
-
-    void endCommand() {
-        if (!mCommandEnd) {
-            LOG_FATAL("beginCommand was not called");
-        } else if (mDataRead > mCommandEnd) {
-            LOG_FATAL("too much data read");
-            mDataRead = mCommandEnd;
-        } else if (mDataRead < mCommandEnd) {
-            LOG_FATAL("too little data read");
-            mDataRead = mCommandEnd;
-        }
-
-        mCommandBegin = mCommandEnd;
-        mCommandEnd = 0;
-    }
-
-    uint32_t getCommandLoc() const { return mCommandBegin; }
-
-    uint32_t read() { return mData[mDataRead++]; }
-
-    int32_t readSigned() {
-        int32_t val;
-        memcpy(&val, &mData[mDataRead++], sizeof(val));
-        return val;
-    }
-
-    float readFloat() {
-        float val;
-        memcpy(&val, &mData[mDataRead++], sizeof(val));
-        return val;
-    }
-
-    uint64_t read64() {
-        uint32_t lo = read();
-        uint32_t hi = read();
-        return (static_cast<uint64_t>(hi) << 32) | lo;
-    }
-
-    Color readColor() {
-        uint32_t val = read();
-        return Color{
-                static_cast<int8_t>((val >> 0) & 0xff),
-                static_cast<int8_t>((val >> 8) & 0xff),
-                static_cast<int8_t>((val >> 16) & 0xff),
-                static_cast<int8_t>((val >> 24) & 0xff),
-        };
-    }
-
-    // ownership of handle is not transferred
-    const native_handle_t* readHandle(bool* outUseCache) {
-        const native_handle_t* handle = nullptr;
-
-        int32_t index = readSigned();
-        switch (index) {
-            case static_cast<int32_t>(HandleIndex::EMPTY):
-                *outUseCache = false;
-                break;
-            case static_cast<int32_t>(HandleIndex::CACHED):
-                *outUseCache = true;
-                break;
-            default:
-                if (static_cast<size_t>(index) < mDataHandles.size()) {
-                    handle = ::android::makeFromAidl(mDataHandles[index]);
-                } else {
-                    ALOGE("invalid handle index %zu", static_cast<size_t>(index));
-                }
-                *outUseCache = false;
-                break;
-        }
-
-        return handle;
-    }
-
-    const native_handle_t* readHandle() {
-        bool useCache;
-        return readHandle(&useCache);
-    }
-
-    // ownership of fence is transferred
-    int readFence() {
-        auto handle = readHandle();
-        if (!handle || handle->numFds == 0) {
-            return -1;
-        }
-
-        if (handle->numFds != 1) {
-            ALOGE("invalid fence handle with %d fds", handle->numFds);
-            return -1;
-        }
-
-        int fd = dup(handle->data[0]);
-        if (fd < 0) {
-            ALOGW("failed to dup fence %d", handle->data[0]);
-            sync_wait(handle->data[0], -1);
-            fd = -1;
-        }
-
-        return fd;
-    }
-
-    std::unique_ptr<int32_t[]> mData;
-    uint32_t mDataRead;
-
-  private:
-    std::unique_ptr<CommandQueueType> mQueue;
-    uint32_t mDataMaxSize;
-
-    uint32_t mDataSize;
-
-    // begin/end offsets of the current command
-    uint32_t mCommandBegin;
-    uint32_t mCommandEnd;
-
-    std::vector<NativeHandle> mDataHandles;
-};
-
-}  // namespace aidl::android::hardware::graphics::composer3
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/translate-ndk.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/translate-ndk.h
deleted file mode 100644
index c892863..0000000
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/translate-ndk.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <limits>
-#include "aidl/android/hardware/graphics/common/FRect.h"
-#include "aidl/android/hardware/graphics/common/Rect.h"
-#include "aidl/android/hardware/graphics/composer3/BlendMode.h"
-#include "aidl/android/hardware/graphics/composer3/Capability.h"
-#include "aidl/android/hardware/graphics/composer3/ClientTargetProperty.h"
-#include "aidl/android/hardware/graphics/composer3/Color.h"
-#include "aidl/android/hardware/graphics/composer3/Command.h"
-#include "aidl/android/hardware/graphics/composer3/Composition.h"
-#include "aidl/android/hardware/graphics/composer3/ContentType.h"
-#include "aidl/android/hardware/graphics/composer3/DisplayAttribute.h"
-#include "aidl/android/hardware/graphics/composer3/DisplayCapability.h"
-#include "aidl/android/hardware/graphics/composer3/DisplayConnectionType.h"
-#include "aidl/android/hardware/graphics/composer3/DisplayRequest.h"
-#include "aidl/android/hardware/graphics/composer3/FloatColor.h"
-#include "aidl/android/hardware/graphics/composer3/FormatColorComponent.h"
-#include "aidl/android/hardware/graphics/composer3/HandleIndex.h"
-#include "aidl/android/hardware/graphics/composer3/IComposer.h"
-#include "aidl/android/hardware/graphics/composer3/LayerGenericMetadataKey.h"
-#include "aidl/android/hardware/graphics/composer3/LayerRequest.h"
-#include "aidl/android/hardware/graphics/composer3/PerFrameMetadata.h"
-#include "aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h"
-#include "aidl/android/hardware/graphics/composer3/PerFrameMetadataKey.h"
-#include "aidl/android/hardware/graphics/composer3/PowerMode.h"
-#include "aidl/android/hardware/graphics/composer3/VsyncPeriodChangeConstraints.h"
-#include "aidl/android/hardware/graphics/composer3/VsyncPeriodChangeTimeline.h"
-#include "android/hardware/graphics/composer/2.1/IComposer.h"
-#include "android/hardware/graphics/composer/2.1/IComposerCallback.h"
-#include "android/hardware/graphics/composer/2.1/IComposerClient.h"
-#include "android/hardware/graphics/composer/2.2/IComposerClient.h"
-#include "android/hardware/graphics/composer/2.3/IComposerClient.h"
-#include "android/hardware/graphics/composer/2.4/IComposerClient.h"
-#include "android/hardware/graphics/composer/2.4/types.h"
-
-namespace android::h2a {
-
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::VsyncPeriodChangeTimeline& in,
-        aidl::android::hardware::graphics::composer3::VsyncPeriodChangeTimeline* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_1::IComposerClient::Rect& in,
-        aidl::android::hardware::graphics::common::Rect* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_1::IComposerClient::FRect& in,
-        aidl::android::hardware::graphics::common::FRect* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_1::IComposerClient::Color& in,
-        aidl::android::hardware::graphics::composer3::Color* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_3::IComposerClient::PerFrameMetadata& in,
-        aidl::android::hardware::graphics::composer3::PerFrameMetadata* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_2::IComposerClient::FloatColor& in,
-        aidl::android::hardware::graphics::composer3::FloatColor* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_3::IComposerClient::PerFrameMetadataBlob&
-                in,
-        aidl::android::hardware::graphics::composer3::PerFrameMetadataBlob* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                VsyncPeriodChangeConstraints& in,
-        aidl::android::hardware::graphics::composer3::VsyncPeriodChangeConstraints* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::IComposerClient::ClientTargetProperty&
-                in,
-        aidl::android::hardware::graphics::composer3::ClientTargetProperty* out);
-__attribute__((warn_unused_result)) bool translate(
-        const ::android::hardware::graphics::composer::V2_4::IComposerClient::
-                LayerGenericMetadataKey& in,
-        aidl::android::hardware::graphics::composer3::LayerGenericMetadataKey* out);
-
-}  // namespace android::h2a
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 2ab9c01..5e012f6 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -21,6 +21,7 @@
 #include <thread>
 #include <vector>
 
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
 
 #include <android-base/logging.h>
@@ -92,7 +93,13 @@
         ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));
 
         hidl_vec<uint8_t> vec;
-        ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));
+        const auto result = mGralloc->get(bufferHandle, metadataType, &vec);
+
+        if (metadataType == gralloc4::MetadataType_Smpte2094_10 && result == Error::UNSUPPORTED) {
+            GTEST_SKIP() << "getting metadata for Smpte2094-10 is unsupported";
+        }
+
+        ASSERT_EQ(Error::NONE, result);
 
         ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
     }
@@ -1205,6 +1212,40 @@
 }
 
 /**
+ * Test IMapper::isSupported with optional format R_8
+ */
+TEST_P(GraphicsMapperHidlTest, IsSupportedR8) {
+    auto info = mDummyDescriptorInfo;
+    info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(
+            aidl::android::hardware::graphics::common::PixelFormat::R_8);
+    bool supported = false;
+
+    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+
+    if (!supported) {
+        GTEST_SUCCEED() << "R_8 is optional; unsupported so skipping allocation test";
+        return;
+    }
+
+    BufferDescriptor descriptor;
+    ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));
+
+    constexpr uint32_t count = 1;
+    std::vector<const native_handle_t*> bufferHandles;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandles =
+                                    mGralloc->allocate(descriptor, count, false,
+                                                       Tolerance::kToleranceStrict, &stride));
+
+    EXPECT_LE(info.width, stride) << "invalid buffer stride";
+    EXPECT_EQ(1u, bufferHandles.size());
+
+    for (auto bufferHandle : bufferHandles) {
+        mGralloc->freeBuffer(bufferHandle);
+    }
+}
+
+/**
  * Test IMapper::get(BufferId)
  */
 TEST_P(GraphicsMapperHidlTest, GetBufferId) {
diff --git a/health/2.1/vts/OWNERS b/health/2.1/vts/OWNERS
index 20450ba..a6803cd 100644
--- a/health/2.1/vts/OWNERS
+++ b/health/2.1/vts/OWNERS
@@ -1,3 +1,2 @@
 elsk@google.com
-hridya@google.com
 sspatil@google.com
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index fae7592..86bca69 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -25,6 +25,7 @@
     name: "android.hardware.health",
     vendor_available: true,
     recovery_available: true,
+    host_supported: true,
     srcs: ["android/hardware/health/*.aidl"],
     stability: "vintf",
     backend: {
@@ -36,7 +37,6 @@
             sdk_version: "module_current",
         },
         ndk: {
-            separate_platform_variant: false,
             vndk: {
                 enabled: true,
             },
@@ -48,6 +48,7 @@
     name: "android.hardware.health-translate-ndk",
     vendor_available: true,
     recovery_available: true,
+    host_supported: true,
     srcs: ["android/hardware/health/translate-ndk.cpp"],
     shared_libs: [
         "libbinder_ndk",
@@ -61,6 +62,11 @@
         "android.hardware.health@2.0",
         "android.hardware.health@2.1",
     ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 java_library {
diff --git a/health/aidl/README.md b/health/aidl/README.md
index 0d7c4c9..a64fe93 100644
--- a/health/aidl/README.md
+++ b/health/aidl/README.md
@@ -63,8 +63,7 @@
 * You may ignore the `service` line. The name of the service does not matter.
 * If your service belongs to additional classes beside `charger`, you need a
   custom health AIDL service.
-* You may ignore the `seclabel` line. When the health AIDL service runs in
-  charger mode, its original SELinux domain is kept.
+* Modify the `seclabel` line. Replace `charger` with `charger_vendor`.
 * If your service has a different `user` (not `system`), you need a custom
   health AIDL service.
 * If your service belongs to additional `group`s beside
@@ -240,6 +239,8 @@
 
 ```text
 service vendor.charger-tuna /vendor/bin/hw/android.hardware.health-service-tuna --charger
+    class charger
+    seclabel u:r:charger_vendor:s0
     # ...
 ```
 
@@ -315,6 +316,5 @@
 `hal_health_tuna`:
 
 ```text
-type hal_health_tuna, charger_type, domain;
-hal_server_domain(hal_health_default, hal_health)
+domain_trans(init, hal_health_tuna_exec, charger_vendor)
 ```
diff --git a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/HealthInfo.aidl b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/HealthInfo.aidl
index 34a87a6..97d9e84 100644
--- a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/HealthInfo.aidl
+++ b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/HealthInfo.aidl
@@ -37,6 +37,7 @@
   boolean chargerAcOnline;
   boolean chargerUsbOnline;
   boolean chargerWirelessOnline;
+  boolean chargerDockOnline;
   int maxChargingCurrentMicroamps;
   int maxChargingVoltageMicrovolts;
   android.hardware.health.BatteryStatus batteryStatus;
diff --git a/health/aidl/android/hardware/health/HealthInfo.aidl b/health/aidl/android/hardware/health/HealthInfo.aidl
index 504e218..5b98baf 100644
--- a/health/aidl/android/hardware/health/HealthInfo.aidl
+++ b/health/aidl/android/hardware/health/HealthInfo.aidl
@@ -40,6 +40,10 @@
      */
     boolean chargerWirelessOnline;
     /**
+     * Dock charger state - 'true' if online
+     */
+    boolean chargerDockOnline;
+    /**
      * Maximum charging current supported by charger in µA
      */
     int maxChargingCurrentMicroamps;
diff --git a/health/aidl/android/hardware/health/translate-ndk.cpp b/health/aidl/android/hardware/health/translate-ndk.cpp
index 7fe6ced..78880cc 100644
--- a/health/aidl/android/hardware/health/translate-ndk.cpp
+++ b/health/aidl/android/hardware/health/translate-ndk.cpp
@@ -106,36 +106,41 @@
 }
 
 __attribute__((warn_unused_result)) bool translate(
+        const ::android::hardware::health::V2_0::HealthInfo& in,
+        aidl::android::hardware::health::HealthInfo* out) {
+    out->chargerAcOnline = static_cast<bool>(in.legacy.chargerAcOnline);
+    out->chargerUsbOnline = static_cast<bool>(in.legacy.chargerUsbOnline);
+    out->chargerWirelessOnline = static_cast<bool>(in.legacy.chargerWirelessOnline);
+    out->maxChargingCurrentMicroamps = static_cast<int32_t>(in.legacy.maxChargingCurrent);
+    out->maxChargingVoltageMicrovolts = static_cast<int32_t>(in.legacy.maxChargingVoltage);
+    out->batteryStatus =
+            static_cast<aidl::android::hardware::health::BatteryStatus>(in.legacy.batteryStatus);
+    out->batteryHealth =
+            static_cast<aidl::android::hardware::health::BatteryHealth>(in.legacy.batteryHealth);
+    out->batteryPresent = static_cast<bool>(in.legacy.batteryPresent);
+    out->batteryLevel = static_cast<int32_t>(in.legacy.batteryLevel);
+    out->batteryVoltageMillivolts = static_cast<int32_t>(in.legacy.batteryVoltage);
+    out->batteryTemperatureTenthsCelsius = static_cast<int32_t>(in.legacy.batteryTemperature);
+    out->batteryCurrentMicroamps = static_cast<int32_t>(in.legacy.batteryCurrent);
+    out->batteryCycleCount = static_cast<int32_t>(in.legacy.batteryCycleCount);
+    out->batteryFullChargeUah = static_cast<int32_t>(in.legacy.batteryFullCharge);
+    out->batteryChargeCounterUah = static_cast<int32_t>(in.legacy.batteryChargeCounter);
+    out->batteryTechnology = in.legacy.batteryTechnology;
+    out->batteryCurrentAverageMicroamps = static_cast<int32_t>(in.batteryCurrentAverage);
+    out->diskStats.clear();
+    out->diskStats.resize(in.diskStats.size());
+    for (size_t i = 0; i < in.diskStats.size(); ++i)
+        if (!translate(in.diskStats[i], &out->diskStats[i])) return false;
+    out->storageInfos.clear();
+    out->storageInfos.resize(in.storageInfos.size());
+    for (size_t i = 0; i < in.storageInfos.size(); ++i)
+        if (!translate(in.storageInfos[i], &out->storageInfos[i])) return false;
+    return true;
+}
+__attribute__((warn_unused_result)) bool translate(
         const ::android::hardware::health::V2_1::HealthInfo& in,
         aidl::android::hardware::health::HealthInfo* out) {
-    out->chargerAcOnline = static_cast<bool>(in.legacy.legacy.chargerAcOnline);
-    out->chargerUsbOnline = static_cast<bool>(in.legacy.legacy.chargerUsbOnline);
-    out->chargerWirelessOnline = static_cast<bool>(in.legacy.legacy.chargerWirelessOnline);
-    out->maxChargingCurrentMicroamps = static_cast<int32_t>(in.legacy.legacy.maxChargingCurrent);
-    out->maxChargingVoltageMicrovolts = static_cast<int32_t>(in.legacy.legacy.maxChargingVoltage);
-    out->batteryStatus = static_cast<aidl::android::hardware::health::BatteryStatus>(
-            in.legacy.legacy.batteryStatus);
-    out->batteryHealth = static_cast<aidl::android::hardware::health::BatteryHealth>(
-            in.legacy.legacy.batteryHealth);
-    out->batteryPresent = static_cast<bool>(in.legacy.legacy.batteryPresent);
-    out->batteryLevel = static_cast<int32_t>(in.legacy.legacy.batteryLevel);
-    out->batteryVoltageMillivolts = static_cast<int32_t>(in.legacy.legacy.batteryVoltage);
-    out->batteryTemperatureTenthsCelsius =
-            static_cast<int32_t>(in.legacy.legacy.batteryTemperature);
-    out->batteryCurrentMicroamps = static_cast<int32_t>(in.legacy.legacy.batteryCurrent);
-    out->batteryCycleCount = static_cast<int32_t>(in.legacy.legacy.batteryCycleCount);
-    out->batteryFullChargeUah = static_cast<int32_t>(in.legacy.legacy.batteryFullCharge);
-    out->batteryChargeCounterUah = static_cast<int32_t>(in.legacy.legacy.batteryChargeCounter);
-    out->batteryTechnology = in.legacy.legacy.batteryTechnology;
-    out->batteryCurrentAverageMicroamps = static_cast<int32_t>(in.legacy.batteryCurrentAverage);
-    out->diskStats.clear();
-    out->diskStats.resize(in.legacy.diskStats.size());
-    for (size_t i = 0; i < in.legacy.diskStats.size(); ++i)
-        if (!translate(in.legacy.diskStats[i], &out->diskStats[i])) return false;
-    out->storageInfos.clear();
-    out->storageInfos.resize(in.legacy.storageInfos.size());
-    for (size_t i = 0; i < in.legacy.storageInfos.size(); ++i)
-        if (!translate(in.legacy.storageInfos[i], &out->storageInfos[i])) return false;
+    if (!translate(in.legacy, out)) return false;
     out->batteryCapacityLevel = static_cast<aidl::android::hardware::health::BatteryCapacityLevel>(
             in.batteryCapacityLevel);
     out->batteryChargeTimeToFullNowSeconds =
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index 8aa7638..8eab997 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -120,6 +120,15 @@
     },
 }
 
+// Users of libhealth_aidl_impl should use this defaults.
+cc_defaults {
+    name: "libhealth_aidl_impl_user",
+    defaults: [
+        "libhealth_aidl_common_defaults",
+        "libhealth_aidl_charger_defaults",
+    ],
+}
+
 // AIDL version of android.hardware.health@2.1-service.
 // Default binder service of the health HAL.
 cc_defaults {
@@ -127,8 +136,7 @@
     relative_install_path: "hw",
     vintf_fragments: ["android.hardware.health-service.example.xml"],
     defaults: [
-        "libhealth_aidl_common_defaults",
-        "libhealth_aidl_charger_defaults",
+        "libhealth_aidl_impl_user",
     ],
     static_libs: [
         "libhealth_aidl_impl",
diff --git a/health/aidl/default/HalHealthLoop.cpp b/health/aidl/default/HalHealthLoop.cpp
index c9a081e..ec23c10 100644
--- a/health/aidl/default/HalHealthLoop.cpp
+++ b/health/aidl/default/HalHealthLoop.cpp
@@ -61,7 +61,7 @@
 
 void HalHealthLoop::set_charger_online(const HealthInfo& health_info) {
     charger_online_ = health_info.chargerAcOnline || health_info.chargerUsbOnline ||
-                      health_info.chargerWirelessOnline;
+                      health_info.chargerWirelessOnline || health_info.chargerDockOnline;
 }
 
 }  // namespace aidl::android::hardware::health
diff --git a/health/aidl/default/android.hardware.health-service.example.rc b/health/aidl/default/android.hardware.health-service.example.rc
index dee3d11..4258890 100644
--- a/health/aidl/default/android.hardware.health-service.example.rc
+++ b/health/aidl/default/android.hardware.health-service.example.rc
@@ -7,6 +7,7 @@
 
 service vendor.charger-default /vendor/bin/hw/android.hardware.health-service.example --charger
     class charger
+    seclabel u:r:charger_vendor:s0
     user system
     group system wakelock input
     capabilities SYS_BOOT
diff --git a/health/aidl/default/health-convert.cpp b/health/aidl/default/health-convert.cpp
index b5251f4..6118865 100644
--- a/health/aidl/default/health-convert.cpp
+++ b/health/aidl/default/health-convert.cpp
@@ -22,6 +22,7 @@
     p->chargerAcOnline = info.chargerAcOnline;
     p->chargerUsbOnline = info.chargerUsbOnline;
     p->chargerWirelessOnline = info.chargerWirelessOnline;
+    p->chargerDockOnline = info.chargerDockOnline;
     p->maxChargingCurrent = info.maxChargingCurrentMicroamps;
     p->maxChargingVoltage = info.maxChargingVoltageMicrovolts;
     p->batteryStatus = static_cast<int>(info.batteryStatus);
diff --git a/health/aidl/include/android/hardware/health/translate-ndk.h b/health/aidl/include/android/hardware/health/translate-ndk.h
index 2f8fe04..91add42 100644
--- a/health/aidl/include/android/hardware/health/translate-ndk.h
+++ b/health/aidl/include/android/hardware/health/translate-ndk.h
@@ -33,6 +33,9 @@
         const ::android::hardware::health::V2_0::DiskStats& in,
         aidl::android::hardware::health::DiskStats* out);
 __attribute__((warn_unused_result)) bool translate(
+        const ::android::hardware::health::V2_0::HealthInfo& in,
+        aidl::android::hardware::health::HealthInfo* out);
+__attribute__((warn_unused_result)) bool translate(
         const ::android::hardware::health::V2_1::HealthInfo& in,
         aidl::android::hardware::health::HealthInfo* out);
 
diff --git a/health/aidl/vts/functional/Android.bp b/health/aidl/vts/functional/Android.bp
index 434f565..d315c60 100644
--- a/health/aidl/vts/functional/Android.bp
+++ b/health/aidl/vts/functional/Android.bp
@@ -43,6 +43,7 @@
         "libhealthtest_headers",
     ],
     test_suites: [
+        "general-tests",
         "vts",
     ],
 }
diff --git a/health/utils/libhealthshim/Android.bp b/health/utils/libhealthshim/Android.bp
new file mode 100644
index 0000000..42e4ea7
--- /dev/null
+++ b/health/utils/libhealthshim/Android.bp
@@ -0,0 +1,80 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+    name: "libhealthshim_defaults",
+    host_supported: true, // for testing
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "android.hardware.health-V1-ndk",
+        "android.hardware.health-translate-ndk",
+        "android.hardware.health@1.0",
+        "android.hardware.health@2.0",
+    ],
+    shared_libs: [
+        // These can be expected from the device or from host.
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
+
+// Shim library that wraps a HIDL IHealth object into an AIDL IHealth object.
+cc_library_static {
+    name: "libhealthshim",
+    defaults: ["libhealthshim_defaults"],
+    recovery_available: true,
+    srcs: [
+        "shim.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_test {
+    name: "libhealthshim_test",
+    defaults: ["libhealthshim_defaults"],
+    static_libs: [
+        "libhealthshim",
+        "libgmock",
+    ],
+    srcs: [
+        "test.cpp",
+    ],
+    test_suites: ["general-tests"],
+    test_options: {
+        unit_test: true,
+    },
+}
diff --git a/health/utils/libhealthshim/include/health-shim/shim.h b/health/utils/libhealthshim/include/health-shim/shim.h
new file mode 100644
index 0000000..f36fa5d
--- /dev/null
+++ b/health/utils/libhealthshim/include/health-shim/shim.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <map>
+
+#include <aidl/android/hardware/health/BnHealth.h>
+#include <android/hardware/health/2.0/IHealth.h>
+
+namespace aidl::android::hardware::health {
+
+// Shim that wraps HIDL IHealth with an AIDL BnHealth.
+// The wrapper always have isRemote() == false because it is BnHealth.
+class HealthShim : public BnHealth {
+    using HidlHealth = ::android::hardware::health::V2_0::IHealth;
+    using HidlHealthInfoCallback = ::android::hardware::health::V2_0::IHealthInfoCallback;
+
+  public:
+    explicit HealthShim(const ::android::sp<HidlHealth>& service);
+
+    ndk::ScopedAStatus registerCallback(
+            const std::shared_ptr<IHealthInfoCallback>& in_callback) override;
+    ndk::ScopedAStatus unregisterCallback(
+            const std::shared_ptr<IHealthInfoCallback>& in_callback) override;
+    ndk::ScopedAStatus update() override;
+    ndk::ScopedAStatus getChargeCounterUah(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getCurrentNowMicroamps(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getCurrentAverageMicroamps(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getCapacity(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getEnergyCounterNwh(int64_t* _aidl_return) override;
+    ndk::ScopedAStatus getChargeStatus(BatteryStatus* _aidl_return) override;
+    ndk::ScopedAStatus getStorageInfo(std::vector<StorageInfo>* _aidl_return) override;
+    ndk::ScopedAStatus getDiskStats(std::vector<DiskStats>* _aidl_return) override;
+    ndk::ScopedAStatus getHealthInfo(HealthInfo* _aidl_return) override;
+
+  private:
+    ::android::sp<HidlHealth> service_;
+    std::map<std::shared_ptr<IHealthInfoCallback>, ::android::sp<HidlHealthInfoCallback>>
+            callback_map_;
+};
+
+}  // namespace aidl::android::hardware::health
diff --git a/health/utils/libhealthshim/shim.cpp b/health/utils/libhealthshim/shim.cpp
new file mode 100644
index 0000000..1329679
--- /dev/null
+++ b/health/utils/libhealthshim/shim.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/health/translate-ndk.h>
+#include <health-shim/shim.h>
+
+using ::android::sp;
+using ::android::h2a::translate;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::health::V2_0::Result;
+using ::android::hardware::health::V2_0::toString;
+using ::ndk::ScopedAStatus;
+using HidlHealth = ::android::hardware::health::V2_0::IHealth;
+using HidlHealthInfoCallback = ::android::hardware::health::V2_0::IHealthInfoCallback;
+using HidlHealthInfo = ::android::hardware::health::V2_0::HealthInfo;
+
+namespace aidl::android::hardware::health {
+
+namespace {
+
+class HealthInfoCallbackShim : public HidlHealthInfoCallback {
+    using AidlHealthInfoCallback = ::aidl::android::hardware::health::IHealthInfoCallback;
+    using AidlHealthInfo = ::aidl::android::hardware::health::HealthInfo;
+
+  public:
+    explicit HealthInfoCallbackShim(const std::shared_ptr<AidlHealthInfoCallback>& impl)
+        : impl_(impl) {}
+    Return<void> healthInfoChanged(const HidlHealthInfo& info) override {
+        AidlHealthInfo aidl_info;
+        // translate() should always return true.
+        CHECK(translate(info, &aidl_info));
+        // This is a oneway function, so we can't (and shouldn't) check for errors.
+        (void)impl_->healthInfoChanged(aidl_info);
+        return Void();
+    }
+
+  private:
+    std::shared_ptr<AidlHealthInfoCallback> impl_;
+};
+
+ScopedAStatus ResultToStatus(Result result) {
+    switch (result) {
+        case Result::SUCCESS:
+            return ScopedAStatus::ok();
+        case Result::NOT_SUPPORTED:
+            return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        case Result::UNKNOWN:
+            return ScopedAStatus::fromServiceSpecificError(IHealth::STATUS_UNKNOWN);
+        case Result::NOT_FOUND:
+            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        case Result::CALLBACK_DIED:
+            return ScopedAStatus::fromServiceSpecificError(IHealth::STATUS_CALLBACK_DIED);
+    }
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            IHealth::STATUS_UNKNOWN, ("Unrecognized result value " + toString(result)).c_str());
+}
+
+template <typename T>
+ScopedAStatus ReturnAndResultToStatus(const Return<T>& ret, Result result) {
+    if (ret.isOk()) {
+        return ResultToStatus(result);
+    }
+    if (ret.isDeadObject()) {
+        return ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
+    }
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(IHealth::STATUS_UNKNOWN,
+                                                              ret.description().c_str());
+}
+
+ScopedAStatus ReturnResultToStatus(const Return<Result>& return_result) {
+    return ReturnAndResultToStatus(return_result, return_result.isOk()
+                                                          ? static_cast<Result>(return_result)
+                                                          : Result::UNKNOWN);
+}
+
+}  // namespace
+
+HealthShim::HealthShim(const sp<HidlHealth>& service) : service_(service) {}
+
+ScopedAStatus HealthShim::registerCallback(
+        const std::shared_ptr<IHealthInfoCallback>& in_callback) {
+    sp<HidlHealthInfoCallback> shim(new HealthInfoCallbackShim(in_callback));
+    callback_map_.emplace(in_callback, shim);
+    return ReturnResultToStatus(service_->registerCallback(shim));
+}
+
+ScopedAStatus HealthShim::unregisterCallback(
+        const std::shared_ptr<IHealthInfoCallback>& in_callback) {
+    auto it = callback_map_.find(in_callback);
+    if (it == callback_map_.end()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    sp<HidlHealthInfoCallback> shim = it->second;
+    callback_map_.erase(it);
+    return ReturnResultToStatus(service_->unregisterCallback(shim));
+}
+
+ScopedAStatus HealthShim::update() {
+    return ReturnResultToStatus(service_->update());
+}
+
+ScopedAStatus HealthShim::getChargeCounterUah(int32_t* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getChargeCounter([out, &out_result](auto result, auto value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        *out = value;
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getCurrentNowMicroamps(int32_t* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getCurrentNow([out, &out_result](auto result, auto value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        *out = value;
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getCurrentAverageMicroamps(int32_t* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getCurrentAverage([out, &out_result](auto result, auto value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        *out = value;
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getCapacity(int32_t* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getCapacity([out, &out_result](auto result, auto value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        *out = value;
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getEnergyCounterNwh(int64_t* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getEnergyCounter([out, &out_result](auto result, auto value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        *out = value;
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getChargeStatus(BatteryStatus* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getChargeStatus([out, &out_result](auto result, auto value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        *out = static_cast<BatteryStatus>(value);
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getStorageInfo(std::vector<StorageInfo>* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getStorageInfo([out, &out_result](auto result, const auto& value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        out->clear();
+        out->reserve(value.size());
+        for (const auto& hidl_info : value) {
+            auto& aidl_info = out->emplace_back();
+            // translate() should always return true.
+            CHECK(translate(hidl_info, &aidl_info));
+        }
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getDiskStats(std::vector<DiskStats>* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getDiskStats([out, &out_result](auto result, const auto& value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        out->clear();
+        out->reserve(value.size());
+        for (const auto& hidl_info : value) {
+            auto& aidl_info = out->emplace_back();
+            // translate() should always return true.
+            CHECK(translate(hidl_info, &aidl_info));
+        }
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+ScopedAStatus HealthShim::getHealthInfo(HealthInfo* out) {
+    Result out_result = Result::UNKNOWN;
+    auto ret = service_->getHealthInfo([out, &out_result](auto result, const auto& value) {
+        out_result = result;
+        if (out_result != Result::SUCCESS) return;
+        // translate() should always return true.
+        CHECK(translate(value, out));
+    });
+    return ReturnAndResultToStatus(ret, out_result);
+}
+
+}  // namespace aidl::android::hardware::health
diff --git a/health/utils/libhealthshim/test.cpp b/health/utils/libhealthshim/test.cpp
new file mode 100644
index 0000000..d1dfb8b
--- /dev/null
+++ b/health/utils/libhealthshim/test.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <health-shim/shim.h>
+
+#include <android/hardware/health/translate-ndk.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using HidlHealth = android::hardware::health::V2_0::IHealth;
+using HidlHealthInfoCallback = android::hardware::health::V2_0::IHealthInfoCallback;
+using HidlStorageInfo = android::hardware::health::V2_0::StorageInfo;
+using HidlDiskStats = android::hardware::health::V2_0::DiskStats;
+using HidlHealthInfo = android::hardware::health::V2_0::HealthInfo;
+using HidlBatteryStatus = android::hardware::health::V1_0::BatteryStatus;
+using android::sp;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::health::V2_0::Result;
+using ndk::SharedRefBase;
+using testing::Invoke;
+using testing::NiceMock;
+
+namespace aidl::android::hardware::health {
+MATCHER(IsOk, "") {
+    *result_listener << "status is " << arg.getDescription();
+    return arg.isOk();
+}
+
+MATCHER_P(ExceptionIs, exception_code, "") {
+    *result_listener << "status is " << arg.getDescription();
+    return arg.getExceptionCode() == exception_code;
+}
+
+class MockHidlHealth : public HidlHealth {
+  public:
+    MOCK_METHOD(Return<Result>, registerCallback, (const sp<HidlHealthInfoCallback>& callback),
+                (override));
+    MOCK_METHOD(Return<Result>, unregisterCallback, (const sp<HidlHealthInfoCallback>& callback),
+                (override));
+    MOCK_METHOD(Return<Result>, update, (), (override));
+    MOCK_METHOD(Return<void>, getChargeCounter, (getChargeCounter_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getCurrentNow, (getCurrentNow_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getCurrentAverage, (getCurrentAverage_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getCapacity, (getCapacity_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getEnergyCounter, (getEnergyCounter_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getChargeStatus, (getChargeStatus_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getStorageInfo, (getStorageInfo_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getDiskStats, (getDiskStats_cb _hidl_cb), (override));
+    MOCK_METHOD(Return<void>, getHealthInfo, (getHealthInfo_cb _hidl_cb), (override));
+};
+
+class HealthShimTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        hidl = new NiceMock<MockHidlHealth>();
+        shim = SharedRefBase::make<HealthShim>(hidl);
+    }
+    sp<MockHidlHealth> hidl;
+    std::shared_ptr<IHealth> shim;
+};
+
+#define ADD_TEST(name, aidl_name, AidlValueType, hidl_value, not_supported_hidl_value) \
+    TEST_F(HealthShimTest, name) {                                                     \
+        ON_CALL(*hidl, name).WillByDefault(Invoke([](auto cb) {                        \
+            cb(Result::SUCCESS, hidl_value);                                           \
+            return Void();                                                             \
+        }));                                                                           \
+        AidlValueType value;                                                           \
+        ASSERT_THAT(shim->aidl_name(&value), IsOk());                                  \
+        ASSERT_EQ(value, static_cast<AidlValueType>(hidl_value));                      \
+    }                                                                                  \
+                                                                                       \
+    TEST_F(HealthShimTest, name##Unsupported) {                                        \
+        ON_CALL(*hidl, name).WillByDefault(Invoke([](auto cb) {                        \
+            cb(Result::NOT_SUPPORTED, not_supported_hidl_value);                       \
+            return Void();                                                             \
+        }));                                                                           \
+        AidlValueType value;                                                           \
+        ASSERT_THAT(shim->aidl_name(&value), ExceptionIs(EX_UNSUPPORTED_OPERATION));   \
+    }
+
+ADD_TEST(getChargeCounter, getChargeCounterUah, int32_t, 0xFEEDBEEF, 0)
+ADD_TEST(getCurrentNow, getCurrentNowMicroamps, int32_t, 0xC0FFEE, 0)
+ADD_TEST(getCurrentAverage, getCurrentAverageMicroamps, int32_t, 0xA2D401D, 0)
+ADD_TEST(getCapacity, getCapacity, int32_t, 77, 0)
+ADD_TEST(getEnergyCounter, getEnergyCounterNwh, int64_t, 0x1234567887654321, 0)
+ADD_TEST(getChargeStatus, getChargeStatus, BatteryStatus, HidlBatteryStatus::CHARGING,
+         HidlBatteryStatus::UNKNOWN)
+
+#undef ADD_TEST
+
+template <typename AidlValueType, typename HidlValueType>
+bool Translate(const HidlValueType& hidl_value, AidlValueType* aidl_value) {
+    return ::android::h2a::translate(hidl_value, aidl_value);
+}
+
+template <typename AidlValueType, typename HidlValueType>
+bool Translate(const std::vector<HidlValueType>& hidl_vec, std::vector<AidlValueType>* aidl_vec) {
+    aidl_vec->clear();
+    aidl_vec->reserve(hidl_vec.size());
+    for (const auto& hidl_value : hidl_vec) {
+        auto& aidl_value = aidl_vec->emplace_back();
+        if (!Translate(hidl_value, &aidl_value)) return false;
+    }
+    return true;
+}
+
+#define ADD_INFO_TEST(name, AidlValueType, hidl_value)                               \
+    TEST_F(HealthShimTest, name) {                                                   \
+        AidlValueType expected_aidl_value;                                           \
+        ASSERT_TRUE(Translate(hidl_value, &expected_aidl_value));                    \
+        ON_CALL(*hidl, name).WillByDefault(Invoke([&](auto cb) {                     \
+            cb(Result::SUCCESS, hidl_value);                                         \
+            return Void();                                                           \
+        }));                                                                         \
+        AidlValueType aidl_value;                                                    \
+        ASSERT_THAT(shim->name(&aidl_value), IsOk());                                \
+        ASSERT_EQ(aidl_value, expected_aidl_value);                                  \
+    }                                                                                \
+                                                                                     \
+    TEST_F(HealthShimTest, name##Unsupported) {                                      \
+        ON_CALL(*hidl, name).WillByDefault(Invoke([](auto cb) {                      \
+            cb(Result::NOT_SUPPORTED, {});                                           \
+            return Void();                                                           \
+        }));                                                                         \
+        AidlValueType aidl_value;                                                    \
+        ASSERT_THAT(shim->name(&aidl_value), ExceptionIs(EX_UNSUPPORTED_OPERATION)); \
+    }
+
+ADD_INFO_TEST(getStorageInfo, std::vector<StorageInfo>,
+              (std::vector<HidlStorageInfo>{{
+                      .lifetimeA = 15,
+                      .lifetimeB = 18,
+              }}))
+
+ADD_INFO_TEST(getDiskStats, std::vector<DiskStats>,
+              (std::vector<HidlDiskStats>{{
+                      .reads = 100,
+                      .writes = 200,
+              }}))
+
+ADD_INFO_TEST(getHealthInfo, HealthInfo,
+              (HidlHealthInfo{
+                      .batteryCurrentAverage = 999,
+              }))
+
+#undef ADD_INFO_TEST
+
+}  // namespace aidl::android::hardware::health
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl
index d8a8128..83e1797 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/Certificate.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl
index 2685525..e6ec04e 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/CipherSuite.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl
index f8d5a9e..cd8d56b 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
index 3224e4b..5065641 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl
index c6fb3c8..c912c52 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -36,6 +37,7 @@
   android.hardware.identity.HardwareInformation getHardwareInformation();
   android.hardware.identity.IWritableIdentityCredential createCredential(in @utf8InCpp String docType, in boolean testCredential);
   android.hardware.identity.IIdentityCredential getCredential(in android.hardware.identity.CipherSuite cipherSuite, in byte[] credentialData);
+  android.hardware.identity.IPresentationSession createPresentationSession(in android.hardware.identity.CipherSuite cipherSuite);
   const int STATUS_OK = 0;
   const int STATUS_FAILED = 1;
   const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2;
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IPresentationSession.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IPresentationSession.aidl
new file mode 100644
index 0000000..705dc29
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IPresentationSession.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.identity;
+@VintfStability
+interface IPresentationSession {
+  byte[] getEphemeralKeyPair();
+  long getAuthChallenge();
+  void setReaderEphemeralPublicKey(in byte[] publicKey);
+  void setSessionTranscript(in byte[] sessionTranscript);
+  android.hardware.identity.IIdentityCredential getCredential(in byte[] credentialData);
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
index 19a29ec..9a0fa9e 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl
index c9c2b9f..cec8e0c 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl
index aaf1e20..05b9ec2 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl
index 695fb3f..2003594 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/SecureAccessControlProfile.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 8ae293b..84d6ed0 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -17,9 +17,9 @@
 package android.hardware.identity;
 
 import android.hardware.identity.Certificate;
+import android.hardware.identity.IWritableIdentityCredential;
 import android.hardware.identity.RequestNamespace;
 import android.hardware.identity.SecureAccessControlProfile;
-import android.hardware.identity.IWritableIdentityCredential;
 import android.hardware.keymaster.HardwareAuthToken;
 import android.hardware.keymaster.VerificationToken;
 
@@ -44,6 +44,9 @@
      * This method was deprecated in API version 3 because there's no challenge so freshness
      * can't be checked. Use deleteCredentalWithChallenge() instead.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @return a COSE_Sign1 signature described above
      * @deprecated use deleteCredentalWithChallenge() instead.
      */
@@ -60,6 +63,9 @@
      * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @return the private key, in DER format as specified in RFC 5915.
      */
     byte[] createEphemeralKeyPair();
@@ -70,6 +76,9 @@
      * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @param publicKey contains the reader's ephemeral public key, in uncompressed
      *        form (e.g. 0x04 || X || Y).
      */
@@ -83,6 +92,9 @@
      * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned. If user authentication is not needed, this method may not be called.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @return challenge, a non-zero number.
      */
     long createAuthChallenge();
@@ -371,6 +383,9 @@
      * This CBOR enables an issuer to determine the exact state of the credential it
      * returns issuer-signed data for.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @param out signingKeyBlob contains an AES-GCM-ENC(storageKey, R, signingKey, docType)
      *     where signingKey is an EC private key in uncompressed form. That is, the returned
      *     blob is an encrypted copy of the newly-generated private signing key.
@@ -420,6 +435,9 @@
      *
      * This method was introduced in API version 3.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @param challenge a challenge set by the issuer to ensure freshness. Maximum size is 32 bytes
      *     and it may be empty. Fails with STATUS_INVALID_DATA if bigger than 32 bytes.
      * @return a COSE_Sign1 signature described above.
@@ -442,6 +460,9 @@
      *
      * This method was introduced in API version 3.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @param challenge a challenge set by the issuer to ensure freshness. Maximum size is 32 bytes
      *     and it may be empty. Fails with STATUS_INVALID_DATA if bigger than 32 bytes.
      * @return a COSE_Sign1 signature described above.
@@ -456,6 +477,9 @@
      *
      * This method was introduced in API version 3.
      *
+     * If the method is called on an instance obtained via IPresentationSession.getCredential(),
+     * STATUS_FAILED must be returned.
+     *
      * @return an IWritableIdentityCredential
      */
     IWritableIdentityCredential updateCredential();
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
index 638be79..86be7f5 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
@@ -16,10 +16,11 @@
 
 package android.hardware.identity;
 
-import android.hardware.identity.IIdentityCredential;
-import android.hardware.identity.IWritableIdentityCredential;
-import android.hardware.identity.HardwareInformation;
 import android.hardware.identity.CipherSuite;
+import android.hardware.identity.HardwareInformation;
+import android.hardware.identity.IIdentityCredential;
+import android.hardware.identity.IPresentationSession;
+import android.hardware.identity.IWritableIdentityCredential;
 
 /**
  * IIdentityCredentialStore provides an interface to a secure store for user identity documents.
@@ -105,7 +106,7 @@
  * STATUS_* integers defined in this interface. Each method states which status can be returned
  * and under which circumstances.
  *
- * The API described here is API version 3 which corresponds to feature version 202101
+ * The API described here is API version 4 which corresponds to feature version 202201
  * of the android.security.identity Framework API. An XML file declaring the feature
  * android.hardware.identity_credential (or android.hardware.identity_credential.direct_access
  * if implementing the Direct Access HAL) should be included declaring this feature version.
@@ -241,4 +242,25 @@
      * @return an IIdentityCredential interface that provides operations on the Credential.
      */
     IIdentityCredential getCredential(in CipherSuite cipherSuite, in byte[] credentialData);
+
+    /**
+     * createPresentationSession creates IPresentationSession interface which can be used to
+     * present one or more credentials to a remote verifier device.
+     *
+     * The cipher suite used to communicate with the remote verifier must be specified. Currently
+     * only a single cipher-suite is supported. Support for other cipher suites may be added in a
+     * future version of this HAL. If the requested cipher suite is not support the call fails
+     * with STATUS_CIPHER_SUITE_NOT_SUPPORTED.
+     *
+     * In this version of the HAL, implementations are only required to support a single session
+     * being active. In a future version, implementations may be required to support multiple
+     * presentation sessions being active at the same time.
+     *
+     * This method was introduced in API version 4.
+     *
+     * @param cipherSuite The cipher suite to use.
+     *
+     * @return an IPresentationSession interface.
+     */
+    IPresentationSession createPresentationSession(in CipherSuite cipherSuite);
 }
diff --git a/identity/aidl/android/hardware/identity/IPresentationSession.aidl b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
new file mode 100644
index 0000000..b0449f0
--- /dev/null
+++ b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.identity;
+
+import android.hardware.identity.CipherSuite;
+import android.hardware.identity.IIdentityCredential;
+
+/**
+ * An interface to present multiple credentials in the same session.
+ *
+ * This interface was introduced in API version 4.
+ *
+ */
+@VintfStability
+interface IPresentationSession {
+    /**
+     * Gets the ephemeral EC key pair to be used in establishing a secure session with a reader.
+     * This method returns the private key so the caller can perform an ECDH key agreement operation
+     * with the reader.  The reason for generating the key pair in the secure environment is so that
+     * the secure environment knows what public key to expect to find in the session transcript
+     * when presenting credentials.
+     *
+     * The generated key matches the selected cipher suite of the presentation session (e.g. EC
+     * key using the P-256 curve).
+     *
+     * @return the private key, in DER format as specified in RFC 5915.
+     */
+    byte[] getEphemeralKeyPair();
+
+    /**
+     * Gets the challenge value to be used for proving successful user authentication. This
+     * is to be included in the authToken passed to the IIdentityCredential.startRetrieval()
+     * method and the verificationToken passed to the IIdentityCredential.setVerificationToken()
+     * method.
+     *
+     * @return challenge, a non-zero number.
+     */
+    long getAuthChallenge();
+
+    /**
+     * Sets the public part of the reader's ephemeral key pair to be used to complete
+     * an ECDH key agreement for the session.
+     *
+     * The curve of the key must match the curve for the key returned by getEphemeralKeyPair().
+     *
+     * This method may only be called once per instance. If called more than once, STATUS_FAILED
+     * must be returned.
+     *
+     * @param publicKey contains the reader's ephemeral public key, in uncompressed
+     *        form (e.g. 0x04 || X || Y).
+     */
+    void setReaderEphemeralPublicKey(in byte[] publicKey);
+
+    /**
+     * Sets the session transcript for the session.
+     *
+     * This can be empty but if it's non-empty it must be valid CBOR.
+     *
+     * This method may only be called once per instance. If called more than once, STATUS_FAILED
+     * must be returned.
+     *
+     * @param sessionTrancsript the session transcript.
+     */
+    void setSessionTranscript(in byte[] sessionTranscript);
+
+    /**
+     * getCredential() retrieves an IIdentityCredential interface for presentation in the
+     * current presentation session.
+     *
+     * On the returned instance only the methods startRetrieval(), startRetrieveEntryValue(),
+     * retrieveEntryValue(), finishRetrieval(), setRequestedNamespaces(), setVerificationToken()
+     * may be called. Other methods will fail with STATUS_FAILED.
+     *
+     * The implementation is expected to get the session transcript, ephemeral key, reader
+     * ephemeral key, and auth challenge from this instance.
+     *
+     * @param credentialData is a CBOR-encoded structure containing metadata about the credential
+     *     and an encrypted byte array that contains data used to secure the credential.  See the
+     *     return argument of the same name in IWritableIdentityCredential.finishAddingEntries().
+     *
+     *     Note that the format of credentialData may depend on the feature version.
+     *     Implementations must support credentialData created by an earlier feature version.
+     *
+     * @return an IIdentityCredential interface that provides operations on the Credential.
+     */
+    IIdentityCredential getCredential(in byte[] credentialData);
+}
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 3de8d30..ca24afa 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -13,6 +13,7 @@
     srcs: [
         "common/IdentityCredential.cpp",
         "common/IdentityCredentialStore.cpp",
+        "common/PresentationSession.cpp",
         "common/WritableIdentityCredential.cpp",
     ],
     export_include_dirs: [
@@ -39,8 +40,8 @@
         "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-V3-ndk",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.identity-V4-ndk",
+        "android.hardware.keymaster-V4-ndk",
     ],
 }
 
@@ -49,6 +50,7 @@
     vendor_available: true,
     srcs: [
         "libeic/EicCbor.c",
+        "libeic/EicSession.c",
         "libeic/EicPresentation.c",
         "libeic/EicProvisioning.c",
         "EicOpsImpl.cc",
@@ -100,8 +102,8 @@
         "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-V3-ndk",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.identity-V4-ndk",
+        "android.hardware.keymaster-V4-ndk",
         "android.hardware.identity-libeic-hal-common",
         "android.hardware.identity-libeic-library",
     ],
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index 8ec4cc9..c98a91e 100644
--- a/identity/aidl/default/EicOpsImpl.cc
+++ b/identity/aidl/default/EicOpsImpl.cc
@@ -20,9 +20,13 @@
 #include <tuple>
 #include <vector>
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <string.h>
+
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
-#include <string.h>
 
 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
 
@@ -63,6 +67,11 @@
     return strlen(s);
 }
 
+void* eicMemMem(const uint8_t* haystack, size_t haystackLen, const uint8_t* needle,
+                size_t needleLen) {
+    return memmem(haystack, haystackLen, needle, needleLen);
+}
+
 int eicCryptoMemCmp(const void* s1, const void* s2, size_t n) {
     return CRYPTO_memcmp(s1, s2, n);
 }
@@ -117,6 +126,25 @@
     return true;
 }
 
+bool eicNextId(uint32_t* id) {
+    uint32_t oldId = *id;
+    uint32_t newId = 0;
+
+    do {
+        union {
+            uint8_t value8;
+            uint32_t value32;
+        } value;
+        if (!eicOpsRandom(&value.value8, sizeof(value))) {
+            return false;
+        }
+        newId = value.value32;
+    } while (newId == oldId && newId == 0);
+
+    *id = newId;
+    return true;
+}
+
 bool eicOpsEncryptAes128Gcm(
         const uint8_t* key,    // Must be 16 bytes
         const uint8_t* nonce,  // Must be 12 bytes
diff --git a/identity/aidl/default/EicTests.cpp b/identity/aidl/default/EicTests.cpp
index a28080d..7b69b75 100644
--- a/identity/aidl/default/EicTests.cpp
+++ b/identity/aidl/default/EicTests.cpp
@@ -66,7 +66,8 @@
     // Then present data from it...
     //
     FakeSecureHardwarePresentationProxy presentationProxy;
-    ASSERT_TRUE(presentationProxy.initialize(isTestCredential, docType, credData.value()));
+    ASSERT_TRUE(presentationProxy.initialize(0 /* sessionId */, isTestCredential, docType,
+                                             credData.value()));
     AccessCheckResult res =
             presentationProxy.startRetrieveEntryValue(nameSpace, name, 1, content.size(), acpIds);
     ASSERT_EQ(res, AccessCheckResult::kNoAccessControlProfiles);
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.cpp b/identity/aidl/default/FakeSecureHardwareProxy.cpp
index f0307dc..91e634c 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.cpp
+++ b/identity/aidl/default/FakeSecureHardwareProxy.cpp
@@ -23,6 +23,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <string.h>
+#include <map>
 
 #include <openssl/sha.h>
 
@@ -52,38 +53,110 @@
 
 // ----------------------------------------------------------------------
 
-FakeSecureHardwareProvisioningProxy::FakeSecureHardwareProvisioningProxy() {}
+// The singleton EicProvisioning object used everywhere.
+//
+EicProvisioning FakeSecureHardwareProvisioningProxy::ctx_;
 
-FakeSecureHardwareProvisioningProxy::~FakeSecureHardwareProvisioningProxy() {}
-
-bool FakeSecureHardwareProvisioningProxy::shutdown() {
-    LOG(INFO) << "FakeSecureHardwarePresentationProxy shutdown";
-    return true;
+FakeSecureHardwareProvisioningProxy::~FakeSecureHardwareProvisioningProxy() {
+    if (id_ != 0) {
+        shutdown();
+    }
 }
 
 bool FakeSecureHardwareProvisioningProxy::initialize(bool testCredential) {
-    LOG(INFO) << "FakeSecureHardwareProvisioningProxy created, sizeof(EicProvisioning): "
-              << sizeof(EicProvisioning);
-    return eicProvisioningInit(&ctx_, testCredential);
+    if (id_ != 0) {
+        LOG(WARNING) << "Proxy is already initialized";
+        return false;
+    }
+    bool initialized = eicProvisioningInit(&ctx_, testCredential);
+    if (!initialized) {
+        return false;
+    }
+    optional<uint32_t> id = getId();
+    if (!id) {
+        LOG(WARNING) << "Error getting id";
+        return false;
+    }
+    id_ = id.value();
+    return true;
 }
 
 bool FakeSecureHardwareProvisioningProxy::initializeForUpdate(
-        bool testCredential, string docType, vector<uint8_t> encryptedCredentialKeys) {
-    return eicProvisioningInitForUpdate(&ctx_, testCredential, docType.c_str(),
-                                        docType.size(),
-                                        encryptedCredentialKeys.data(),
-                                        encryptedCredentialKeys.size());
+        bool testCredential, const string& docType,
+        const vector<uint8_t>& encryptedCredentialKeys) {
+    if (id_ != 0) {
+        LOG(WARNING) << "Proxy is already initialized";
+        return false;
+    }
+    bool initialized = eicProvisioningInitForUpdate(&ctx_, testCredential, docType.c_str(),
+                                                    docType.size(), encryptedCredentialKeys.data(),
+                                                    encryptedCredentialKeys.size());
+    if (!initialized) {
+        return false;
+    }
+    optional<uint32_t> id = getId();
+    if (!id) {
+        LOG(WARNING) << "Error getting id";
+        return false;
+    }
+    id_ = id.value();
+    return true;
+}
+
+optional<uint32_t> FakeSecureHardwareProvisioningProxy::getId() {
+    uint32_t id;
+    if (!eicProvisioningGetId(&ctx_, &id)) {
+        return std::nullopt;
+    }
+    return id;
+}
+
+bool FakeSecureHardwareProvisioningProxy::validateId(const string& callerName) {
+    if (id_ == 0) {
+        LOG(WARNING) << "FakeSecureHardwareProvisioningProxy::" << callerName
+                     << ": While validating expected id is 0";
+        return false;
+    }
+    optional<uint32_t> id = getId();
+    if (!id) {
+        LOG(WARNING) << "FakeSecureHardwareProvisioningProxy::" << callerName
+                     << ": Error getting id for validating";
+        return false;
+    }
+    if (id.value() != id_) {
+        LOG(WARNING) << "FakeSecureHardwareProvisioningProxy::" << callerName
+                     << ": While validating expected id " << id_ << " but got " << id.value();
+        return false;
+    }
+    return true;
+}
+
+bool FakeSecureHardwareProvisioningProxy::shutdown() {
+    bool validated = validateId(__func__);
+    id_ = 0;
+    if (!validated) {
+        return false;
+    }
+    if (!eicProvisioningShutdown(&ctx_)) {
+        LOG(INFO) << "Error shutting down provisioning";
+        return false;
+    }
+    return true;
 }
 
 // Returns public key certificate.
 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::createCredentialKey(
         const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     uint8_t publicKeyCert[4096];
     size_t publicKeyCertSize = sizeof publicKeyCert;
     if (!eicProvisioningCreateCredentialKey(&ctx_, challenge.data(), challenge.size(),
                                             applicationId.data(), applicationId.size(),
                                             publicKeyCert, &publicKeyCertSize)) {
-        return {};
+        return std::nullopt;
     }
     vector<uint8_t> pubKeyCert(publicKeyCertSize);
     memcpy(pubKeyCert.data(), publicKeyCert, publicKeyCertSize);
@@ -91,8 +164,11 @@
 }
 
 bool FakeSecureHardwareProvisioningProxy::startPersonalization(
-        int accessControlProfileCount, vector<int> entryCounts, const string& docType,
+        int accessControlProfileCount, const vector<int>& entryCounts, const string& docType,
         size_t expectedProofOfProvisioningSize) {
+    if (!validateId(__func__)) {
+        return false;
+    }
 
     if (!eicProvisioningStartPersonalization(&ctx_, accessControlProfileCount,
                                              entryCounts.data(),
@@ -108,13 +184,17 @@
 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::addAccessControlProfile(
         int id, const vector<uint8_t>& readerCertificate, bool userAuthenticationRequired,
         uint64_t timeoutMillis, uint64_t secureUserId) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> mac(28);
     uint8_t scratchSpace[512];
     if (!eicProvisioningAddAccessControlProfile(
                 &ctx_, id, readerCertificate.data(), readerCertificate.size(),
                 userAuthenticationRequired, timeoutMillis, secureUserId, mac.data(),
                 scratchSpace, sizeof(scratchSpace))) {
-        return {};
+        return std::nullopt;
     }
     return mac;
 }
@@ -122,6 +202,10 @@
 bool FakeSecureHardwareProvisioningProxy::beginAddEntry(const vector<int>& accessControlProfileIds,
                                                         const string& nameSpace, const string& name,
                                                         uint64_t entrySize) {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
     uint8_t scratchSpace[512];
     vector<uint8_t> uint8AccessControlProfileIds;
     for (size_t i = 0; i < accessControlProfileIds.size(); i++) {
@@ -138,6 +222,10 @@
 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::addEntryValue(
         const vector<int>& accessControlProfileIds, const string& nameSpace, const string& name,
         const vector<uint8_t>& content) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> eicEncryptedContent;
     uint8_t scratchSpace[512];
     vector<uint8_t> uint8AccessControlProfileIds;
@@ -150,16 +238,20 @@
                 &ctx_, uint8AccessControlProfileIds.data(), uint8AccessControlProfileIds.size(),
                 nameSpace.c_str(), nameSpace.size(), name.c_str(), name.size(), content.data(),
                 content.size(), eicEncryptedContent.data(), scratchSpace, sizeof(scratchSpace))) {
-        return {};
+        return std::nullopt;
     }
     return eicEncryptedContent;
 }
 
 // Returns signatureOfToBeSigned (EIC_ECDSA_P256_SIGNATURE_SIZE bytes).
 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::finishAddingEntries() {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
     if (!eicProvisioningFinishAddingEntries(&ctx_, signatureOfToBeSigned.data())) {
-        return {};
+        return std::nullopt;
     }
     return signatureOfToBeSigned;
 }
@@ -167,11 +259,15 @@
 // Returns encryptedCredentialKeys.
 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::finishGetCredentialData(
         const string& docType) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> encryptedCredentialKeys(116);
     size_t size = encryptedCredentialKeys.size();
     if (!eicProvisioningFinishGetCredentialData(&ctx_, docType.c_str(), docType.size(),
                                                 encryptedCredentialKeys.data(), &size)) {
-        return {};
+        return std::nullopt;
     }
     encryptedCredentialKeys.resize(size);
     return encryptedCredentialKeys;
@@ -179,21 +275,200 @@
 
 // ----------------------------------------------------------------------
 
-FakeSecureHardwarePresentationProxy::FakeSecureHardwarePresentationProxy() {}
+// The singleton EicSession object used everywhere.
+//
+EicSession FakeSecureHardwareSessionProxy::ctx_;
 
-FakeSecureHardwarePresentationProxy::~FakeSecureHardwarePresentationProxy() {}
+FakeSecureHardwareSessionProxy::~FakeSecureHardwareSessionProxy() {
+    if (id_ != 0) {
+        shutdown();
+    }
+}
 
-bool FakeSecureHardwarePresentationProxy::initialize(bool testCredential, string docType,
-                                                     vector<uint8_t> encryptedCredentialKeys) {
-    LOG(INFO) << "FakeSecureHardwarePresentationProxy created, sizeof(EicPresentation): "
-              << sizeof(EicPresentation);
-    return eicPresentationInit(&ctx_, testCredential, docType.c_str(), docType.size(),
-                               encryptedCredentialKeys.data(), encryptedCredentialKeys.size());
+bool FakeSecureHardwareSessionProxy::initialize() {
+    if (id_ != 0) {
+        LOG(WARNING) << "Proxy is already initialized";
+        return false;
+    }
+    bool initialized = eicSessionInit(&ctx_);
+    if (!initialized) {
+        return false;
+    }
+    optional<uint32_t> id = getId();
+    if (!id) {
+        LOG(WARNING) << "Error getting id";
+        return false;
+    }
+    id_ = id.value();
+    return true;
+}
+
+optional<uint32_t> FakeSecureHardwareSessionProxy::getId() {
+    uint32_t id;
+    if (!eicSessionGetId(&ctx_, &id)) {
+        return std::nullopt;
+    }
+    return id;
+}
+
+bool FakeSecureHardwareSessionProxy::shutdown() {
+    bool validated = validateId(__func__);
+    id_ = 0;
+    if (!validated) {
+        return false;
+    }
+    if (!eicSessionShutdown(&ctx_)) {
+        LOG(INFO) << "Error shutting down session";
+        return false;
+    }
+    return true;
+}
+
+bool FakeSecureHardwareSessionProxy::validateId(const string& callerName) {
+    if (id_ == 0) {
+        LOG(WARNING) << "FakeSecureHardwareSessionProxy::" << callerName
+                     << ": While validating expected id is 0";
+        return false;
+    }
+    optional<uint32_t> id = getId();
+    if (!id) {
+        LOG(WARNING) << "FakeSecureHardwareSessionProxy::" << callerName
+                     << ": Error getting id for validating";
+        return false;
+    }
+    if (id.value() != id_) {
+        LOG(WARNING) << "FakeSecureHardwareSessionProxy::" << callerName
+                     << ": While validating expected id " << id_ << " but got " << id.value();
+        return false;
+    }
+    return true;
+}
+
+optional<uint64_t> FakeSecureHardwareSessionProxy::getAuthChallenge() {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
+    uint64_t authChallenge;
+    if (!eicSessionGetAuthChallenge(&ctx_, &authChallenge)) {
+        return std::nullopt;
+    }
+    return authChallenge;
+}
+
+optional<vector<uint8_t>> FakeSecureHardwareSessionProxy::getEphemeralKeyPair() {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
+    vector<uint8_t> priv(EIC_P256_PRIV_KEY_SIZE);
+    if (!eicSessionGetEphemeralKeyPair(&ctx_, priv.data())) {
+        return std::nullopt;
+    }
+    return priv;
+}
+
+bool FakeSecureHardwareSessionProxy::setReaderEphemeralPublicKey(
+        const vector<uint8_t>& readerEphemeralPublicKey) {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
+    return eicSessionSetReaderEphemeralPublicKey(&ctx_, readerEphemeralPublicKey.data());
+}
+
+bool FakeSecureHardwareSessionProxy::setSessionTranscript(
+        const vector<uint8_t>& sessionTranscript) {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
+    return eicSessionSetSessionTranscript(&ctx_, sessionTranscript.data(),
+                                          sessionTranscript.size());
+}
+
+// ----------------------------------------------------------------------
+
+// The singleton EicPresentation object used everywhere.
+//
+EicPresentation FakeSecureHardwarePresentationProxy::ctx_;
+
+FakeSecureHardwarePresentationProxy::~FakeSecureHardwarePresentationProxy() {
+    if (id_ != 0) {
+        shutdown();
+    }
+}
+
+bool FakeSecureHardwarePresentationProxy::initialize(
+        uint32_t sessionId, bool testCredential, const string& docType,
+        const vector<uint8_t>& encryptedCredentialKeys) {
+    if (id_ != 0) {
+        LOG(WARNING) << "Proxy is already initialized";
+        return false;
+    }
+    bool initialized =
+            eicPresentationInit(&ctx_, sessionId, testCredential, docType.c_str(), docType.size(),
+                                encryptedCredentialKeys.data(), encryptedCredentialKeys.size());
+    if (!initialized) {
+        return false;
+    }
+    optional<uint32_t> id = getId();
+    if (!id) {
+        LOG(WARNING) << "Error getting id";
+        return false;
+    }
+    id_ = id.value();
+    return true;
+}
+
+optional<uint32_t> FakeSecureHardwarePresentationProxy::getId() {
+    uint32_t id;
+    if (!eicPresentationGetId(&ctx_, &id)) {
+        return std::nullopt;
+    }
+    return id;
+}
+
+bool FakeSecureHardwarePresentationProxy::validateId(const string& callerName) {
+    if (id_ == 0) {
+        LOG(WARNING) << "FakeSecureHardwarePresentationProxy::" << callerName
+                     << ": While validating expected id is 0";
+        return false;
+    }
+    optional<uint32_t> id = getId();
+    if (!id) {
+        LOG(WARNING) << "FakeSecureHardwarePresentationProxy::" << callerName
+                     << ": Error getting id for validating";
+        return false;
+    }
+    if (id.value() != id_) {
+        LOG(WARNING) << "FakeSecureHardwarePresentationProxy::" << callerName
+                     << ": While validating expected id " << id_ << " but got " << id.value();
+        return false;
+    }
+    return true;
+}
+
+bool FakeSecureHardwarePresentationProxy::shutdown() {
+    bool validated = validateId(__func__);
+    id_ = 0;
+    if (!validated) {
+        return false;
+    }
+    if (!eicPresentationShutdown(&ctx_)) {
+        LOG(INFO) << "Error shutting down presentation";
+        return false;
+    }
+    return true;
 }
 
 // Returns publicKeyCert (1st component) and signingKeyBlob (2nd component)
 optional<pair<vector<uint8_t>, vector<uint8_t>>>
-FakeSecureHardwarePresentationProxy::generateSigningKeyPair(string docType, time_t now) {
+FakeSecureHardwarePresentationProxy::generateSigningKeyPair(const string& docType, time_t now) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     uint8_t publicKeyCert[512];
     size_t publicKeyCertSize = sizeof(publicKeyCert);
     vector<uint8_t> signingKeyBlob(60);
@@ -201,7 +476,7 @@
     if (!eicPresentationGenerateSigningKeyPair(&ctx_, docType.c_str(), docType.size(), now,
                                                publicKeyCert, &publicKeyCertSize,
                                                signingKeyBlob.data())) {
-        return {};
+        return std::nullopt;
     }
 
     vector<uint8_t> cert;
@@ -213,33 +488,44 @@
 
 // Returns private key
 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::createEphemeralKeyPair() {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> priv(EIC_P256_PRIV_KEY_SIZE);
     if (!eicPresentationCreateEphemeralKeyPair(&ctx_, priv.data())) {
-        return {};
+        return std::nullopt;
     }
     return priv;
 }
 
 optional<uint64_t> FakeSecureHardwarePresentationProxy::createAuthChallenge() {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     uint64_t challenge;
     if (!eicPresentationCreateAuthChallenge(&ctx_, &challenge)) {
-        return {};
+        return std::nullopt;
     }
     return challenge;
 }
 
-bool FakeSecureHardwarePresentationProxy::shutdown() {
-    LOG(INFO) << "FakeSecureHardwarePresentationProxy shutdown";
-    return true;
-}
-
 bool FakeSecureHardwarePresentationProxy::pushReaderCert(const vector<uint8_t>& certX509) {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
     return eicPresentationPushReaderCert(&ctx_, certX509.data(), certX509.size());
 }
 
 bool FakeSecureHardwarePresentationProxy::validateRequestMessage(
         const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& requestMessage,
         int coseSignAlg, const vector<uint8_t>& readerSignatureOfToBeSigned) {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
     return eicPresentationValidateRequestMessage(
             &ctx_, sessionTranscript.data(), sessionTranscript.size(), requestMessage.data(),
             requestMessage.size(), coseSignAlg, readerSignatureOfToBeSigned.data(),
@@ -251,6 +537,10 @@
         int hardwareAuthenticatorType, uint64_t timeStamp, const vector<uint8_t>& mac,
         uint64_t verificationTokenChallenge, uint64_t verificationTokenTimestamp,
         int verificationTokenSecurityLevel, const vector<uint8_t>& verificationTokenMac) {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
     return eicPresentationSetAuthToken(&ctx_, challenge, secureUserId, authenticatorId,
                                        hardwareAuthenticatorType, timeStamp, mac.data(), mac.size(),
                                        verificationTokenChallenge, verificationTokenTimestamp,
@@ -261,6 +551,10 @@
 optional<bool> FakeSecureHardwarePresentationProxy::validateAccessControlProfile(
         int id, const vector<uint8_t>& readerCertificate, bool userAuthenticationRequired,
         int timeoutMillis, uint64_t secureUserId, const vector<uint8_t>& mac) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     bool accessGranted = false;
     uint8_t scratchSpace[512];
     if (!eicPresentationValidateAccessControlProfile(&ctx_, id, readerCertificate.data(),
@@ -268,12 +562,16 @@
                                                      userAuthenticationRequired, timeoutMillis,
                                                      secureUserId, mac.data(), &accessGranted,
                                                      scratchSpace, sizeof(scratchSpace))) {
-        return {};
+        return std::nullopt;
     }
     return accessGranted;
 }
 
 bool FakeSecureHardwarePresentationProxy::startRetrieveEntries() {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
     return eicPresentationStartRetrieveEntries(&ctx_);
 }
 
@@ -281,6 +579,10 @@
         const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& readerEphemeralPublicKey,
         const vector<uint8_t>& signingKeyBlob, const string& docType,
         unsigned int numNamespacesWithValues, size_t expectedProofOfProvisioningSize) {
+    if (!validateId(__func__)) {
+        return false;
+    }
+
     if (signingKeyBlob.size() != 60) {
         eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size());
         return false;
@@ -294,6 +596,10 @@
 AccessCheckResult FakeSecureHardwarePresentationProxy::startRetrieveEntryValue(
         const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
         int32_t entrySize, const vector<int32_t>& accessControlProfileIds) {
+    if (!validateId(__func__)) {
+        return AccessCheckResult::kFailed;
+    }
+
     uint8_t scratchSpace[512];
     vector<uint8_t> uint8AccessControlProfileIds;
     for (size_t i = 0; i < accessControlProfileIds.size(); i++) {
@@ -324,6 +630,10 @@
 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::retrieveEntryValue(
         const vector<uint8_t>& encryptedContent, const string& nameSpace, const string& name,
         const vector<int32_t>& accessControlProfileIds) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     uint8_t scratchSpace[512];
     vector<uint8_t> uint8AccessControlProfileIds;
     for (size_t i = 0; i < accessControlProfileIds.size(); i++) {
@@ -337,16 +647,20 @@
                 nameSpace.c_str(), nameSpace.size(), name.c_str(), name.size(),
                 uint8AccessControlProfileIds.data(), uint8AccessControlProfileIds.size(),
                 scratchSpace, sizeof(scratchSpace))) {
-        return {};
+        return std::nullopt;
     }
     return content;
 }
 
 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::finishRetrieval() {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> mac(32);
     size_t macSize = 32;
     if (!eicPresentationFinishRetrieval(&ctx_, mac.data(), &macSize)) {
-        return {};
+        return std::nullopt;
     }
     mac.resize(macSize);
     return mac;
@@ -355,11 +669,15 @@
 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::deleteCredential(
         const string& docType, const vector<uint8_t>& challenge, bool includeChallenge,
         size_t proofOfDeletionCborSize) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
     if (!eicPresentationDeleteCredential(&ctx_, docType.c_str(), docType.size(), challenge.data(),
                                          challenge.size(), includeChallenge,
                                          proofOfDeletionCborSize, signatureOfToBeSigned.data())) {
-        return {};
+        return std::nullopt;
     }
     return signatureOfToBeSigned;
 }
@@ -367,11 +685,15 @@
 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::proveOwnership(
         const string& docType, bool testCredential, const vector<uint8_t>& challenge,
         size_t proofOfOwnershipCborSize) {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
     vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
     if (!eicPresentationProveOwnership(&ctx_, docType.c_str(), docType.size(), testCredential,
                                        challenge.data(), challenge.size(), proofOfOwnershipCborSize,
                                        signatureOfToBeSigned.data())) {
-        return {};
+        return std::nullopt;
     }
     return signatureOfToBeSigned;
 }
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.h b/identity/aidl/default/FakeSecureHardwareProxy.h
index 6852c1a..df98c7a 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.h
+++ b/identity/aidl/default/FakeSecureHardwareProxy.h
@@ -27,21 +27,23 @@
 //
 class FakeSecureHardwareProvisioningProxy : public SecureHardwareProvisioningProxy {
   public:
-    FakeSecureHardwareProvisioningProxy();
+    FakeSecureHardwareProvisioningProxy() = default;
     virtual ~FakeSecureHardwareProvisioningProxy();
 
     bool initialize(bool testCredential) override;
 
-    bool initializeForUpdate(bool testCredential, string docType,
-                             vector<uint8_t> encryptedCredentialKeys) override;
+    bool initializeForUpdate(bool testCredential, const string& docType,
+                             const vector<uint8_t>& encryptedCredentialKeys) override;
 
     bool shutdown() override;
 
+    optional<uint32_t> getId() override;
+
     // Returns public key certificate.
     optional<vector<uint8_t>> createCredentialKey(const vector<uint8_t>& challenge,
                                                   const vector<uint8_t>& applicationId) override;
 
-    bool startPersonalization(int accessControlProfileCount, vector<int> entryCounts,
+    bool startPersonalization(int accessControlProfileCount, const vector<int>& entryCounts,
                               const string& docType,
                               size_t expectedProofOfProvisioningSize) override;
 
@@ -67,21 +69,81 @@
     optional<vector<uint8_t>> finishGetCredentialData(const string& docType) override;
 
   protected:
-    EicProvisioning ctx_;
+    // See docs for id_.
+    //
+    bool validateId(const string& callerName);
+
+    // We use a singleton libeic object, shared by all proxy instances.  This is to
+    // properly simulate a situation where libeic is used on constrained hardware
+    // with only enough RAM for a single instance of the libeic object.
+    //
+    static EicProvisioning ctx_;
+
+    // On the HAL side we keep track of the ID that was assigned to the libeic object
+    // created in secure hardware. For every call into libeic we validate that this
+    // identifier matches what is on the secure side. This is what the validateId()
+    // method does.
+    //
+    uint32_t id_ = 0;
+};
+
+// This implementation uses libEmbeddedIC in-process.
+//
+class FakeSecureHardwareSessionProxy : public SecureHardwareSessionProxy {
+  public:
+    FakeSecureHardwareSessionProxy() = default;
+    virtual ~FakeSecureHardwareSessionProxy();
+
+    bool initialize() override;
+
+    bool shutdown() override;
+
+    optional<uint32_t> getId() override;
+
+    optional<uint64_t> getAuthChallenge() override;
+
+    // Returns private key
+    optional<vector<uint8_t>> getEphemeralKeyPair() override;
+
+    bool setReaderEphemeralPublicKey(const vector<uint8_t>& readerEphemeralPublicKey) override;
+
+    bool setSessionTranscript(const vector<uint8_t>& sessionTranscript) override;
+
+  protected:
+    // See docs for id_.
+    //
+    bool validateId(const string& callerName);
+
+    // We use a singleton libeic object, shared by all proxy instances.  This is to
+    // properly simulate a situation where libeic is used on constrained hardware
+    // with only enough RAM for a single instance of the libeic object.
+    //
+    static EicSession ctx_;
+
+    // On the HAL side we keep track of the ID that was assigned to the libeic object
+    // created in secure hardware. For every call into libeic we validate that this
+    // identifier matches what is on the secure side. This is what the validateId()
+    // method does.
+    //
+    uint32_t id_ = 0;
 };
 
 // This implementation uses libEmbeddedIC in-process.
 //
 class FakeSecureHardwarePresentationProxy : public SecureHardwarePresentationProxy {
   public:
-    FakeSecureHardwarePresentationProxy();
+    FakeSecureHardwarePresentationProxy() = default;
     virtual ~FakeSecureHardwarePresentationProxy();
 
-    bool initialize(bool testCredential, string docType,
-                    vector<uint8_t> encryptedCredentialKeys) override;
+    bool initialize(uint32_t sessionId, bool testCredential, const string& docType,
+                    const vector<uint8_t>& encryptedCredentialKeys) override;
+
+    bool shutdown() override;
+
+    optional<uint32_t> getId() override;
 
     // Returns publicKeyCert (1st component) and signingKeyBlob (2nd component)
-    optional<pair<vector<uint8_t>, vector<uint8_t>>> generateSigningKeyPair(string docType,
+    optional<pair<vector<uint8_t>, vector<uint8_t>>> generateSigningKeyPair(const string& docType,
                                                                             time_t now) override;
 
     // Returns private key
@@ -133,10 +195,23 @@
                                              const vector<uint8_t>& challenge,
                                              size_t proofOfOwnershipCborSize) override;
 
-    bool shutdown() override;
-
   protected:
-    EicPresentation ctx_;
+    // See docs for id_.
+    //
+    bool validateId(const string& callerName);
+
+    // We use a singleton libeic object, shared by all proxy instances.  This is to
+    // properly simulate a situation where libeic is used on constrained hardware
+    // with only enough RAM for a single instance of the libeic object.
+    //
+    static EicPresentation ctx_;
+
+    // On the HAL side we keep track of the ID that was assigned to the libeic object
+    // created in secure hardware. For every call into libeic we validate that this
+    // identifier matches what is on the secure side. This is what the validateId()
+    // method does.
+    //
+    uint32_t id_ = 0;
 };
 
 // Factory implementation.
@@ -150,6 +225,10 @@
         return new FakeSecureHardwareProvisioningProxy();
     }
 
+    sp<SecureHardwareSessionProxy> createSessionProxy() override {
+        return new FakeSecureHardwareSessionProxy();
+    }
+
     sp<SecureHardwarePresentationProxy> createPresentationProxy() override {
         return new FakeSecureHardwarePresentationProxy();
     }
diff --git a/identity/aidl/default/android.hardware.identity_credential.xml b/identity/aidl/default/android.hardware.identity_credential.xml
index 5149792..20b2710 100644
--- a/identity/aidl/default/android.hardware.identity_credential.xml
+++ b/identity/aidl/default/android.hardware.identity_credential.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <permissions>
-  <feature name="android.hardware.identity_credential" version="202101" />
+  <feature name="android.hardware.identity_credential" version="202201" />
 </permissions>
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index 95557b5..7678ecb 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -72,14 +72,38 @@
     testCredential_ = testCredentialItem->value();
 
     encryptedCredentialKeys_ = encryptedCredentialKeysItem->value();
-    if (!hwProxy_->initialize(testCredential_, docType_, encryptedCredentialKeys_)) {
-        LOG(ERROR) << "hwProxy->initialize failed";
-        return false;
+
+    // If in a session, delay the initialization of the proxy.
+    //
+    if (!session_) {
+        ndk::ScopedAStatus status = ensureHwProxy();
+        if (!status.isOk()) {
+            LOG(ERROR) << "Error initializing hw proxy";
+            return IIdentityCredentialStore::STATUS_FAILED;
+        }
     }
 
     return IIdentityCredentialStore::STATUS_OK;
 }
 
+ndk::ScopedAStatus IdentityCredential::ensureHwProxy() {
+    if (hwProxy_) {
+        return ndk::ScopedAStatus::ok();
+    }
+    hwProxy_ = hwProxyFactory_->createPresentationProxy();
+    if (!hwProxy_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error creating hw proxy"));
+    }
+    uint64_t sessionId = session_ ? session_->getSessionId() : EIC_PRESENTATION_ID_UNSET;
+    if (!hwProxy_->initialize(sessionId, testCredential_, docType_, encryptedCredentialKeys_)) {
+        hwProxy_.clear();
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error initializing hw proxy"));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus IdentityCredential::deleteCredential(
         vector<uint8_t>* outProofOfDeletionSignature) {
     return deleteCredentialCommon({}, false, outProofOfDeletionSignature);
@@ -93,6 +117,14 @@
 ndk::ScopedAStatus IdentityCredential::deleteCredentialCommon(
         const vector<uint8_t>& challenge, bool includeChallenge,
         vector<uint8_t>* outProofOfDeletionSignature) {
+    if (session_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+    }
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
     if (challenge.size() > 32) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge too big"));
@@ -128,6 +160,14 @@
 
 ndk::ScopedAStatus IdentityCredential::proveOwnership(
         const vector<uint8_t>& challenge, vector<uint8_t>* outProofOfOwnershipSignature) {
+    if (session_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+    }
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
     if (challenge.size() > 32) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge too big"));
@@ -159,6 +199,14 @@
 }
 
 ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector<uint8_t>* outKeyPair) {
+    if (session_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+    }
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
     optional<vector<uint8_t>> ephemeralPriv = hwProxy_->createEphemeralKeyPair();
     if (!ephemeralPriv) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -186,11 +234,23 @@
 
 ndk::ScopedAStatus IdentityCredential::setReaderEphemeralPublicKey(
         const vector<uint8_t>& publicKey) {
+    if (session_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+    }
     readerPublicKey_ = publicKey;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus IdentityCredential::createAuthChallenge(int64_t* outChallenge) {
+    if (session_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+    }
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
     optional<uint64_t> challenge = hwProxy_->createAuthChallenge();
     if (!challenge) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -217,16 +277,22 @@
         const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
         const vector<uint8_t>& signingKeyBlob, const vector<uint8_t>& sessionTranscript,
         const vector<uint8_t>& readerSignature, const vector<int32_t>& requestCounts) {
-    std::unique_ptr<cppbor::Item> sessionTranscriptItem;
-    if (sessionTranscript.size() > 0) {
-        auto [item, _, message] = cppbor::parse(sessionTranscript);
-        if (item == nullptr) {
-            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_INVALID_DATA,
-                    "SessionTranscript contains invalid CBOR"));
-        }
-        sessionTranscriptItem = std::move(item);
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
     }
+
+    // If in a session, ensure the passed-in session transcript matches the
+    // session transcript from the session.
+    if (session_) {
+        if (sessionTranscript != session_->getSessionTranscript()) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH,
+                    "In a session and passed-in SessionTranscript doesn't match the one "
+                    "from the session"));
+        }
+    }
+
     if (numStartRetrievalCalls_ > 0) {
         if (sessionTranscript_ != sessionTranscript) {
             LOG(ERROR) << "Session Transcript changed";
@@ -390,32 +456,36 @@
         }
     }
 
-    // TODO: move this check to the TA
-#if 1
-    // To prevent replay-attacks, we check that the public part of the ephemeral
-    // key we previously created, is present in the DeviceEngagement part of
-    // SessionTranscript as a COSE_Key, in uncompressed form.
-    //
-    // We do this by just searching for the X and Y coordinates.
-    if (sessionTranscript.size() > 0) {
-        auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
-        if (!getXYSuccess) {
-            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
-                    "Error extracting X and Y from ePub"));
-        }
-        if (sessionTranscript.size() > 0 &&
-            !(memmem(sessionTranscript.data(), sessionTranscript.size(), ePubX.data(),
-                     ePubX.size()) != nullptr &&
-              memmem(sessionTranscript.data(), sessionTranscript.size(), ePubY.data(),
-                     ePubY.size()) != nullptr)) {
-            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
-                    "Did not find ephemeral public key's X and Y coordinates in "
-                    "SessionTranscript (make sure leading zeroes are not used)"));
+    if (session_) {
+        // If presenting in a session, the TA has already done this check.
+
+    } else {
+        // To prevent replay-attacks, we check that the public part of the ephemeral
+        // key we previously created, is present in the DeviceEngagement part of
+        // SessionTranscript as a COSE_Key, in uncompressed form.
+        //
+        // We do this by just searching for the X and Y coordinates.
+        //
+        // Would be nice to move this check to the TA.
+        if (sessionTranscript.size() > 0) {
+            auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
+            if (!getXYSuccess) {
+                return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                        IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+                        "Error extracting X and Y from ePub"));
+            }
+            if (sessionTranscript.size() > 0 &&
+                !(memmem(sessionTranscript.data(), sessionTranscript.size(), ePubX.data(),
+                         ePubX.size()) != nullptr &&
+                  memmem(sessionTranscript.data(), sessionTranscript.size(), ePubY.data(),
+                         ePubY.size()) != nullptr)) {
+                return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                        IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+                        "Did not find ephemeral public key's X and Y coordinates in "
+                        "SessionTranscript (make sure leading zeroes are not used)"));
+            }
         }
     }
-#endif
 
     // itemsRequest: If non-empty, contains request data that may be signed by the
     // reader.  The content can be defined in the way appropriate for the
@@ -537,21 +607,38 @@
 
     // Finally, pass info so the HMAC key can be derived and the TA can start
     // creating the DeviceNameSpaces CBOR...
-    if (sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0 && signingKeyBlob.size() > 0) {
-        // We expect the reader ephemeral public key to be same size and curve
-        // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
-        // won't work. So its length should be 65 bytes and it should be
-        // starting with 0x04.
-        if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
-            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_FAILED,
-                    "Reader public key is not in expected format"));
+    if (!session_) {
+        if (sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0 &&
+            signingKeyBlob.size() > 0) {
+            // We expect the reader ephemeral public key to be same size and curve
+            // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
+            // won't work. So its length should be 65 bytes and it should be
+            // starting with 0x04.
+            if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
+                return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                        IIdentityCredentialStore::STATUS_FAILED,
+                        "Reader public key is not in expected format"));
+            }
+            vector<uint8_t> pubKeyP256(readerPublicKey_.begin() + 1, readerPublicKey_.end());
+            if (!hwProxy_->calcMacKey(sessionTranscript_, pubKeyP256, signingKeyBlob, docType_,
+                                      numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+                return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                        IIdentityCredentialStore::STATUS_FAILED,
+                        "Error starting retrieving entries"));
+            }
         }
-        vector<uint8_t> pubKeyP256(readerPublicKey_.begin() + 1, readerPublicKey_.end());
-        if (!hwProxy_->calcMacKey(sessionTranscript_, pubKeyP256, signingKeyBlob, docType_,
-                                  numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
-            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_FAILED, "Error starting retrieving entries"));
+    } else {
+        if (session_->getSessionTranscript().size() > 0 &&
+            session_->getReaderEphemeralPublicKey().size() > 0 && signingKeyBlob.size() > 0) {
+            // Don't actually pass the reader ephemeral public key in, the TA will get
+            // it from the session object.
+            //
+            if (!hwProxy_->calcMacKey(sessionTranscript_, {}, signingKeyBlob, docType_,
+                                      numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+                return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                        IIdentityCredentialStore::STATUS_FAILED,
+                        "Error starting retrieving entries"));
+            }
         }
     }
 
@@ -665,6 +752,11 @@
 ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue(
         const string& nameSpace, const string& name, int32_t entrySize,
         const vector<int32_t>& accessControlProfileIds) {
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
+
     if (name.empty()) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_INVALID_DATA, "Name cannot be empty"));
@@ -785,6 +877,11 @@
 
 ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector<uint8_t>& encryptedContent,
                                                           vector<uint8_t>* outContent) {
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
+
     optional<vector<uint8_t>> content = hwProxy_->retrieveEntryValue(
             encryptedContent, currentNameSpace_, currentName_, currentAccessControlProfileIds_);
     if (!content) {
@@ -829,6 +926,11 @@
 
 ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
                                                        vector<uint8_t>* outDeviceNameSpaces) {
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
+
     if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
         deviceNameSpacesMap_.add(currentNameSpace_,
                                  std::move(currentNameSpaceDeviceNameSpacesMap_));
@@ -846,18 +948,23 @@
                         .c_str()));
     }
 
-    // If there's no signing key or no sessionTranscript or no reader ephemeral
-    // public key, we return the empty MAC.
+    // If the TA calculated a MAC (it might not have), format it as a COSE_Mac0
+    //
     optional<vector<uint8_t>> mac;
-    if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
-        readerPublicKey_.size() > 0) {
-        optional<vector<uint8_t>> digestToBeMaced = hwProxy_->finishRetrieval();
-        if (!digestToBeMaced || digestToBeMaced.value().size() != 32) {
+    optional<vector<uint8_t>> digestToBeMaced = hwProxy_->finishRetrieval();
+
+    // The MAC not being set means an error occurred.
+    if (!digestToBeMaced) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA, "Error generating digestToBeMaced"));
+    }
+    // Size 0 means that the MAC isn't set. If it's set, it has to be 32 bytes.
+    if (digestToBeMaced.value().size() != 0) {
+        if (digestToBeMaced.value().size() != 32) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                     IIdentityCredentialStore::STATUS_INVALID_DATA,
-                    "Error generating digestToBeMaced"));
+                    "Unexpected size for digestToBeMaced"));
         }
-        // Now construct COSE_Mac0 from the returned MAC...
         mac = support::coseMacWithDigest(digestToBeMaced.value(), {} /* data */);
     }
 
@@ -868,6 +975,15 @@
 
 ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
         vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
+    if (session_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+    }
+    ndk::ScopedAStatus status = ensureHwProxy();
+    if (!status.isOk()) {
+        return status;
+    }
+
     time_t now = time(NULL);
     optional<pair<vector<uint8_t>, vector<uint8_t>>> pair =
             hwProxy_->generateSigningKeyPair(docType_, now);
@@ -885,9 +1001,18 @@
 
 ndk::ScopedAStatus IdentityCredential::updateCredential(
         shared_ptr<IWritableIdentityCredential>* outWritableCredential) {
-    sp<SecureHardwareProvisioningProxy> hwProxy = hwProxyFactory_->createProvisioningProxy();
+    if (session_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+    }
+    sp<SecureHardwareProvisioningProxy> provisioningHwProxy =
+            hwProxyFactory_->createProvisioningProxy();
+    if (!provisioningHwProxy) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error creating provisioning proxy"));
+    }
     shared_ptr<WritableIdentityCredential> wc =
-            ndk::SharedRefBase::make<WritableIdentityCredential>(hwProxy, docType_,
+            ndk::SharedRefBase::make<WritableIdentityCredential>(provisioningHwProxy, docType_,
                                                                  testCredential_);
     if (!wc->initializeForUpdate(encryptedCredentialKeys_)) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index ef9d133..2935fb8 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -30,6 +30,7 @@
 #include <cppbor.h>
 
 #include "IdentityCredentialStore.h"
+#include "PresentationSession.h"
 #include "SecureHardwareProxy.h"
 
 namespace aidl::android::hardware::identity {
@@ -46,11 +47,11 @@
 class IdentityCredential : public BnIdentityCredential {
   public:
     IdentityCredential(sp<SecureHardwareProxyFactory> hwProxyFactory,
-                       sp<SecureHardwarePresentationProxy> hwProxy,
-                       const vector<uint8_t>& credentialData)
+                       const vector<uint8_t>& credentialData,
+                       std::shared_ptr<PresentationSession> session)
         : hwProxyFactory_(hwProxyFactory),
-          hwProxy_(hwProxy),
           credentialData_(credentialData),
+          session_(std::move(session)),
           numStartRetrievalCalls_(0),
           expectedDeviceNameSpacesSize_(0) {}
 
@@ -94,10 +95,13 @@
                                               bool includeChallenge,
                                               vector<uint8_t>* outProofOfDeletionSignature);
 
+    // Creates and initializes hwProxy_.
+    ndk::ScopedAStatus ensureHwProxy();
+
     // Set by constructor
     sp<SecureHardwareProxyFactory> hwProxyFactory_;
-    sp<SecureHardwarePresentationProxy> hwProxy_;
     vector<uint8_t> credentialData_;
+    shared_ptr<PresentationSession> session_;
     int numStartRetrievalCalls_;
 
     // Set by initialize()
@@ -105,6 +109,9 @@
     bool testCredential_;
     vector<uint8_t> encryptedCredentialKeys_;
 
+    // Set by ensureHwProxy()
+    sp<SecureHardwarePresentationProxy> hwProxy_;
+
     // Set by createEphemeralKeyPair()
     vector<uint8_t> ephemeralPublicKey_;
 
diff --git a/identity/aidl/default/common/IdentityCredentialStore.cpp b/identity/aidl/default/common/IdentityCredentialStore.cpp
index e6b5466..4703ffe 100644
--- a/identity/aidl/default/common/IdentityCredentialStore.cpp
+++ b/identity/aidl/default/common/IdentityCredentialStore.cpp
@@ -20,6 +20,7 @@
 
 #include "IdentityCredential.h"
 #include "IdentityCredentialStore.h"
+#include "PresentationSession.h"
 #include "WritableIdentityCredential.h"
 
 namespace aidl::android::hardware::identity {
@@ -61,9 +62,8 @@
                 "Unsupported cipher suite"));
     }
 
-    sp<SecureHardwarePresentationProxy> hwProxy = hwProxyFactory_->createPresentationProxy();
-    shared_ptr<IdentityCredential> credential =
-            ndk::SharedRefBase::make<IdentityCredential>(hwProxyFactory_, hwProxy, credentialData);
+    shared_ptr<IdentityCredential> credential = ndk::SharedRefBase::make<IdentityCredential>(
+            hwProxyFactory_, credentialData, nullptr /* session */);
     auto ret = credential->initialize();
     if (ret != IIdentityCredentialStore::STATUS_OK) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -73,4 +73,25 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus IdentityCredentialStore::createPresentationSession(
+        CipherSuite cipherSuite, shared_ptr<IPresentationSession>* outSession) {
+    // We only support CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 right now.
+    if (cipherSuite != CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED,
+                "Unsupported cipher suite"));
+    }
+
+    sp<SecureHardwareSessionProxy> hwProxy = hwProxyFactory_->createSessionProxy();
+    shared_ptr<PresentationSession> session =
+            ndk::SharedRefBase::make<PresentationSession>(hwProxyFactory_, hwProxy);
+    auto ret = session->initialize();
+    if (ret != IIdentityCredentialStore::STATUS_OK) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                int(ret), "Error initializing PresentationSession"));
+    }
+    *outSession = session;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/common/IdentityCredentialStore.h b/identity/aidl/default/common/IdentityCredentialStore.h
index d35e632..77b894d 100644
--- a/identity/aidl/default/common/IdentityCredentialStore.h
+++ b/identity/aidl/default/common/IdentityCredentialStore.h
@@ -47,6 +47,9 @@
     ndk::ScopedAStatus getCredential(CipherSuite cipherSuite, const vector<uint8_t>& credentialData,
                                      shared_ptr<IIdentityCredential>* outCredential) override;
 
+    ndk::ScopedAStatus createPresentationSession(
+            CipherSuite cipherSuite, shared_ptr<IPresentationSession>* outSession) override;
+
   private:
     sp<SecureHardwareProxyFactory> hwProxyFactory_;
 };
diff --git a/identity/aidl/default/common/PresentationSession.cpp b/identity/aidl/default/common/PresentationSession.cpp
new file mode 100644
index 0000000..fbd8972
--- /dev/null
+++ b/identity/aidl/default/common/PresentationSession.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PresentationSession"
+
+#include "PresentationSession.h"
+#include "IdentityCredentialStore.h"
+
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include "FakeSecureHardwareProxy.h"
+#include "IdentityCredential.h"
+#include "PresentationSession.h"
+
+namespace aidl::android::hardware::identity {
+
+using ::std::optional;
+
+using namespace ::android::hardware::identity;
+
+PresentationSession::~PresentationSession() {}
+
+int PresentationSession::initialize() {
+    if (!hwProxy_->initialize()) {
+        LOG(ERROR) << "hwProxy->initialize failed";
+        return IIdentityCredentialStore::STATUS_FAILED;
+    }
+
+    optional<uint64_t> id = hwProxy_->getId();
+    if (!id) {
+        LOG(ERROR) << "Error getting id for session";
+        return IIdentityCredentialStore::STATUS_FAILED;
+    }
+    id_ = id.value();
+
+    optional<vector<uint8_t>> ephemeralKeyPriv = hwProxy_->getEphemeralKeyPair();
+    if (!ephemeralKeyPriv) {
+        LOG(ERROR) << "Error getting ephemeral private key for session";
+        return IIdentityCredentialStore::STATUS_FAILED;
+    }
+    optional<vector<uint8_t>> ephemeralKeyPair =
+            support::ecPrivateKeyToKeyPair(ephemeralKeyPriv.value());
+    if (!ephemeralKeyPair) {
+        LOG(ERROR) << "Error creating ephemeral key-pair";
+        return IIdentityCredentialStore::STATUS_FAILED;
+    }
+    ephemeralKeyPair_ = ephemeralKeyPair.value();
+
+    optional<uint64_t> authChallenge = hwProxy_->getAuthChallenge();
+    if (!authChallenge) {
+        LOG(ERROR) << "Error getting authChallenge for session";
+        return IIdentityCredentialStore::STATUS_FAILED;
+    }
+    authChallenge_ = authChallenge.value();
+
+    return IIdentityCredentialStore::STATUS_OK;
+}
+
+ndk::ScopedAStatus PresentationSession::getEphemeralKeyPair(vector<uint8_t>* outKeyPair) {
+    *outKeyPair = ephemeralKeyPair_;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PresentationSession::getAuthChallenge(int64_t* outChallenge) {
+    *outChallenge = authChallenge_;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PresentationSession::setReaderEphemeralPublicKey(
+        const vector<uint8_t>& publicKey) {
+    // We expect the reader ephemeral public key to be same size and curve
+    // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
+    // won't work. So its length should be 65 bytes and it should be
+    // starting with 0x04.
+    if (publicKey.size() != 65 || publicKey[0] != 0x04) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Reader public key is not in expected format"));
+    }
+    readerPublicKey_ = publicKey;
+    vector<uint8_t> pubKeyP256(publicKey.begin() + 1, publicKey.end());
+    if (!hwProxy_->setReaderEphemeralPublicKey(pubKeyP256)) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error setting readerEphemeralPublicKey for session"));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PresentationSession::setSessionTranscript(
+        const vector<uint8_t>& sessionTranscript) {
+    sessionTranscript_ = sessionTranscript;
+    if (!hwProxy_->setSessionTranscript(sessionTranscript)) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error setting SessionTranscript for session"));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PresentationSession::getCredential(
+        const vector<uint8_t>& credentialData, shared_ptr<IIdentityCredential>* outCredential) {
+    shared_ptr<PresentationSession> p = ref<PresentationSession>();
+    shared_ptr<IdentityCredential> credential =
+            ndk::SharedRefBase::make<IdentityCredential>(hwProxyFactory_, credentialData, p);
+    int ret = credential->initialize();
+    if (ret != IIdentityCredentialStore::STATUS_OK) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                ret, "Error initializing IdentityCredential"));
+    }
+    *outCredential = std::move(credential);
+
+    return ndk::ScopedAStatus::ok();
+}
+
+uint64_t PresentationSession::getSessionId() {
+    return id_;
+}
+
+vector<uint8_t> PresentationSession::getSessionTranscript() {
+    return sessionTranscript_;
+}
+
+vector<uint8_t> PresentationSession::getReaderEphemeralPublicKey() {
+    return readerPublicKey_;
+}
+
+}  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/common/PresentationSession.h b/identity/aidl/default/common/PresentationSession.h
new file mode 100644
index 0000000..76ca67b
--- /dev/null
+++ b/identity/aidl/default/common/PresentationSession.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_IDENTITY_PRESENTATIONSESSION_H
+#define ANDROID_HARDWARE_IDENTITY_PRESENTATIONSESSION_H
+
+#include <aidl/android/hardware/identity/BnPresentationSession.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <vector>
+
+#include <cppbor.h>
+
+#include "IdentityCredentialStore.h"
+#include "SecureHardwareProxy.h"
+
+namespace aidl::android::hardware::identity {
+
+using ::aidl::android::hardware::keymaster::HardwareAuthToken;
+using ::aidl::android::hardware::keymaster::VerificationToken;
+using ::android::sp;
+using ::android::hardware::identity::SecureHardwareSessionProxy;
+using ::std::vector;
+
+class PresentationSession : public BnPresentationSession {
+  public:
+    PresentationSession(sp<SecureHardwareProxyFactory> hwProxyFactory,
+                        sp<SecureHardwareSessionProxy> hwProxy)
+        : hwProxyFactory_(std::move(hwProxyFactory)), hwProxy_(std::move(hwProxy)) {}
+
+    virtual ~PresentationSession();
+
+    // Creates ephemeral key and auth-challenge in TA. Returns a status code from
+    // IIdentityCredentialStore. Must be called right after construction.
+    int initialize();
+
+    uint64_t getSessionId();
+
+    vector<uint8_t> getSessionTranscript();
+    vector<uint8_t> getReaderEphemeralPublicKey();
+
+    // Methods from IPresentationSession follow.
+    ndk::ScopedAStatus getEphemeralKeyPair(vector<uint8_t>* outKeyPair) override;
+    ndk::ScopedAStatus getAuthChallenge(int64_t* outChallenge) override;
+    ndk::ScopedAStatus setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) override;
+    ndk::ScopedAStatus setSessionTranscript(const vector<uint8_t>& sessionTranscript) override;
+
+    ndk::ScopedAStatus getCredential(const vector<uint8_t>& credentialData,
+                                     shared_ptr<IIdentityCredential>* outCredential) override;
+
+  private:
+    // Set by constructor
+    sp<SecureHardwareProxyFactory> hwProxyFactory_;
+    sp<SecureHardwareSessionProxy> hwProxy_;
+
+    // Set by initialize()
+    uint64_t id_;
+    vector<uint8_t> ephemeralKeyPair_;
+    uint64_t authChallenge_;
+
+    // Set by setReaderEphemeralPublicKey()
+    vector<uint8_t> readerPublicKey_;
+
+    // Set by setSessionTranscript()
+    vector<uint8_t> sessionTranscript_;
+};
+
+}  // namespace aidl::android::hardware::identity
+
+#endif  // ANDROID_HARDWARE_IDENTITY_PRESENTATIONSESSION_H
diff --git a/identity/aidl/default/common/SecureHardwareProxy.h b/identity/aidl/default/common/SecureHardwareProxy.h
index a1ed1ef..a580444 100644
--- a/identity/aidl/default/common/SecureHardwareProxy.h
+++ b/identity/aidl/default/common/SecureHardwareProxy.h
@@ -42,6 +42,7 @@
 // Forward declare.
 //
 class SecureHardwareProvisioningProxy;
+class SecureHardwareSessionProxy;
 class SecureHardwarePresentationProxy;
 
 // This is a class used to create proxies.
@@ -52,6 +53,7 @@
     virtual ~SecureHardwareProxyFactory() {}
 
     virtual sp<SecureHardwareProvisioningProxy> createProvisioningProxy() = 0;
+    virtual sp<SecureHardwareSessionProxy> createSessionProxy() = 0;
     virtual sp<SecureHardwarePresentationProxy> createPresentationProxy() = 0;
 };
 
@@ -64,8 +66,12 @@
 
     virtual bool initialize(bool testCredential) = 0;
 
-    virtual bool initializeForUpdate(bool testCredential, string docType,
-                                     vector<uint8_t> encryptedCredentialKeys) = 0;
+    virtual bool initializeForUpdate(bool testCredential, const string& docType,
+                                     const vector<uint8_t>& encryptedCredentialKeys) = 0;
+
+    virtual optional<uint32_t> getId() = 0;
+
+    virtual bool shutdown() = 0;
 
     // Returns public key certificate chain with attestation.
     //
@@ -76,7 +82,7 @@
     virtual optional<vector<uint8_t>> createCredentialKey(const vector<uint8_t>& challenge,
                                                           const vector<uint8_t>& applicationId) = 0;
 
-    virtual bool startPersonalization(int accessControlProfileCount, vector<int> entryCounts,
+    virtual bool startPersonalization(int accessControlProfileCount, const vector<int>& entryCounts,
                                       const string& docType,
                                       size_t expectedProofOfProvisioningSize) = 0;
 
@@ -98,8 +104,6 @@
 
     // Returns encryptedCredentialKeys (80 bytes).
     virtual optional<vector<uint8_t>> finishGetCredentialData(const string& docType) = 0;
-
-    virtual bool shutdown() = 0;
 };
 
 enum AccessCheckResult {
@@ -110,6 +114,30 @@
     kReaderAuthenticationFailed,
 };
 
+// The proxy used for sessions.
+//
+class SecureHardwareSessionProxy : public RefBase {
+  public:
+    SecureHardwareSessionProxy() {}
+
+    virtual ~SecureHardwareSessionProxy() {}
+
+    virtual bool initialize() = 0;
+
+    virtual optional<uint32_t> getId() = 0;
+
+    virtual bool shutdown() = 0;
+
+    virtual optional<uint64_t> getAuthChallenge() = 0;
+
+    // Returns private key
+    virtual optional<vector<uint8_t>> getEphemeralKeyPair() = 0;
+
+    virtual bool setReaderEphemeralPublicKey(const vector<uint8_t>& readerEphemeralPublicKey) = 0;
+
+    virtual bool setSessionTranscript(const vector<uint8_t>& sessionTranscript) = 0;
+};
+
 // The proxy used for presentation.
 //
 class SecureHardwarePresentationProxy : public RefBase {
@@ -117,12 +145,16 @@
     SecureHardwarePresentationProxy() {}
     virtual ~SecureHardwarePresentationProxy() {}
 
-    virtual bool initialize(bool testCredential, string docType,
-                            vector<uint8_t> encryptedCredentialKeys) = 0;
+    virtual bool initialize(uint32_t sessionId, bool testCredential, const string& docType,
+                            const vector<uint8_t>& encryptedCredentialKeys) = 0;
+
+    virtual optional<uint32_t> getId() = 0;
+
+    virtual bool shutdown() = 0;
 
     // Returns publicKeyCert (1st component) and signingKeyBlob (2nd component)
-    virtual optional<pair<vector<uint8_t>, vector<uint8_t>>> generateSigningKeyPair(string docType,
-                                                                                    time_t now) = 0;
+    virtual optional<pair<vector<uint8_t>, vector<uint8_t>>> generateSigningKeyPair(
+            const string& docType, time_t now) = 0;
 
     // Returns private key
     virtual optional<vector<uint8_t>> createEphemeralKeyPair() = 0;
@@ -174,8 +206,6 @@
     virtual optional<vector<uint8_t>> proveOwnership(const string& docType, bool testCredential,
                                                      const vector<uint8_t>& challenge,
                                                      size_t proofOfOwnershipCborSize) = 0;
-
-    virtual bool shutdown() = 0;
 };
 
 }  // namespace android::hardware::identity
diff --git a/identity/aidl/default/identity-default.xml b/identity/aidl/default/identity-default.xml
index a074250..cc0ddc7 100644
--- a/identity/aidl/default/identity-default.xml
+++ b/identity/aidl/default/identity-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.identity</name>
-        <version>3</version>
+        <version>4</version>
         <interface>
             <name>IIdentityCredentialStore</name>
             <instance>default</instance>
diff --git a/identity/aidl/default/libeic/EicCommon.h b/identity/aidl/default/libeic/EicCommon.h
index 476276e..2a08a35 100644
--- a/identity/aidl/default/libeic/EicCommon.h
+++ b/identity/aidl/default/libeic/EicCommon.h
@@ -21,6 +21,9 @@
 #ifndef ANDROID_HARDWARE_IDENTITY_EIC_COMMON_H
 #define ANDROID_HARDWARE_IDENTITY_EIC_COMMON_H
 
+// KeyMint auth-challenges are 64-bit numbers and 0 typically means unset.
+#define EIC_KM_AUTH_CHALLENGE_UNSET 0
+
 // Feature version 202009:
 //
 //         CredentialKeys = [
diff --git a/identity/aidl/default/libeic/EicOps.h b/identity/aidl/default/libeic/EicOps.h
index d4fcf0e..aa26e62 100644
--- a/identity/aidl/default/libeic/EicOps.h
+++ b/identity/aidl/default/libeic/EicOps.h
@@ -141,6 +141,10 @@
 // String length, see strlen(3).
 size_t eicStrLen(const char* s);
 
+// Locate a substring, see memmem(3)
+void* eicMemMem(const uint8_t* haystack, size_t haystackLen, const uint8_t* needle,
+                size_t needleLen);
+
 // Memory compare, see CRYPTO_memcmp(3SSL)
 //
 // It takes an amount of time dependent on len, but independent of the contents of the
@@ -151,6 +155,12 @@
 // Random number generation.
 bool eicOpsRandom(uint8_t* buf, size_t numBytes);
 
+// Creates a new non-zero identifier in |id|.
+//
+// Is guaranteed to be non-zero and different than what is already in |id|.
+//
+bool eicNextId(uint32_t* id);
+
 // If |testCredential| is true, returns the 128-bit AES Hardware-Bound Key (16 bytes).
 //
 // Otherwise returns all zeroes (16 bytes).
@@ -295,6 +305,8 @@
                              int verificationTokenSecurityLevel,
                              const uint8_t* verificationTokenMac, size_t verificationTokenMacSize);
 
+// Also see eicOpsLookupActiveSessionFromId() defined in EicSession.h
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c
index 0d03ae9..104a559 100644
--- a/identity/aidl/default/libeic/EicPresentation.c
+++ b/identity/aidl/default/libeic/EicPresentation.c
@@ -16,11 +16,17 @@
 
 #include "EicPresentation.h"
 #include "EicCommon.h"
+#include "EicSession.h"
 
 #include <inttypes.h>
 
-bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType,
-                         size_t docTypeLength, const uint8_t* encryptedCredentialKeys,
+// Global used for assigning ids for presentation objects.
+//
+static uint32_t gPresentationLastIdAssigned = 0;
+
+bool eicPresentationInit(EicPresentation* ctx, uint32_t sessionId, bool testCredential,
+                         const char* docType, size_t docTypeLength,
+                         const uint8_t* encryptedCredentialKeys,
                          size_t encryptedCredentialKeysSize) {
     uint8_t credentialKeys[EIC_CREDENTIAL_KEYS_CBOR_SIZE_FEATURE_VERSION_202101];
     bool expectPopSha256 = false;
@@ -39,6 +45,13 @@
     }
 
     eicMemSet(ctx, '\0', sizeof(EicPresentation));
+    ctx->sessionId = sessionId;
+
+    if (!eicNextId(&gPresentationLastIdAssigned)) {
+        eicDebug("Error getting id for object");
+        return false;
+    }
+    ctx->id = gPresentationLastIdAssigned;
 
     if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys,
                                 encryptedCredentialKeysSize,
@@ -86,6 +99,23 @@
     if (expectPopSha256) {
         eicMemCpy(ctx->proofOfProvisioningSha256, credentialKeys + 54, EIC_SHA256_DIGEST_SIZE);
     }
+
+    eicDebug("Initialized presentation with id %" PRIu32, ctx->id);
+    return true;
+}
+
+bool eicPresentationShutdown(EicPresentation* ctx) {
+    if (ctx->id == 0) {
+        eicDebug("Trying to shut down presentation with id 0");
+        return false;
+    }
+    eicDebug("Shut down presentation with id %" PRIu32, ctx->id);
+    eicMemSet(ctx, '\0', sizeof(EicPresentation));
+    return true;
+}
+
+bool eicPresentationGetId(EicPresentation* ctx, uint32_t* outId) {
+    *outId = ctx->id;
     return true;
 }
 
@@ -174,7 +204,7 @@
             eicDebug("Failed generating random challenge");
             return false;
         }
-    } while (ctx->authChallenge == 0);
+    } while (ctx->authChallenge == EIC_KM_AUTH_CHALLENGE_UNSET);
     eicDebug("Created auth challenge %" PRIu64, ctx->authChallenge);
     *authChallenge = ctx->authChallenge;
     return true;
@@ -190,6 +220,24 @@
                                            int coseSignAlg,
                                            const uint8_t* readerSignatureOfToBeSigned,
                                            size_t readerSignatureOfToBeSignedSize) {
+    if (ctx->sessionId != 0) {
+        EicSession* session = eicSessionGetForId(ctx->sessionId);
+        if (session == NULL) {
+            eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+            return false;
+        }
+        EicSha256Ctx sha256;
+        uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+        eicOpsSha256Init(&sha256);
+        eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
+        eicOpsSha256Final(&sha256, sessionTranscriptSha256);
+        if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
+                            EIC_SHA256_DIGEST_SIZE) != 0) {
+            eicDebug("SessionTranscript mismatch");
+            return false;
+        }
+    }
+
     if (ctx->readerPublicKeySize == 0) {
         eicDebug("No public key for reader");
         return false;
@@ -330,6 +378,20 @@
     return true;
 }
 
+static bool getChallenge(EicPresentation* ctx, uint64_t* outAuthChallenge) {
+    // Use authChallenge from session if applicable.
+    *outAuthChallenge = ctx->authChallenge;
+    if (ctx->sessionId != 0) {
+        EicSession* session = eicSessionGetForId(ctx->sessionId);
+        if (session == NULL) {
+            eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+            return false;
+        }
+        *outAuthChallenge = session->authChallenge;
+    }
+    return true;
+}
+
 bool eicPresentationSetAuthToken(EicPresentation* ctx, uint64_t challenge, uint64_t secureUserId,
                                  uint64_t authenticatorId, int hardwareAuthenticatorType,
                                  uint64_t timeStamp, const uint8_t* mac, size_t macSize,
@@ -338,14 +400,19 @@
                                  int verificationTokenSecurityLevel,
                                  const uint8_t* verificationTokenMac,
                                  size_t verificationTokenMacSize) {
+    uint64_t authChallenge;
+    if (!getChallenge(ctx, &authChallenge)) {
+        return false;
+    }
+
     // It doesn't make sense to accept any tokens if eicPresentationCreateAuthChallenge()
     // was never called.
-    if (ctx->authChallenge == 0) {
-        eicDebug("Trying validate tokens when no auth-challenge was previously generated");
+    if (authChallenge == EIC_KM_AUTH_CHALLENGE_UNSET) {
+        eicDebug("Trying to validate tokens when no auth-challenge was previously generated");
         return false;
     }
     // At least the verification-token must have the same challenge as what was generated.
-    if (verificationTokenChallenge != ctx->authChallenge) {
+    if (verificationTokenChallenge != authChallenge) {
         eicDebug("Challenge in verification token does not match the challenge "
                  "previously generated");
         return false;
@@ -354,6 +421,7 @@
                 challenge, secureUserId, authenticatorId, hardwareAuthenticatorType, timeStamp, mac,
                 macSize, verificationTokenChallenge, verificationTokenTimestamp,
                 verificationTokenSecurityLevel, verificationTokenMac, verificationTokenMacSize)) {
+        eicDebug("Error validating authToken");
         return false;
     }
     ctx->authTokenChallenge = challenge;
@@ -377,11 +445,16 @@
     // Only ACP with auth-on-every-presentation - those with timeout == 0 - need the
     // challenge to match...
     if (timeoutMillis == 0) {
-        if (ctx->authTokenChallenge != ctx->authChallenge) {
+        uint64_t authChallenge;
+        if (!getChallenge(ctx, &authChallenge)) {
+            return false;
+        }
+
+        if (ctx->authTokenChallenge != authChallenge) {
             eicDebug("Challenge in authToken (%" PRIu64
                      ") doesn't match the challenge "
                      "that was created (%" PRIu64 ") for this session",
-                     ctx->authTokenChallenge, ctx->authChallenge);
+                     ctx->authTokenChallenge, authChallenge);
             return false;
         }
     }
@@ -490,6 +563,25 @@
                                const uint8_t signingKeyBlob[60], const char* docType,
                                size_t docTypeLength, unsigned int numNamespacesWithValues,
                                size_t expectedDeviceNamespacesSize) {
+    if (ctx->sessionId != 0) {
+        EicSession* session = eicSessionGetForId(ctx->sessionId);
+        if (session == NULL) {
+            eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+            return false;
+        }
+        EicSha256Ctx sha256;
+        uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+        eicOpsSha256Init(&sha256);
+        eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
+        eicOpsSha256Final(&sha256, sessionTranscriptSha256);
+        if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
+                            EIC_SHA256_DIGEST_SIZE) != 0) {
+            eicDebug("SessionTranscript mismatch");
+            return false;
+        }
+        readerEphemeralPublicKey = session->readerEphemeralPublicKey;
+    }
+
     uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
     if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
                                 docTypeLength, signingKeyPriv)) {
diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h
index 6f7f432..a031890 100644
--- a/identity/aidl/default/libeic/EicPresentation.h
+++ b/identity/aidl/default/libeic/EicPresentation.h
@@ -30,7 +30,13 @@
 // The maximum size we support for public keys in reader certificates.
 #define EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE 65
 
+// Constant used to convey that no session is associated with a presentation.
+#define EIC_PRESENTATION_ID_UNSET 0
+
 typedef struct {
+    // A non-zero number unique for this EicPresentation instance
+    uint32_t id;
+
     int featureLevel;
 
     uint8_t storageKey[EIC_AES_128_KEY_SIZE];
@@ -38,6 +44,10 @@
 
     uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE];
 
+    // If non-zero (not EIC_PRESENTATION_ID_UNSET), the id of the EicSession object this
+    // presentation object is associated with.
+    uint32_t sessionId;
+
     // The challenge generated with eicPresentationCreateAuthChallenge()
     uint64_t authChallenge;
 
@@ -93,10 +103,18 @@
     EicCbor cbor;
 } EicPresentation;
 
-bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType,
-                         size_t docTypeLength, const uint8_t* encryptedCredentialKeys,
+// If sessionId is zero (EIC_PRESENTATION_ID_UNSET), the presentation object is not associated
+// with a session object. Otherwise it's the id of the session object.
+//
+bool eicPresentationInit(EicPresentation* ctx, uint32_t sessionId, bool testCredential,
+                         const char* docType, size_t docTypeLength,
+                         const uint8_t* encryptedCredentialKeys,
                          size_t encryptedCredentialKeysSize);
 
+bool eicPresentationShutdown(EicPresentation* ctx);
+
+bool eicPresentationGetId(EicPresentation* ctx, uint32_t* outId);
+
 bool eicPresentationGenerateSigningKeyPair(EicPresentation* ctx, const char* docType,
                                            size_t docTypeLength, time_t now,
                                            uint8_t* publicKeyCert, size_t* publicKeyCertSize,
diff --git a/identity/aidl/default/libeic/EicProvisioning.c b/identity/aidl/default/libeic/EicProvisioning.c
index c9df4fd..a241b71 100644
--- a/identity/aidl/default/libeic/EicProvisioning.c
+++ b/identity/aidl/default/libeic/EicProvisioning.c
@@ -17,8 +17,21 @@
 #include "EicProvisioning.h"
 #include "EicCommon.h"
 
+#include <inttypes.h>
+
+// Global used for assigning ids for provisioning objects.
+//
+static uint32_t gProvisioningLastIdAssigned = 0;
+
 bool eicProvisioningInit(EicProvisioning* ctx, bool testCredential) {
     eicMemSet(ctx, '\0', sizeof(EicProvisioning));
+
+    if (!eicNextId(&gProvisioningLastIdAssigned)) {
+        eicDebug("Error getting id for object");
+        return false;
+    }
+    ctx->id = gProvisioningLastIdAssigned;
+
     ctx->testCredential = testCredential;
     if (!eicOpsRandom(ctx->storageKey, EIC_AES_128_KEY_SIZE)) {
         return false;
@@ -47,6 +60,13 @@
     }
 
     eicMemSet(ctx, '\0', sizeof(EicProvisioning));
+
+    if (!eicNextId(&gProvisioningLastIdAssigned)) {
+        eicDebug("Error getting id for object");
+        return false;
+    }
+    ctx->id = gProvisioningLastIdAssigned;
+
     ctx->testCredential = testCredential;
 
     if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys,
@@ -96,6 +116,21 @@
     return true;
 }
 
+bool eicProvisioningShutdown(EicProvisioning* ctx) {
+    if (ctx->id == 0) {
+        eicDebug("Trying to shut down provsioning with id 0");
+        return false;
+    }
+    eicDebug("Shut down provsioning with id %" PRIu32, ctx->id);
+    eicMemSet(ctx, '\0', sizeof(EicProvisioning));
+    return true;
+}
+
+bool eicProvisioningGetId(EicProvisioning* ctx, uint32_t* outId) {
+    *outId = ctx->id;
+    return true;
+}
+
 bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
                                         size_t challengeSize, const uint8_t* applicationId,
                                         size_t applicationIdSize, uint8_t* publicKeyCert,
diff --git a/identity/aidl/default/libeic/EicProvisioning.h b/identity/aidl/default/libeic/EicProvisioning.h
index 92f1e4a..d94f8f1 100644
--- a/identity/aidl/default/libeic/EicProvisioning.h
+++ b/identity/aidl/default/libeic/EicProvisioning.h
@@ -31,6 +31,9 @@
 #define EIC_MAX_NUM_ACCESS_CONTROL_PROFILE_IDS 32
 
 typedef struct {
+    // A non-zero number unique for this EicProvisioning instance
+    uint32_t id;
+
     // Set by eicCreateCredentialKey() OR eicProvisioningInitForUpdate()
     uint8_t credentialPrivateKey[EIC_P256_PRIV_KEY_SIZE];
 
@@ -68,6 +71,10 @@
                                   size_t docTypeLength, const uint8_t* encryptedCredentialKeys,
                                   size_t encryptedCredentialKeysSize);
 
+bool eicProvisioningShutdown(EicProvisioning* ctx);
+
+bool eicProvisioningGetId(EicProvisioning* ctx, uint32_t* outId);
+
 bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
                                         size_t challengeSize, const uint8_t* applicationId,
                                         size_t applicationIdSize, uint8_t* publicKeyCert,
diff --git a/identity/aidl/default/libeic/EicSession.c b/identity/aidl/default/libeic/EicSession.c
new file mode 100644
index 0000000..d0c7a0d
--- /dev/null
+++ b/identity/aidl/default/libeic/EicSession.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#include "EicCommon.h"
+#include "EicSession.h"
+
+// Global used for assigning ids for session objects.
+//
+static uint32_t gSessionLastIdAssigned = 0;
+
+// The current session object or NULL if never initialized or if it has been shut down.
+//
+static EicSession* gSessionCurrent = NULL;
+
+EicSession* eicSessionGetForId(uint32_t sessionId) {
+    if (gSessionCurrent != NULL && gSessionCurrent->id == sessionId) {
+        return gSessionCurrent;
+    }
+    return NULL;
+}
+
+bool eicSessionInit(EicSession* ctx) {
+    eicMemSet(ctx, '\0', sizeof(EicSession));
+
+    if (!eicNextId(&gSessionLastIdAssigned)) {
+        eicDebug("Error getting id for object");
+        return false;
+    }
+    ctx->id = gSessionLastIdAssigned;
+
+    do {
+        if (!eicOpsRandom((uint8_t*)&(ctx->authChallenge), sizeof(ctx->authChallenge))) {
+            eicDebug("Failed generating random challenge");
+            return false;
+        }
+    } while (ctx->authChallenge == EIC_KM_AUTH_CHALLENGE_UNSET);
+
+    if (!eicOpsCreateEcKey(ctx->ephemeralPrivateKey, ctx->ephemeralPublicKey)) {
+        eicDebug("Error creating ephemeral key-pair");
+        return false;
+    }
+
+    gSessionCurrent = ctx;
+    eicDebug("Initialized session with id %" PRIu32, ctx->id);
+    return true;
+}
+
+bool eicSessionShutdown(EicSession* ctx) {
+    if (ctx->id == 0) {
+        eicDebug("Trying to shut down session with id 0");
+        return false;
+    }
+    eicDebug("Shut down session with id %" PRIu32, ctx->id);
+    eicMemSet(ctx, '\0', sizeof(EicSession));
+    gSessionCurrent = NULL;
+    return true;
+}
+
+bool eicSessionGetId(EicSession* ctx, uint32_t* outId) {
+    *outId = ctx->id;
+    return true;
+}
+
+bool eicSessionGetAuthChallenge(EicSession* ctx, uint64_t* outAuthChallenge) {
+    *outAuthChallenge = ctx->authChallenge;
+    return true;
+}
+
+bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
+                                   uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]) {
+    eicMemCpy(ephemeralPrivateKey, ctx->ephemeralPrivateKey, EIC_P256_PRIV_KEY_SIZE);
+    return true;
+}
+
+bool eicSessionSetReaderEphemeralPublicKey(
+        EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]) {
+    eicMemCpy(ctx->readerEphemeralPublicKey, readerEphemeralPublicKey, EIC_P256_PUB_KEY_SIZE);
+    return true;
+}
+
+bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
+                                    size_t sessionTranscriptSize) {
+    // Only accept the SessionTranscript if X and Y from the ephemeral key
+    // we created is somewhere in SessionTranscript...
+    //
+    if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
+                  EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+        eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
+        return false;
+    }
+    if (eicMemMem(sessionTranscript, sessionTranscriptSize,
+                  ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
+                  EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+        eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
+        return false;
+    }
+
+    // To save space we only store the SHA-256 of SessionTranscript
+    //
+    EicSha256Ctx shaCtx;
+    eicOpsSha256Init(&shaCtx);
+    eicOpsSha256Update(&shaCtx, sessionTranscript, sessionTranscriptSize);
+    eicOpsSha256Final(&shaCtx, ctx->sessionTranscriptSha256);
+    return true;
+}
diff --git a/identity/aidl/default/libeic/EicSession.h b/identity/aidl/default/libeic/EicSession.h
new file mode 100644
index 0000000..0303dae
--- /dev/null
+++ b/identity/aidl/default/libeic/EicSession.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(EIC_INSIDE_LIBEIC_H) && !defined(EIC_COMPILATION)
+#error "Never include this file directly, include libeic.h instead."
+#endif
+
+#ifndef ANDROID_HARDWARE_IDENTITY_EIC_SESSION_H
+#define ANDROID_HARDWARE_IDENTITY_EIC_SESSION_H
+
+#include "EicOps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    // A non-zero number unique for this EicSession instance
+    uint32_t id;
+
+    // The challenge generated at construction time by eicSessionInit().
+    uint64_t authChallenge;
+
+    uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE];
+    uint8_t ephemeralPublicKey[EIC_P256_PUB_KEY_SIZE];
+
+    uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE];
+
+    uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+
+} EicSession;
+
+bool eicSessionInit(EicSession* ctx);
+
+bool eicSessionShutdown(EicSession* ctx);
+
+bool eicSessionGetId(EicSession* ctx, uint32_t* outId);
+
+bool eicSessionGetAuthChallenge(EicSession* ctx, uint64_t* outAuthChallenge);
+
+bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
+                                   uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]);
+
+bool eicSessionSetReaderEphemeralPublicKey(
+        EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]);
+
+bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
+                                    size_t sessionTranscriptSize);
+
+// Looks up an active session with the given id.
+//
+// Returns NULL if no active session with the given id is found.
+//
+EicSession* eicSessionGetForId(uint32_t sessionId);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // ANDROID_HARDWARE_IDENTITY_EIC_PRESENTATION_H
diff --git a/identity/aidl/default/libeic/libeic.h b/identity/aidl/default/libeic/libeic.h
index 20c8896..d89fc9a 100644
--- a/identity/aidl/default/libeic/libeic.h
+++ b/identity/aidl/default/libeic/libeic.h
@@ -27,10 +27,11 @@
  */
 #define EIC_INSIDE_LIBEIC_H
 #include "EicCbor.h"
+#include "EicCommon.h"
 #include "EicOps.h"
 #include "EicPresentation.h"
 #include "EicProvisioning.h"
-#include "EicCommon.h"
+#include "EicSession.h"
 #undef EIC_INSIDE_LIBEIC_H
 
 #ifdef __cplusplus
diff --git a/identity/aidl/default/service.cpp b/identity/aidl/default/service.cpp
index c290c08..78f4fbc 100644
--- a/identity/aidl/default/service.cpp
+++ b/identity/aidl/default/service.cpp
@@ -43,7 +43,7 @@
 
     const std::string instance = std::string() + IdentityCredentialStore::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(store->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index e5de91e..7b6f2c8 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -28,6 +28,7 @@
         "EndToEndTests.cpp",
         "TestCredentialTests.cpp",
         "AuthenticationKeyTests.cpp",
+        "PresentationSessionTests.cpp",
     ],
     shared_libs: [
         "libbinder",
@@ -40,9 +41,9 @@
         "libpuresoftkeymasterdevice",
         "android.hardware.keymaster@4.0",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-V3-cpp",
-        "android.hardware.keymaster-V3-cpp",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.identity-V4-cpp",
+        "android.hardware.keymaster-V4-cpp",
+        "android.hardware.keymaster-V4-ndk",
         "libkeymaster4support",
         "libkeymaster4_1support",
     ],
diff --git a/identity/aidl/vts/PresentationSessionTests.cpp b/identity/aidl/vts/PresentationSessionTests.cpp
new file mode 100644
index 0000000..88acb26
--- /dev/null
+++ b/identity/aidl/vts/PresentationSessionTests.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PresentationSessionTests"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
+#include <aidl/android/hardware/keymaster/VerificationToken.h>
+#include <android-base/logging.h>
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
+#include <gtest/gtest.h>
+#include <future>
+#include <map>
+#include <utility>
+
+#include "Util.h"
+
+namespace android::hardware::identity {
+
+using std::endl;
+using std::make_pair;
+using std::map;
+using std::optional;
+using std::pair;
+using std::string;
+using std::tie;
+using std::vector;
+
+using ::android::sp;
+using ::android::String16;
+using ::android::binder::Status;
+
+using ::android::hardware::keymaster::HardwareAuthToken;
+using ::android::hardware::keymaster::VerificationToken;
+
+class PresentationSessionTests : public testing::TestWithParam<string> {
+  public:
+    virtual void SetUp() override {
+        credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
+                String16(GetParam().c_str()));
+        ASSERT_NE(credentialStore_, nullptr);
+        halApiVersion_ = credentialStore_->getInterfaceVersion();
+    }
+
+    void provisionData();
+
+    void provisionSingleDocument(const string& docType, vector<uint8_t>* outCredentialData,
+                                 vector<uint8_t>* outCredentialPubKey);
+
+    // Set by provisionData
+    vector<uint8_t> credential1Data_;
+    vector<uint8_t> credential1PubKey_;
+    vector<uint8_t> credential2Data_;
+    vector<uint8_t> credential2PubKey_;
+
+    sp<IIdentityCredentialStore> credentialStore_;
+    int halApiVersion_;
+};
+
+void PresentationSessionTests::provisionData() {
+    provisionSingleDocument("org.iso.18013-5.2019.mdl", &credential1Data_, &credential1PubKey_);
+    provisionSingleDocument("org.blah.OtherhDocTypeXX", &credential2Data_, &credential2PubKey_);
+}
+
+void PresentationSessionTests::provisionSingleDocument(const string& docType,
+                                                       vector<uint8_t>* outCredentialData,
+                                                       vector<uint8_t>* outCredentialPubKey) {
+    bool testCredential = true;
+    sp<IWritableIdentityCredential> wc;
+    ASSERT_TRUE(credentialStore_->createCredential(docType, testCredential, &wc).isOk());
+
+    vector<uint8_t> attestationApplicationId;
+    vector<uint8_t> attestationChallenge = {1};
+    vector<Certificate> certChain;
+    ASSERT_TRUE(wc->getAttestationCertificate(attestationApplicationId, attestationChallenge,
+                                              &certChain)
+                        .isOk());
+
+    optional<vector<uint8_t>> optCredentialPubKey =
+            support::certificateChainGetTopMostKey(certChain[0].encodedCertificate);
+    ASSERT_TRUE(optCredentialPubKey);
+    *outCredentialPubKey = optCredentialPubKey.value();
+
+    size_t proofOfProvisioningSize = 106;
+    // Not in v1 HAL, may fail
+    wc->setExpectedProofOfProvisioningSize(proofOfProvisioningSize);
+
+    ASSERT_TRUE(wc->startPersonalization(1 /* numAccessControlProfiles */,
+                                         {1} /* numDataElementsPerNamespace */)
+                        .isOk());
+
+    // Access control profile 0: open access - don't care about the returned SACP
+    SecureAccessControlProfile sacp;
+    ASSERT_TRUE(wc->addAccessControlProfile(1, {}, false, 0, 0, &sacp).isOk());
+
+    // Single entry - don't care about the returned encrypted data
+    ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "Some Data", 1).isOk());
+    vector<uint8_t> encryptedData;
+    ASSERT_TRUE(wc->addEntryValue({9}, &encryptedData).isOk());
+
+    vector<uint8_t> proofOfProvisioningSignature;
+    Status status = wc->finishAddingEntries(outCredentialData, &proofOfProvisioningSignature);
+    EXPECT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
+}
+
+// This checks that any methods called on an IIdentityCredential obtained via a session
+// returns STATUS_FAILED except for startRetrieval(), startRetrieveEntryValue(),
+// retrieveEntryValue(), finishRetrieval(), setRequestedNamespaces(), setVerificationToken()
+//
+TEST_P(PresentationSessionTests, returnsFailureOnUnsupportedMethods) {
+    if (halApiVersion_ < 4) {
+        GTEST_SKIP() << "Need HAL API version 4, have " << halApiVersion_;
+    }
+
+    provisionData();
+
+    sp<IPresentationSession> session;
+    ASSERT_TRUE(credentialStore_
+                        ->createPresentationSession(
+                                CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
+                                &session)
+                        .isOk());
+
+    sp<IIdentityCredential> credential;
+    ASSERT_TRUE(session->getCredential(credential1Data_, &credential).isOk());
+
+    Status result;
+
+    vector<uint8_t> signatureProofOfDeletion;
+    result = credential->deleteCredential(&signatureProofOfDeletion);
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+
+    vector<uint8_t> ephemeralKeyPair;
+    result = credential->createEphemeralKeyPair(&ephemeralKeyPair);
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+
+    result = credential->setReaderEphemeralPublicKey({});
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+
+    int64_t authChallenge;
+    result = credential->createAuthChallenge(&authChallenge);
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+
+    Certificate certificate;
+    vector<uint8_t> signingKeyBlob;
+    result = credential->generateSigningKeyPair(&signingKeyBlob, &certificate);
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+
+    result = credential->deleteCredentialWithChallenge({}, &signatureProofOfDeletion);
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+
+    vector<uint8_t> signatureProofOfOwnership;
+    result = credential->proveOwnership({}, &signatureProofOfOwnership);
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+
+    sp<IWritableIdentityCredential> writableCredential;
+    result = credential->updateCredential(&writableCredential);
+    EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
+    EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
+}
+
+// TODO: need to add tests to check that the returned IIdentityCredential works
+//       as intended.
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresentationSessionTests);
+INSTANTIATE_TEST_SUITE_P(
+        Identity, PresentationSessionTests,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
+        android::PrintInstanceNameToString);
+
+}  // namespace android::hardware::identity
diff --git a/input/classifier/1.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp
index 58945d3..5ff1457 100644
--- a/input/classifier/1.0/vts/functional/Android.bp
+++ b/input/classifier/1.0/vts/functional/Android.bp
@@ -30,7 +30,10 @@
         ":inputconstants_aidl",
         "VtsHalInputClassifierV1_0TargetTest.cpp",
     ],
-    header_libs: ["jni_headers"],
+    header_libs: [
+        "jni_headers",
+        "libbinder_headers",
+    ],
     static_libs: [
         "android.hardware.input.classifier@1.0",
         "android.hardware.input.common@1.0",
diff --git a/input/common/aidl/Android.bp b/input/common/aidl/Android.bp
new file mode 100644
index 0000000..6cf64a6
--- /dev/null
+++ b/input/common/aidl/Android.bp
@@ -0,0 +1,22 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.input.common",
+    srcs: ["android/hardware/input/common/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+    },
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Action.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Action.aidl
new file mode 100644
index 0000000..a2e0381
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Action.aidl
@@ -0,0 +1,50 @@
+/*
+ * 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.input.common;
+@Backing(type="int") @VintfStability
+enum Action {
+  DOWN = 0,
+  UP = 1,
+  MOVE = 2,
+  CANCEL = 3,
+  OUTSIDE = 4,
+  POINTER_DOWN = 5,
+  POINTER_UP = 6,
+  HOVER_MOVE = 7,
+  SCROLL = 8,
+  HOVER_ENTER = 9,
+  HOVER_EXIT = 10,
+  BUTTON_PRESS = 11,
+  BUTTON_RELEASE = 12,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Axis.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Axis.aidl
new file mode 100644
index 0000000..2114c7d
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Axis.aidl
@@ -0,0 +1,82 @@
+/*
+ * 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.input.common;
+@Backing(type="int") @VintfStability
+enum Axis {
+  X = 0,
+  Y = 1,
+  PRESSURE = 2,
+  SIZE = 3,
+  TOUCH_MAJOR = 4,
+  TOUCH_MINOR = 5,
+  TOOL_MAJOR = 6,
+  TOOL_MINOR = 7,
+  ORIENTATION = 8,
+  VSCROLL = 9,
+  HSCROLL = 10,
+  Z = 11,
+  RX = 12,
+  RY = 13,
+  RZ = 14,
+  HAT_X = 15,
+  HAT_Y = 16,
+  LTRIGGER = 17,
+  RTRIGGER = 18,
+  THROTTLE = 19,
+  RUDDER = 20,
+  WHEEL = 21,
+  GAS = 22,
+  BRAKE = 23,
+  DISTANCE = 24,
+  TILT = 25,
+  SCROLL = 26,
+  RELATIVE_X = 27,
+  RELATIVE_Y = 28,
+  GENERIC_1 = 32,
+  GENERIC_2 = 33,
+  GENERIC_3 = 34,
+  GENERIC_4 = 35,
+  GENERIC_5 = 36,
+  GENERIC_6 = 37,
+  GENERIC_7 = 38,
+  GENERIC_8 = 39,
+  GENERIC_9 = 40,
+  GENERIC_10 = 41,
+  GENERIC_11 = 42,
+  GENERIC_12 = 43,
+  GENERIC_13 = 44,
+  GENERIC_14 = 45,
+  GENERIC_15 = 46,
+  GENERIC_16 = 47,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Button.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Button.aidl
new file mode 100644
index 0000000..10ad65a
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Button.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.input.common;
+@Backing(type="int") @VintfStability
+enum Button {
+  NONE = 0,
+  PRIMARY = 1,
+  SECONDARY = 2,
+  TERTIARY = 4,
+  BACK = 8,
+  FORWARD = 16,
+  STYLUS_PRIMARY = 32,
+  STYLUS_SECONDARY = 64,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Classification.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Classification.aidl
new file mode 100644
index 0000000..ddd5246
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Classification.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.input.common;
+@Backing(type="byte") @VintfStability
+enum Classification {
+  NONE = 0,
+  AMBIGUOUS_GESTURE = 1,
+  DEEP_PRESS = 2,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/EdgeFlag.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/EdgeFlag.aidl
new file mode 100644
index 0000000..1040049
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/EdgeFlag.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.input.common;
+@Backing(type="int") @VintfStability
+enum EdgeFlag {
+  NONE = 0,
+  TOP = 1,
+  BOTTOM = 2,
+  LEFT = 4,
+  RIGHT = 8,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Flag.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Flag.aidl
new file mode 100644
index 0000000..d3fcd9f
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Flag.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.input.common;
+@Backing(type="int") @VintfStability
+enum Flag {
+  WINDOW_IS_OBSCURED = 1,
+  IS_GENERATED_GESTURE = 8,
+  TAINTED = -2147483648,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Meta.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Meta.aidl
new file mode 100644
index 0000000..2c229f9
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Meta.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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.input.common;
+@Backing(type="int") @VintfStability
+enum Meta {
+  NONE = 0,
+  ALT_ON = 2,
+  ALT_LEFT_ON = 16,
+  ALT_RIGHT_ON = 32,
+  SHIFT_ON = 1,
+  SHIFT_LEFT_ON = 64,
+  SHIFT_RIGHT_ON = 128,
+  SYM_ON = 4,
+  FUNCTION_ON = 8,
+  CTRL_ON = 4096,
+  CTRL_LEFT_ON = 8192,
+  CTRL_RIGHT_ON = 16384,
+  META_ON = 65536,
+  META_LEFT_ON = 131072,
+  META_RIGHT_ON = 262144,
+  CAPS_LOCK_ON = 1048576,
+  NUM_LOCK_ON = 2097152,
+  SCROLL_LOCK_ON = 4194304,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/MotionEvent.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/MotionEvent.aidl
new file mode 100644
index 0000000..84af4bf
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/MotionEvent.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.input.common;
+@VintfStability
+parcelable MotionEvent {
+  int deviceId;
+  android.hardware.input.common.Source source;
+  int displayId;
+  long downTime;
+  long eventTime;
+  android.hardware.input.common.Action action;
+  byte actionIndex;
+  android.hardware.input.common.Button actionButton;
+  android.hardware.input.common.Flag flags;
+  android.hardware.input.common.PolicyFlag policyFlags;
+  android.hardware.input.common.EdgeFlag edgeFlags;
+  android.hardware.input.common.Meta metaState;
+  android.hardware.input.common.Button buttonState;
+  float xPrecision;
+  float yPrecision;
+  android.hardware.input.common.PointerProperties[] pointerProperties;
+  android.hardware.input.common.PointerCoords[] pointerCoords;
+  int deviceTimestamp;
+  android.hardware.input.common.VideoFrame[] frames;
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PointerCoords.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PointerCoords.aidl
new file mode 100644
index 0000000..353a106
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PointerCoords.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.input.common;
+@VintfStability
+parcelable PointerCoords {
+  long bits;
+  float[] values;
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PointerProperties.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PointerProperties.aidl
new file mode 100644
index 0000000..a49581b
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PointerProperties.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.input.common;
+@VintfStability
+parcelable PointerProperties {
+  int id;
+  android.hardware.input.common.ToolType toolType;
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PolicyFlag.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PolicyFlag.aidl
new file mode 100644
index 0000000..247e868
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/PolicyFlag.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.input.common;
+@Backing(type="int") @VintfStability
+enum PolicyFlag {
+  WAKE = 1,
+  VIRTUAL = 2,
+  FUNCTION = 4,
+  GESTURE = 8,
+  INJECTED = 16777216,
+  TRUSTED = 33554432,
+  FILTERED = 67108864,
+  DISABLE_KEY_REPEAT = 134217728,
+  INTERACTIVE = 536870912,
+  PASS_TO_USER = 1073741824,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Source.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Source.aidl
new file mode 100644
index 0000000..24d02cd
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/Source.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.input.common;
+@Backing(type="int") @VintfStability
+enum Source {
+  UNKNOWN = 0,
+  KEYBOARD = 257,
+  DPAD = 513,
+  GAMEPAD = 1025,
+  TOUCHSCREEN = 4098,
+  MOUSE = 8194,
+  STYLUS = 16386,
+  BLUETOOTH_STYLUS = 49154,
+  TRACKBALL = 65540,
+  MOUSE_RELATIVE = 131076,
+  TOUCHPAD = 1048584,
+  TOUCH_NAVIGATION = 2097152,
+  ROTARY_ENCODER = 4194304,
+  JOYSTICK = 16777232,
+  SENSOR = 67108864,
+  ANY = -256,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/SourceClass.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/SourceClass.aidl
new file mode 100644
index 0000000..96eede2
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/SourceClass.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.input.common;
+@Backing(type="byte") @VintfStability
+enum SourceClass {
+  NONE = 0,
+  BUTTON = 1,
+  POINTER = 2,
+  NAVIGATION = 4,
+  POSITION = 8,
+  JOYSTICK = 16,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/ToolType.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/ToolType.aidl
new file mode 100644
index 0000000..ac1b69d
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/ToolType.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.input.common;
+@Backing(type="byte") @VintfStability
+enum ToolType {
+  UNKNOWN = 0,
+  FINGER = 1,
+  STYLUS = 2,
+  MOUSE = 3,
+  ERASER = 4,
+}
diff --git a/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/VideoFrame.aidl b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/VideoFrame.aidl
new file mode 100644
index 0000000..14985c5
--- /dev/null
+++ b/input/common/aidl/aidl_api/android.hardware.input.common/current/android/hardware/input/common/VideoFrame.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.input.common;
+@VintfStability
+parcelable VideoFrame {
+  char[] data;
+  int height;
+  int width;
+  long timestamp;
+}
diff --git a/input/common/aidl/android/hardware/input/common/Action.aidl b/input/common/aidl/android/hardware/input/common/Action.aidl
new file mode 100644
index 0000000..ebe5e67
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/Action.aidl
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Motion event actions
+ */
+@VintfStability
+@Backing(type="int")
+enum Action {
+    /**
+     * A pressed gesture has started, the motion contains the initial starting location.
+     */
+    DOWN = 0,
+    /**
+     * A pressed gesture has finished, the motion contains the final release location
+     * as well as any intermediate points since the last down or move event.
+     */
+    UP = 1,
+    /**
+     * A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and
+     * AMOTION_EVENT_ACTION_UP). The motion contains the most recent point.
+     */
+    MOVE = 2,
+    /**
+     * The current gesture has been aborted.
+     * You will not receive any more points in it. You must treat this as
+     * an up event, but not perform any action that you normally would.
+     */
+    CANCEL = 3,
+    /**
+     * A movement has happened outside of the normal bounds of the UI element.
+     * This does not provide a full gesture, but only the initial location of the movement/touch.
+     */
+    OUTSIDE = 4,
+    /**
+     * A non-primary pointer has gone down.
+     */
+    POINTER_DOWN = 5,
+    /**
+     * A non-primary pointer has gone up.
+     */
+    POINTER_UP = 6,
+    /**
+     * A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE).
+     * The motion contains the most recent point, as well as any intermediate points since
+     * the last hover move event.
+     */
+    HOVER_MOVE = 7,
+    /**
+     * The motion event contains relative vertical and/or horizontal scroll offsets.
+     * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL
+     * and AMOTION_EVENT_AXIS_HSCROLL.
+     * The pointer may or may not be down when this event is dispatched.
+     * The framework will always deliver this action to the window under the pointer, which
+     * may not be the window currently touched.
+     */
+    SCROLL = 8,
+    /**
+     * The pointer is not down but has entered the boundaries of a window or view.
+     */
+    HOVER_ENTER = 9,
+    /**
+     * The pointer is not down but has exited the boundaries of a window or view.
+     */
+    HOVER_EXIT = 10,
+    /**
+     * One or more buttons have been pressed.
+     */
+    BUTTON_PRESS = 11,
+    /**
+     * One or more buttons have been released.
+     */
+    BUTTON_RELEASE = 12,
+}
diff --git a/input/common/aidl/android/hardware/input/common/Axis.aidl b/input/common/aidl/android/hardware/input/common/Axis.aidl
new file mode 100644
index 0000000..1150949
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/Axis.aidl
@@ -0,0 +1,387 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Constants that identify each individual axis of a motion event.
+ * Each value represents a bit position. The user is expected to manually shift
+ * to the desired position (e.g., 1 << Axis.X) when reading or writing these
+ * from a bitfield manually.
+ */
+@VintfStability
+@Backing(type="int")
+enum Axis {
+    /**
+     * Axis constant: X axis of a motion event.
+     *
+     * - For a touch screen, reports the absolute X screen position of the center of
+     * the touch contact area.  The units are display pixels.
+     * - For a touch pad, reports the absolute X surface position of the center of the touch
+     * contact area. The units are device-dependent.
+     * - For a mouse, reports the absolute X screen position of the mouse pointer.
+     * The units are display pixels.
+     * - For a trackball, reports the relative horizontal displacement of the trackball.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     * - For a joystick, reports the absolute X position of the joystick.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     */
+    X = 0,
+    /**
+     * Axis constant: Y axis of a motion event.
+     *
+     * - For a touch screen, reports the absolute Y screen position of the center of
+     * the touch contact area.  The units are display pixels.
+     * - For a touch pad, reports the absolute Y surface position of the center of the touch
+     * contact area. The units are device-dependent.
+     * - For a mouse, reports the absolute Y screen position of the mouse pointer.
+     * The units are display pixels.
+     * - For a trackball, reports the relative vertical displacement of the trackball.
+     * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+     * - For a joystick, reports the absolute Y position of the joystick.
+     * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near).
+     */
+    Y = 1,
+    /**
+     * Axis constant: Pressure axis of a motion event.
+     *
+     * - For a touch screen or touch pad, reports the approximate pressure applied to the surface
+     * by a finger or other tool.  The value is normalized to a range from
+     * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1
+     * may be generated depending on the calibration of the input device.
+     * - For a trackball, the value is set to 1 if the trackball button is pressed
+     * or 0 otherwise.
+     * - For a mouse, the value is set to 1 if the primary mouse button is pressed
+     * or 0 otherwise.
+     */
+    PRESSURE = 2,
+    /**
+     * Axis constant: Size axis of a motion event.
+     *
+     * - For a touch screen or touch pad, reports the approximate size of the contact area in
+     * relation to the maximum detectable size for the device.  The value is normalized
+     * to a range from 0 (smallest detectable size) to 1 (largest detectable size),
+     * although it is not a linear scale. This value is of limited use.
+     * To obtain calibrated size information, see
+     * {@link TOUCH_MAJOR} or {@link TOOL_MAJOR}.
+     */
+    SIZE = 3,
+    /**
+     * Axis constant: TouchMajor axis of a motion event.
+     *
+     * - For a touch screen, reports the length of the major axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are display pixels.
+     * - For a touch pad, reports the length of the major axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are device-dependent.
+     */
+    TOUCH_MAJOR = 4,
+    /**
+     * Axis constant: TouchMinor axis of a motion event.
+     *
+     * - For a touch screen, reports the length of the minor axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are display pixels.
+     * - For a touch pad, reports the length of the minor axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are device-dependent.
+     *
+     * When the touch is circular, the major and minor axis lengths will be equal to one another.
+     */
+    TOUCH_MINOR = 5,
+    /**
+     * Axis constant: ToolMajor axis of a motion event.
+     *
+     * - For a touch screen, reports the length of the major axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * - For a touch pad, reports the length of the major axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * The units are device-dependent.
+     *
+     * When the touch is circular, the major and minor axis lengths will be equal to one another.
+     *
+     * The tool size may be larger than the touch size since the tool may not be fully
+     * in contact with the touch sensor.
+     */
+    TOOL_MAJOR = 6,
+    /**
+     * Axis constant: ToolMinor axis of a motion event.
+     *
+     * - For a touch screen, reports the length of the minor axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * - For a touch pad, reports the length of the minor axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * The units are device-dependent.
+     *
+     * When the touch is circular, the major and minor axis lengths will be equal to one another.
+     *
+     * The tool size may be larger than the touch size since the tool may not be fully
+     * in contact with the touch sensor.
+     */
+    TOOL_MINOR = 7,
+    /**
+     * Axis constant: Orientation axis of a motion event.
+     *
+     * - For a touch screen or touch pad, reports the orientation of the finger
+     * or tool in radians relative to the vertical plane of the device.
+     * An angle of 0 radians indicates that the major axis of contact is oriented
+     * upwards, is perfectly circular or is of unknown orientation.  A positive angle
+     * indicates that the major axis of contact is oriented to the right.  A negative angle
+     * indicates that the major axis of contact is oriented to the left.
+     * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
+     * (finger pointing fully right).
+     * - For a stylus, the orientation indicates the direction in which the stylus
+     * is pointing in relation to the vertical axis of the current orientation of the screen.
+     * The range is from -PI radians to PI radians, where 0 is pointing up,
+     * -PI/2 radians is pointing left, -PI or PI radians is pointing down, and PI/2 radians
+     * is pointing right.  See also {@link TILT}.
+     */
+    ORIENTATION = 8,
+    /**
+     * Axis constant: Vertical Scroll axis of a motion event.
+     *
+     * - For a mouse, reports the relative movement of the vertical scroll wheel.
+     * The value is normalized to a range from -1.0 (down) to 1.0 (up).
+     *
+     * The framework may use this axis to scroll views vertically.
+     */
+    VSCROLL = 9,
+    /**
+     * Axis constant: Horizontal Scroll axis of a motion event.
+     *
+     * - For a mouse, reports the relative movement of the horizontal scroll wheel.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     *
+     * The framework may use this axis to scroll views horizontally.
+     */
+    HSCROLL = 10,
+    /**
+     * Axis constant: Z axis of a motion event.
+     *
+     * - For a joystick, reports the absolute Z position of the joystick.
+     * The value is normalized to a range from -1.0 (high) to 1.0 (low).
+     * <em>On game pads with two analog joysticks, this axis is often reinterpreted
+     * to report the absolute X position of the second joystick instead.</em>
+     */
+    Z = 11,
+    /**
+     * Axis constant: X Rotation axis of a motion event.
+     *
+     * - For a joystick, reports the absolute rotation angle about the X axis.
+     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+     */
+    RX = 12,
+    /**
+     * Axis constant: Y Rotation axis of a motion event.
+     *
+     * - For a joystick, reports the absolute rotation angle about the Y axis.
+     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+     */
+    RY = 13,
+    /**
+     * Axis constant: Z Rotation axis of a motion event.
+     *
+     * - For a joystick, reports the absolute rotation angle about the Z axis.
+     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+     * On game pads with two analog joysticks, this axis is often reinterpreted
+     * to report the absolute Y position of the second joystick instead.
+     */
+    RZ = 14,
+    /**
+     * Axis constant: Hat X axis of a motion event.
+     *
+     * - For a joystick, reports the absolute X position of the directional hat control.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     */
+    HAT_X = 15,
+    /**
+     * Axis constant: Hat Y axis of a motion event.
+     *
+     * - For a joystick, reports the absolute Y position of the directional hat control.
+     * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+     */
+    HAT_Y = 16,
+    /**
+     * Axis constant: Left Trigger axis of a motion event.
+     *
+     * - For a joystick, reports the absolute position of the left trigger control.
+     * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
+     */
+    LTRIGGER = 17,
+    /**
+     * Axis constant: Right Trigger axis of a motion event.
+     *
+     * - For a joystick, reports the absolute position of the right trigger control.
+     * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
+     */
+    RTRIGGER = 18,
+    /**
+     * Axis constant: Throttle axis of a motion event.
+     *
+     * - For a joystick, reports the absolute position of the throttle control.
+     * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed).
+     */
+    THROTTLE = 19,
+    /**
+     * Axis constant: Rudder axis of a motion event.
+     *
+     * - For a joystick, reports the absolute position of the rudder control.
+     * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+     */
+    RUDDER = 20,
+    /**
+     * Axis constant: Wheel axis of a motion event.
+     *
+     * - For a joystick, reports the absolute position of the steering wheel control.
+     * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+     */
+    WHEEL = 21,
+    /**
+     * Axis constant: Gas axis of a motion event.
+     *
+     * - For a joystick, reports the absolute position of the gas (accelerator) control.
+     * The value is normalized to a range from 0.0 (no acceleration)
+     * to 1.0 (maximum acceleration).
+     */
+    GAS = 22,
+    /**
+     * Axis constant: Brake axis of a motion event.
+     *
+     * - For a joystick, reports the absolute position of the brake control.
+     * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking).
+     */
+    BRAKE = 23,
+    /**
+     * Axis constant: Distance axis of a motion event.
+     *
+     * - For a stylus, reports the distance of the stylus from the screen.
+     * A value of 0.0 indicates direct contact and larger values indicate increasing
+     * distance from the surface.
+     */
+    DISTANCE = 24,
+    /**
+     * Axis constant: Tilt axis of a motion event.
+     *
+     * - For a stylus, reports the tilt angle of the stylus in radians where
+     * 0 radians indicates that the stylus is being held perpendicular to the
+     * surface, and PI/2 radians indicates that the stylus is being held flat
+     * against the surface.
+     */
+    TILT = 25,
+    /**
+     * Axis constant:  Generic scroll axis of a motion event.
+     *
+     * - This is used for scroll axis motion events that can't be classified as strictly
+     *   vertical or horizontal. The movement of a rotating scroller is an example of this.
+     */
+    SCROLL = 26,
+    /**
+     * Axis constant: The movement of x position of a motion event.
+     *
+     * - For a mouse, reports a difference of x position between the previous position.
+     * This is useful when pointer is captured, in that case the mouse pointer doesn't
+     * change the location but this axis reports the difference which allows the app
+     * to see how the mouse is moved.
+     */
+    RELATIVE_X = 27,
+    /**
+     * Axis constant: The movement of y position of a motion event.
+     *
+     * Same as {@link RELATIVE_X}, but for y position.
+     */
+    RELATIVE_Y = 28,
+    /**
+     * Axis constant: Generic 1 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_1 = 32,
+    /**
+     * Axis constant: Generic 2 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_2 = 33,
+    /**
+     * Axis constant: Generic 3 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_3 = 34,
+    /**
+     * Axis constant: Generic 4 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_4 = 35,
+    /**
+     * Axis constant: Generic 5 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_5 = 36,
+    /**
+     * Axis constant: Generic 6 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_6 = 37,
+    /**
+     * Axis constant: Generic 7 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_7 = 38,
+    /**
+     * Axis constant: Generic 8 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_8 = 39,
+    /**
+     * Axis constant: Generic 9 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_9 = 40,
+    /**
+     * Axis constant: Generic 10 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_10 = 41,
+    /**
+     * Axis constant: Generic 11 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_11 = 42,
+    /**
+     * Axis constant: Generic 12 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_12 = 43,
+    /**
+     * Axis constant: Generic 13 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_13 = 44,
+    /**
+     * Axis constant: Generic 14 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_14 = 45,
+    /**
+     * Axis constant: Generic 15 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_15 = 46,
+    /**
+     * Axis constant: Generic 16 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     */
+    GENERIC_16 = 47,
+}
diff --git a/input/common/aidl/android/hardware/input/common/Button.aidl b/input/common/aidl/android/hardware/input/common/Button.aidl
new file mode 100644
index 0000000..4bbd5f5
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/Button.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Buttons that are associated with motion events.
+ */
+@VintfStability
+@Backing(type="int")
+enum Button {
+    NONE = 0,
+    PRIMARY = 1 << 0,
+    SECONDARY = 1 << 1,
+    TERTIARY = 1 << 2,
+    BACK = 1 << 3,
+    FORWARD = 1 << 4,
+    STYLUS_PRIMARY = 1 << 5,
+    STYLUS_SECONDARY = 1 << 6,
+}
diff --git a/input/common/aidl/android/hardware/input/common/Classification.aidl b/input/common/aidl/android/hardware/input/common/Classification.aidl
new file mode 100644
index 0000000..f573174
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/Classification.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Classification of the current gesture, if available.
+ */
+@VintfStability
+@Backing(type="byte")
+enum Classification {
+    NONE = 0,
+    /**
+     * Too early to classify the gesture, need more events.
+     */
+    AMBIGUOUS_GESTURE = 1,
+    /**
+     * User is force-pressing the screen.
+     */
+    DEEP_PRESS = 2,
+}
diff --git a/input/common/aidl/android/hardware/input/common/EdgeFlag.aidl b/input/common/aidl/android/hardware/input/common/EdgeFlag.aidl
new file mode 100644
index 0000000..8d22635
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/EdgeFlag.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Edge flags
+ */
+@VintfStability
+@Backing(type="int")
+enum EdgeFlag {
+    /**
+     * No edges are intersected
+     */
+    NONE = 0,
+    /**
+     * Motion intersected top edge of the screen
+     */
+    TOP = 1 << 0,
+    /**
+     * Motion intersected bottom edge of the screen
+     */
+    BOTTOM = 1 << 1,
+    /**
+     * Motion intersected left edge of the screen
+     */
+    LEFT = 1 << 2,
+    /**
+     * Motion intersected right edge of the screen
+     */
+    RIGHT = 1 << 3,
+}
diff --git a/input/common/aidl/android/hardware/input/common/Flag.aidl b/input/common/aidl/android/hardware/input/common/Flag.aidl
new file mode 100644
index 0000000..600bdd3
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/Flag.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Motion event flags
+ */
+@VintfStability
+@Backing(type="int")
+enum Flag {
+    /**
+     * Indicates that the window that received this motion event is partly
+     * or wholly obscured by another visible window above it. This flag is set to true
+     * even if the event did not directly pass through the obscured area.
+     * A security sensitive application can check this flag to identify situations in which
+     * a malicious application may have covered up part of its content for the purpose
+     * of misleading the user or hijacking touches. An appropriate response might be
+     * to drop the suspect touches or to take additional precautions to confirm the user's
+     * actual intent.
+     */
+    WINDOW_IS_OBSCURED = 1 << 0,
+    /**
+     * This flag indicates that the event has been generated by a gesture generator. It
+     * could be used, for example, to determine whether touch slop should be applied.
+     */
+    IS_GENERATED_GESTURE = 1 << 3,
+    /**
+     * Motion event is inconsistent with previously sent motion events.
+     */
+    TAINTED = 1 << 31,
+}
diff --git a/input/common/aidl/android/hardware/input/common/Meta.aidl b/input/common/aidl/android/hardware/input/common/Meta.aidl
new file mode 100644
index 0000000..9ccf11b
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/Meta.aidl
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Meta key / modifier state
+ */
+@VintfStability
+@Backing(type="int")
+enum Meta {
+    NONE = 0,
+    /**
+     * One of the ALT meta keys is pressed.
+     */
+    ALT_ON = 1 << 1,
+    /**
+     * The left ALT meta key is pressed.
+     */
+    ALT_LEFT_ON = 1 << 4,
+    /**
+     * The right ALT meta key is pressed.
+     */
+    ALT_RIGHT_ON = 1 << 5,
+    /**
+     * One of the SHIFT meta keys is pressed.
+     */
+    SHIFT_ON = 1 << 0,
+    /**
+     * The left SHIFT meta key is pressed.
+     */
+    SHIFT_LEFT_ON = 1 << 6,
+    /**
+     * The right SHIFT meta key is pressed.
+     */
+    SHIFT_RIGHT_ON = 1 << 7,
+    /**
+     * The SYM meta key is pressed.
+     */
+    SYM_ON = 1 << 2,
+    /**
+     * The FUNCTION meta key is pressed.
+     */
+    FUNCTION_ON = 1 << 3,
+    /**
+     * One of the CTRL meta keys is pressed.
+     */
+    CTRL_ON = 1 << 12,
+    /**
+     * The left CTRL meta key is pressed.
+     */
+    CTRL_LEFT_ON = 1 << 13,
+    /**
+     * The right CTRL meta key is pressed.
+     */
+    CTRL_RIGHT_ON = 1 << 14,
+    /**
+     * One of the META meta keys is pressed.
+     */
+    META_ON = 1 << 16,
+    /**
+     * The left META meta key is pressed.
+     */
+    META_LEFT_ON = 1 << 17,
+    /**
+     * The right META meta key is pressed.
+     */
+    META_RIGHT_ON = 1 << 18,
+    /**
+     * The CAPS LOCK meta key is on.
+     */
+    CAPS_LOCK_ON = 1 << 20,
+    /**
+     * The NUM LOCK meta key is on.
+     */
+    NUM_LOCK_ON = 1 << 21,
+    /**
+     * The SCROLL LOCK meta key is on.
+     */
+    SCROLL_LOCK_ON = 1 << 22,
+}
diff --git a/input/common/aidl/android/hardware/input/common/MotionEvent.aidl b/input/common/aidl/android/hardware/input/common/MotionEvent.aidl
new file mode 100644
index 0000000..dfea703
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/MotionEvent.aidl
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+import android.hardware.input.common.Action;
+import android.hardware.input.common.Button;
+import android.hardware.input.common.EdgeFlag;
+import android.hardware.input.common.Flag;
+import android.hardware.input.common.Meta;
+import android.hardware.input.common.PointerCoords;
+import android.hardware.input.common.PointerProperties;
+import android.hardware.input.common.PolicyFlag;
+import android.hardware.input.common.Source;
+import android.hardware.input.common.VideoFrame;
+
+/**
+ * Analogous to Android's native MotionEvent / NotifyMotionArgs.
+ * Stores the basic information about pointer movements.
+ */
+@VintfStability
+parcelable MotionEvent {
+    /**
+     * The id of the device which produced this event.
+     */
+    int deviceId;
+    /**
+     * The source type of this event.
+     */
+    Source source;
+    /**
+     * The display id associated with this event.
+     */
+    int displayId;
+    /**
+     * Time when the initial touch down occurred, in nanoseconds.
+     */
+    long downTime;
+    /**
+     * Time when this event occurred, in nanoseconds.
+     */
+    long eventTime;
+    /**
+     * The kind of action being performed.
+     */
+    Action action;
+    /**
+     * For ACTION_POINTER_DOWN or ACTION_POINTER_UP, this contains the associated pointer index.
+     * The index may be used to get information about the pointer that has gone down or up.
+     */
+    byte actionIndex;
+    /**
+     * The button that has been modified during a press or release action.
+     */
+    Button actionButton;
+    /**
+     * The motion event flags.
+     */
+    Flag flags;
+    /**
+     * The motion event policy flags.
+     */
+    PolicyFlag policyFlags;
+    /**
+     * The edges, if any, that were touched by this motion event.
+     */
+    EdgeFlag edgeFlags;
+    /**
+     * The state of any meta / modifier keys that were in effect when the event was generated.
+     */
+    Meta metaState;
+    /**
+     * The state of buttons that are pressed.
+     */
+    Button buttonState;
+    /**
+     * The precision of the X coordinate being reported.
+     */
+    float xPrecision;
+    /**
+     * The precision of the Y coordinate being reported.
+     */
+    float yPrecision;
+    /**
+     * The properties of each pointer present in this motion event.
+     */
+    PointerProperties[] pointerProperties;
+    /**
+     * The coordinates of each pointer.
+     */
+    PointerCoords[] pointerCoords;
+    /**
+     * Device time at which the event occurred, in microseconds.
+     * Will wrap after a little over an hour.
+     */
+    int deviceTimestamp;
+    /**
+     * The video frames, if any, associated with the current or previous motion events.
+     */
+    VideoFrame[] frames;
+}
diff --git a/input/common/aidl/android/hardware/input/common/PointerCoords.aidl b/input/common/aidl/android/hardware/input/common/PointerCoords.aidl
new file mode 100644
index 0000000..56d9a74
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/PointerCoords.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+import android.hardware.input.common.Axis;
+
+/**
+ * Pointer coordinate data. Analogous to Android's PointerCoords.
+ */
+@VintfStability
+parcelable PointerCoords {
+    /**
+     * Bitfield of axes that are present in this structure.
+     * Each bit position matches an axis defined in Axis.aidl.
+     */
+    long bits;
+    /**
+     * The values corresponding to each non-zero axis. This vector only
+     * contains non-zero entries. If an axis that is not currently specified
+     * in "bits" is requested, a zero value is returned.
+     * There are only as many values stored here
+     * as there are non-zero bits in the "bits" field.
+     * The values are position-packed. So the first non-zero axis will be
+     * at position 0, the next non-zero axis will be at position 1, and so on.
+     */
+    float[] values;
+}
diff --git a/input/common/aidl/android/hardware/input/common/PointerProperties.aidl b/input/common/aidl/android/hardware/input/common/PointerProperties.aidl
new file mode 100644
index 0000000..38d815e
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/PointerProperties.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+import android.hardware.input.common.ToolType;
+
+/**
+ * Properties of a particular pointer. Analogous to Android's PointerProperties.
+ */
+@VintfStability
+parcelable PointerProperties {
+    /**
+     * A number identifying a specific pointer. When a pointer is lifted,
+     * this value may be reused by another new pointer, even during the
+     * same gesture. For example, if there are two pointers touching the screen
+     * at the same time, they might have pointer ID's of 0 and 1. If the
+     * pointer with id = 0 is lifted, while the pointer with id = 1 remains, and
+     * a new pointer is placed on the screen, then the new pointer may receive
+     * an id of 0. While a pointer is active, it is guaranteed to keep the same
+     * id.
+     */
+    int id;
+    /**
+     * Type of tool used to make contact, such as a finger or stylus, if known.
+     */
+    ToolType toolType;
+}
diff --git a/input/common/aidl/android/hardware/input/common/PolicyFlag.aidl b/input/common/aidl/android/hardware/input/common/PolicyFlag.aidl
new file mode 100644
index 0000000..c5edd0d
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/PolicyFlag.aidl
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Policy flags.
+ * The values 1 << 4 through 1 << 23 are not currently used.
+ * When a new value is added, make sure it matches a value defined in Input.h
+ * and other relevant files in frameworks/base and frameworks/native.
+ */
+@VintfStability
+@Backing(type="int")
+enum PolicyFlag {
+    /**
+     * Event should wake the device
+     */
+    WAKE = 1 << 0,
+    /**
+     * Key is virtual, and should generate haptic feedback
+     */
+    VIRTUAL = 1 << 1,
+    /**
+     * Key is the special function modifier
+     */
+    FUNCTION = 1 << 2,
+    /**
+     * Key represents a special gesture that has been detected
+     * by the touch firmware or driver.
+     */
+    GESTURE = 1 << 3,
+    /**
+     * Event was injected
+     */
+    INJECTED = 1 << 24,
+    /**
+     * Event comes from a trusted source, such as a directly attached input
+     * device or an application with system-wide event injection permission.
+     */
+    TRUSTED = 1 << 25,
+    /**
+     * Event has passed through an input filter.
+     */
+    FILTERED = 1 << 26,
+    /**
+     * Disable automatic key repeating behaviour.
+     */
+    DISABLE_KEY_REPEAT = 1 << 27,
+    /**
+     * Device was in an interactive state when the event was intercepted
+     */
+    INTERACTIVE = 1 << 29,
+    /**
+     * Event should be dispatched to applications
+     */
+    PASS_TO_USER = 1 << 30,
+}
diff --git a/input/common/aidl/android/hardware/input/common/Source.aidl b/input/common/aidl/android/hardware/input/common/Source.aidl
new file mode 100644
index 0000000..7eb6d66
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/Source.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.
+ */
+
+package android.hardware.input.common;
+
+import android.hardware.input.common.SourceClass;
+
+/**
+ * Input sources
+ */
+@VintfStability
+@Backing(type="int")
+enum Source {
+    UNKNOWN = 0,
+    KEYBOARD = (1 << 8) | SourceClass.BUTTON,
+    DPAD = (1 << 9) | SourceClass.BUTTON,
+    GAMEPAD = (1 << 10) | SourceClass.BUTTON,
+    TOUCHSCREEN = (1 << 12) | SourceClass.POINTER,
+    MOUSE = (1 << 13) | SourceClass.POINTER,
+    STYLUS = (1 << 14) | SourceClass.POINTER,
+    BLUETOOTH_STYLUS = (1 << 15) | STYLUS,
+    TRACKBALL = (1 << 16) | SourceClass.NAVIGATION,
+    MOUSE_RELATIVE = (1 << 17) | SourceClass.NAVIGATION,
+    TOUCHPAD = (1 << 20) | SourceClass.POSITION,
+    TOUCH_NAVIGATION = (1 << 21) | SourceClass.NONE,
+    ROTARY_ENCODER = (1 << 22) | SourceClass.NONE,
+    JOYSTICK = (1 << 24) | SourceClass.JOYSTICK,
+    SENSOR = (1 << 26) | SourceClass.NONE,
+    ANY = 0xFFFFFF00,
+}
diff --git a/input/common/aidl/android/hardware/input/common/SourceClass.aidl b/input/common/aidl/android/hardware/input/common/SourceClass.aidl
new file mode 100644
index 0000000..4315798
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/SourceClass.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+@VintfStability
+@Backing(type="byte")
+enum SourceClass {
+    NONE = 0 << 0,
+    BUTTON = 1 << 0,
+    POINTER = 1 << 1,
+    NAVIGATION = 1 << 2,
+    POSITION = 1 << 3,
+    JOYSTICK = 1 << 4,
+}
diff --git a/input/common/aidl/android/hardware/input/common/ToolType.aidl b/input/common/aidl/android/hardware/input/common/ToolType.aidl
new file mode 100644
index 0000000..cfa057d
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/ToolType.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Tool type of a pointer
+ */
+@VintfStability
+@Backing(type="byte")
+enum ToolType {
+    UNKNOWN = 0,
+    FINGER = 1,
+    STYLUS = 2,
+    MOUSE = 3,
+    ERASER = 4,
+}
diff --git a/input/common/aidl/android/hardware/input/common/VideoFrame.aidl b/input/common/aidl/android/hardware/input/common/VideoFrame.aidl
new file mode 100644
index 0000000..409cee5
--- /dev/null
+++ b/input/common/aidl/android/hardware/input/common/VideoFrame.aidl
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package android.hardware.input.common;
+
+/**
+ * Touch heatmap.
+ *
+ * The array is a 2-D row-major matrix with dimensions (height, width).
+ * The heatmap data is rotated when device orientation changes.
+ *
+ * Example:
+ *
+ * If the data in the array is:
+ * data[i] = i for i in 0 .. 59,
+ * then it can be represented as a 10 x 6 matrix:
+ *
+ *  <--   width   -->
+ *   0  1  2  3  4  5   ^
+ *   6  7  8  9 10 11   |
+ *  12 13 14 15 16 17   |
+ *  18    ...      23   |
+ *  24    ...      29   | height
+ *  30    ...      35   |
+ *  36    ...      41   |
+ *  42    ...      47   |
+ *  48    ...      53   |
+ *  54    ...      59   v
+ *
+ * Looking at the device in standard portrait orientation,
+ * the element "0" is the top left of the screen,
+ * "5" is at the top right, and "59" is the bottom right.
+ * Here height=10 and width=6.
+ *
+ * If the screen orientation changes to landscape (a 90 degree orientation
+ * change), the frame's dimensions will become 6 x 10
+ * and the data will look as follows:
+ * 54 48 42 36 30 24 18 12  6  0     ^
+ * ...                  13  7  1     |
+ * ...                  14  8  2     | height
+ * ...                  15  9  3     |
+ * ...                  16 10  4     |
+ * 59 53 47 41 35 29 23 17 11  5     v
+ * <--        width          -->
+ *
+ * Here the element "0" is at the physical top left of the unrotated screen.
+ *
+ * Since the coordinates of a MotionEvent are also adjusted based on the
+ * orientation, the rotation of the video frame data ensures that
+ * the axes for MotionEvent and VideoFrame data are consistent.
+ */
+@VintfStability
+parcelable VideoFrame {
+    /**
+     * Video frame data.
+     * Size of the data is height * width.
+     */
+    char[] data;
+    int height;
+    int width;
+    /**
+     * Time at which the frame was collected, in nanoseconds.
+     * Measured with the same clock that is used to populate MotionEvent times.
+     */
+    long timestamp;
+}
diff --git a/ir/OWNERS b/ir/OWNERS
new file mode 100644
index 0000000..04de9ef
--- /dev/null
+++ b/ir/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 163905
+connoro@google.com
diff --git a/ir/aidl/Android.bp b/ir/aidl/Android.bp
new file mode 100644
index 0000000..5dbf68f
--- /dev/null
+++ b/ir/aidl/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.ir",
+    vendor_available: true,
+    srcs: ["android/hardware/ir/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/ir/aidl/aidl_api/android.hardware.ir/current/android/hardware/ir/ConsumerIrFreqRange.aidl b/ir/aidl/aidl_api/android.hardware.ir/current/android/hardware/ir/ConsumerIrFreqRange.aidl
new file mode 100644
index 0000000..4a0d286
--- /dev/null
+++ b/ir/aidl/aidl_api/android.hardware.ir/current/android/hardware/ir/ConsumerIrFreqRange.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.ir;
+@VintfStability
+parcelable ConsumerIrFreqRange {
+  int minHz;
+  int maxHz;
+}
diff --git a/ir/aidl/aidl_api/android.hardware.ir/current/android/hardware/ir/IConsumerIr.aidl b/ir/aidl/aidl_api/android.hardware.ir/current/android/hardware/ir/IConsumerIr.aidl
new file mode 100644
index 0000000..07bf4b4
--- /dev/null
+++ b/ir/aidl/aidl_api/android.hardware.ir/current/android/hardware/ir/IConsumerIr.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.ir;
+@VintfStability
+interface IConsumerIr {
+  android.hardware.ir.ConsumerIrFreqRange[] getCarrierFreqs();
+  void transmit(in int carrierFreqHz, in int[] pattern);
+}
diff --git a/ir/aidl/android/hardware/ir/ConsumerIrFreqRange.aidl b/ir/aidl/android/hardware/ir/ConsumerIrFreqRange.aidl
new file mode 100644
index 0000000..ab0276a
--- /dev/null
+++ b/ir/aidl/android/hardware/ir/ConsumerIrFreqRange.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.ir;
+
+@VintfStability
+parcelable ConsumerIrFreqRange {
+    int minHz;
+    int maxHz;
+}
diff --git a/ir/aidl/android/hardware/ir/IConsumerIr.aidl b/ir/aidl/android/hardware/ir/IConsumerIr.aidl
new file mode 100644
index 0000000..f6f9742
--- /dev/null
+++ b/ir/aidl/android/hardware/ir/IConsumerIr.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.ir;
+
+import android.hardware.ir.ConsumerIrFreqRange;
+
+@VintfStability
+interface IConsumerIr {
+    /**
+     * Enumerates which frequencies the IR transmitter supports.
+     *
+     * @return - an array of all supported frequency ranges.
+     */
+    ConsumerIrFreqRange[] getCarrierFreqs();
+
+    /**
+     * Sends an IR pattern at a given frequency in HZ.
+     * This call must return when the transmit is complete or encounters an error.
+     *
+     * @param carrierFreq - Frequency of the transmission in HZ.
+     *
+     * @param pattern - Alternating series of on and off periods measured in
+     * microseconds. The carrier should be turned off at the end of a transmit
+     * even if there are an odd number of entries in the pattern array.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION when the frequency is not supported.
+     */
+    void transmit(in int carrierFreqHz, in int[] pattern);
+}
diff --git a/ir/aidl/default/Android.bp b/ir/aidl/default/Android.bp
new file mode 100644
index 0000000..a4fb439
--- /dev/null
+++ b/ir/aidl/default/Android.bp
@@ -0,0 +1,42 @@
+// 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.
+
+// Example binder service of the ir HAL.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.ir-service.example",
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.ir-service.example.rc"],
+    vendor: true,
+    vintf_fragments: ["android.hardware.ir-service.example.xml"],
+
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "android.hardware.ir-V1-ndk",
+    ],
+
+    srcs: ["main.cpp"],
+}
diff --git a/ir/aidl/default/android.hardware.ir-service.example.rc b/ir/aidl/default/android.hardware.ir-service.example.rc
new file mode 100644
index 0000000..56def64
--- /dev/null
+++ b/ir/aidl/default/android.hardware.ir-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.ir-default /vendor/bin/hw/android.hardware.ir-service.example
+    class hal
+    user nobody
+    group nobody
diff --git a/ir/aidl/default/android.hardware.ir-service.example.xml b/ir/aidl/default/android.hardware.ir-service.example.xml
new file mode 100644
index 0000000..1a63520
--- /dev/null
+++ b/ir/aidl/default/android.hardware.ir-service.example.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.ir</name>
+        <version>1</version>
+        <fqname>IConsumerIr/default</fqname>
+    </hal>
+</manifest>
diff --git a/ir/aidl/default/main.cpp b/ir/aidl/default/main.cpp
new file mode 100644
index 0000000..7c4a816
--- /dev/null
+++ b/ir/aidl/default/main.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/ir/BnConsumerIr.h>
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <numeric>
+
+namespace aidl::android::hardware::ir {
+
+const std::vector<ConsumerIrFreqRange> kSupportedFreqs = {
+        {2000, 4000},
+        {10000, 30000},
+};
+
+class ConsumerIr : public BnConsumerIr {
+    ::ndk::ScopedAStatus getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) override;
+    ::ndk::ScopedAStatus transmit(int32_t in_carrierFreqHz,
+                                  const std::vector<int32_t>& in_pattern) override;
+};
+
+::ndk::ScopedAStatus ConsumerIr::getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) {
+    *_aidl_return = kSupportedFreqs;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+bool isSupportedFreq(int32_t freq) {
+    for (const auto& range : kSupportedFreqs) {
+        if (freq >= range.minHz && freq <= range.maxHz) return true;
+    }
+    return false;
+}
+
+::ndk::ScopedAStatus ConsumerIr::transmit(int32_t in_carrierFreqHz,
+                                          const std::vector<int32_t>& in_pattern) {
+    if (isSupportedFreq(in_carrierFreqHz)) {
+        // trasmit the pattern, each integer is number of microseconds in an
+        // alternating on/off state.
+        usleep(std::accumulate(in_pattern.begin(), in_pattern.end(), 0));
+        return ::ndk::ScopedAStatus::ok();
+    } else {
+        // unsupported operation
+        return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::ir
+
+using aidl::android::hardware::ir::ConsumerIr;
+
+int main() {
+    auto binder = ::ndk::SharedRefBase::make<ConsumerIr>();
+    const std::string name = std::string() + ConsumerIr::descriptor + "/default";
+    CHECK_EQ(STATUS_OK, AServiceManager_addService(binder->asBinder().get(), name.c_str()))
+            << "Failed to register " << name;
+
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    ABinderProcess_joinThreadPool();
+
+    return EXIT_FAILURE;  // should not reached
+}
diff --git a/ir/aidl/vts/Android.bp b/ir/aidl/vts/Android.bp
new file mode 100644
index 0000000..c2491b8
--- /dev/null
+++ b/ir/aidl/vts/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalIrTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalIrTargetTest.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.ir-V1-ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/ir/aidl/vts/VtsHalIrTargetTest.cpp b/ir/aidl/vts/VtsHalIrTargetTest.cpp
new file mode 100644
index 0000000..3527625
--- /dev/null
+++ b/ir/aidl/vts/VtsHalIrTargetTest.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ir_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/ir/IConsumerIr.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <algorithm>
+#include <vector>
+
+using ::aidl::android::hardware::ir::ConsumerIrFreqRange;
+using ::aidl::android::hardware::ir::IConsumerIr;
+using ::ndk::SpAIBinder;
+
+class ConsumerIrTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mIr = IConsumerIr::fromBinder(
+                SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(mIr, nullptr);
+    }
+
+    std::shared_ptr<IConsumerIr> mIr;
+};
+
+// Test transmit() for the min and max frequency of every available range
+TEST_P(ConsumerIrTest, TransmitTest) {
+    std::vector<ConsumerIrFreqRange> ranges;
+    const auto& ret = mIr->getCarrierFreqs(&ranges);
+    ASSERT_TRUE(ret.isOk());
+
+    if (ranges.size() > 0) {
+        uint32_t len = 16;
+        std::vector<int32_t> vec;
+        vec.resize(len);
+        std::fill(vec.begin(), vec.end(), 1000);
+        for (auto range = ranges.begin(); range != ranges.end(); range++) {
+            EXPECT_TRUE(mIr->transmit(range->minHz, vec).isOk());
+            EXPECT_TRUE(mIr->transmit(range->maxHz, vec).isOk());
+        }
+    }
+}
+
+// Test transmit() when called with invalid frequencies
+TEST_P(ConsumerIrTest, BadFreqTest) {
+    uint32_t len = 16;
+    std::vector<int32_t> vec;
+    vec.resize(len);
+    std::fill(vec.begin(), vec.end(), 1);
+    const auto& res = mIr->transmit(-1, vec);
+    EXPECT_FALSE(res.isOk());
+    EXPECT_EQ(res.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ConsumerIrTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ConsumerIrTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IConsumerIr::descriptor)),
+        ::android::PrintInstanceNameToString);
diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp
index e2ae803..39bec3f 100644
--- a/keymaster/3.0/vts/functional/Android.bp
+++ b/keymaster/3.0/vts/functional/Android.bp
@@ -38,5 +38,11 @@
         "libcrypto_static",
         "libsoftkeymasterdevice",
     ],
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    sanitize: {
+        cfi: false,
+    },
 }
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index dfde060..1c6ae47 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -1254,7 +1254,8 @@
      * o PaddingMode::RSA_PSS.  For PSS-padded signature operations, the PSS salt length must match
      *   the size of the PSS digest selected.  The digest specified with Tag::DIGEST in inputParams
      *   on begin() must be used as the PSS digest algorithm, MGF1 must be used as the mask
-     *   generation function and SHA1 must be used as the MGF1 digest algorithm.
+     *   generation function and the digest specified with Tag:DIGEST in inputParams must also be
+     *   used as the MGF1 digest algorithm.
      *
      * o PaddingMode::RSA_OAEP.  The digest specified with Tag::DIGEST in inputParams on begin is
      *   used as the OAEP digest algorithm, MGF1 must be used as the mask generation function and
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index a7be660..8e5a0ff 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -41,6 +41,10 @@
         "general-tests",
         "vts",
     ],
+    sanitize: {
+        cfi: false,
+    },
+
 }
 
 cc_test_library {
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 2c15823..6412f3a 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -81,6 +81,12 @@
 namespace test {
 namespace {
 
+// The maximum number of times we'll attempt to verify that corruption
+// of an encrypted blob results in an error. Retries are necessary as there
+// is a small (roughly 1/256) chance that corrupting ciphertext still results
+// in valid PKCS7 padding.
+constexpr size_t kMaxPaddingCorruptionRetries = 8;
+
 template <TagType tag_type, Tag tag, typename ValueT>
 bool contains(hidl_vec<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
     size_t count = std::count_if(set.begin(), set.end(), [&](const KeyParameter& param) {
@@ -1706,6 +1712,7 @@
                     case PaddingMode::RSA_PSS:
                         EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING), 0);
                         EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, EVP_MD_size(md)), 0);
+                        EXPECT_GT(EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, md), 0);
                         break;
                     case PaddingMode::RSA_PKCS1_1_5_SIGN:
                         // PKCS1 is the default; don't need to set anything.
@@ -2853,11 +2860,22 @@
     string ciphertext = EncryptMessage(message, params);
     EXPECT_EQ(16U, ciphertext.size());
     EXPECT_NE(ciphertext, message);
-    ++ciphertext[ciphertext.size() / 2];
 
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
-    string plaintext;
-    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
+    for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
+        ++ciphertext[ciphertext.size() / 2];
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+        string plaintext;
+        ErrorCode error = Finish(message, &plaintext);
+        if (error == ErrorCode::INVALID_INPUT_LENGTH) {
+            // This is the expected error, we can exit the test now.
+            return;
+        } else {
+            // Very small chance we got valid decryption, so try again.
+            ASSERT_EQ(error, ErrorCode::OK);
+        }
+    }
+    FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
 }
 
 HidlBuf CopyIv(const AuthorizationSet& set) {
@@ -3923,17 +3941,30 @@
     string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
     EXPECT_EQ(8U, ciphertext.size());
     EXPECT_NE(ciphertext, message);
-    ++ciphertext[ciphertext.size() / 2];
 
     AuthorizationSetBuilder begin_params;
     begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
     begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
-    string plaintext;
-    size_t input_consumed;
-    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
-    EXPECT_EQ(ciphertext.size(), input_consumed);
-    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+
+    for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
+        ++ciphertext[ciphertext.size() / 2];
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+        string plaintext;
+
+        size_t input_consumed;
+        EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+        EXPECT_EQ(ciphertext.size(), input_consumed);
+        ErrorCode error = Finish(&plaintext);
+        if (error == ErrorCode::INVALID_ARGUMENT) {
+            // This is the expected error, we can exit the test now.
+            return;
+        } else {
+            // Very small chance we got valid decryption, so try again.
+            ASSERT_EQ(error, ErrorCode::OK);
+        }
+    }
+    FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
 }
 
 struct TripleDesTestVector {
@@ -4234,18 +4265,28 @@
     string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
     EXPECT_EQ(8U, ciphertext.size());
     EXPECT_NE(ciphertext, message);
-    ++ciphertext[ciphertext.size() / 2];
 
     auto begin_params = AuthorizationSetBuilder()
                             .BlockMode(BlockMode::CBC)
                             .Padding(PaddingMode::PKCS7)
                             .Authorization(TAG_NONCE, iv);
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
-    string plaintext;
-    size_t input_consumed;
-    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
-    EXPECT_EQ(ciphertext.size(), input_consumed);
-    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+    for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
+        ++ciphertext[ciphertext.size() / 2];
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+        string plaintext;
+        size_t input_consumed;
+        EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+        EXPECT_EQ(ciphertext.size(), input_consumed);
+        ErrorCode error = Finish(&plaintext);
+        if (error == ErrorCode::INVALID_ARGUMENT) {
+            // This is the expected error, we can exit the test now.
+            return;
+        } else {
+            // Very small chance we got valid decryption, so try again.
+            ASSERT_EQ(error, ErrorCode::OK);
+        }
+    }
+    FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
 }
 
 /*
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
index c650bec..547ce38 100644
--- a/keymaster/4.1/vts/functional/Android.bp
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -48,4 +48,7 @@
         "general-tests",
         "vts",
     ],
+    sanitize: {
+        cfi: false,
+    },
 }
diff --git a/light/aidl/default/main.cpp b/light/aidl/default/main.cpp
index a860bf4..54e1316 100644
--- a/light/aidl/default/main.cpp
+++ b/light/aidl/default/main.cpp
@@ -28,7 +28,7 @@
 
     const std::string instance = std::string() + Lights::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reached
diff --git a/media/omx/1.0/vts/OWNERS b/media/omx/1.0/vts/OWNERS
index e0e0dd1..9e390c2 100644
--- a/media/omx/1.0/vts/OWNERS
+++ b/media/omx/1.0/vts/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 25690
 # Media team
-pawin@google.com
+taklee@google.com
+wonsik@google.com
 lajos@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
\ No newline at end of file
diff --git a/memtrack/OWNERS b/memtrack/OWNERS
new file mode 100644
index 0000000..a182ed9
--- /dev/null
+++ b/memtrack/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 30545
+connoro@google.com
diff --git a/memtrack/aidl/default/main.cpp b/memtrack/aidl/default/main.cpp
index d063d2a..5cf5f94 100644
--- a/memtrack/aidl/default/main.cpp
+++ b/memtrack/aidl/default/main.cpp
@@ -29,7 +29,7 @@
     const std::string instance = std::string() + Memtrack::descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(memtrack->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // Unreachable
diff --git a/neuralnetworks/1.0/utils/Android.bp b/neuralnetworks/1.0/utils/Android.bp
index 31cdded..ad30e30 100644
--- a/neuralnetworks/1.0/utils/Android.bp
+++ b/neuralnetworks/1.0/utils/Android.bp
@@ -31,16 +31,11 @@
     export_include_dirs: ["include"],
     cflags: ["-Wthread-safety"],
     static_libs: [
+        "android.hardware.neuralnetworks@1.0",
         "libarect",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
     ],
-    shared_libs: [
-        "android.hardware.neuralnetworks@1.0",
-    ],
-    export_static_lib_headers: [
-        "neuralnetworks_utils_hal_common",
-    ],
     target: {
         android: {
             shared_libs: ["libnativewindow"],
@@ -55,19 +50,14 @@
     static_libs: [
         "android.hardware.neuralnetworks@1.0",
         "libgmock",
-        "libneuralnetworks_common",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
     ],
     shared_libs: [
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
         "libbase",
         "libcutils",
-        "libfmq",
         "libhidlbase",
-        "libhidlmemory",
         "liblog",
         "libutils",
     ],
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
index 8bd2fbe..cef76c6 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
@@ -45,12 +45,15 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
   private:
     const nn::SharedPreparedModel kPreparedModel;
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
index 0a6ca3e..d7c43ef 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
@@ -65,8 +65,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache,
-            const nn::CacheToken& token) const override;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
index bdb5b54..337c132 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
@@ -49,18 +49,23 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
             const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
             const nn::OptionalDuration& loopTimeoutDuration,
-            const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+            const nn::OptionalDuration& timeoutDurationAfterFence,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
 
diff --git a/neuralnetworks/1.0/utils/src/Burst.cpp b/neuralnetworks/1.0/utils/src/Burst.cpp
index 1284721..3642bc6 100644
--- a/neuralnetworks/1.0/utils/src/Burst.cpp
+++ b/neuralnetworks/1.0/utils/src/Burst.cpp
@@ -50,15 +50,20 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalTimePoint& deadline,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
-    return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
+        const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+    return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration, hints,
+                                   extensionNameToPrefix);
 }
 
 nn::GeneralResult<nn::SharedExecution> Burst::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
-    return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration);
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+    return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration, hints,
+                                                   extensionNameToPrefix);
 }
 
 }  // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Device.cpp b/neuralnetworks/1.0/utils/src/Device.cpp
index b0c236e..620d040 100644
--- a/neuralnetworks/1.0/utils/src/Device.cpp
+++ b/neuralnetworks/1.0/utils/src/Device.cpp
@@ -143,7 +143,9 @@
 nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
         const nn::Model& model, nn::ExecutionPreference /*preference*/, nn::Priority /*priority*/,
         nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
-        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that model is ready for IPC.
     std::optional<nn::Model> maybeModelInShared;
     const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
index 00e7d22..b8055fc 100644
--- a/neuralnetworks/1.0/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
@@ -59,7 +59,9 @@
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
         const nn::Request& request, nn::MeasureTiming /*measure*/,
         const nn::OptionalTimePoint& /*deadline*/,
-        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
@@ -94,19 +96,22 @@
 }
 
 nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& /*request*/,
-                             const std::vector<nn::SyncFence>& /*waitFor*/,
-                             nn::MeasureTiming /*measure*/,
-                             const nn::OptionalTimePoint& /*deadline*/,
-                             const nn::OptionalDuration& /*loopTimeoutDuration*/,
-                             const nn::OptionalDuration& /*timeoutDurationAfterFence*/) const {
+PreparedModel::executeFenced(
+        const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+        nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const nn::OptionalDuration& /*timeoutDurationAfterFence*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
            << "IPreparedModel::executeFenced is not supported on 1.0 HAL service";
 }
 
 nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming /*measure*/,
-        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
diff --git a/neuralnetworks/1.0/utils/test/DeviceTest.cpp b/neuralnetworks/1.0/utils/test/DeviceTest.cpp
index 83e555f..9e9db16 100644
--- a/neuralnetworks/1.0/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.0/utils/test/DeviceTest.cpp
@@ -380,7 +380,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -399,7 +399,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -417,7 +417,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -435,7 +435,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -452,7 +452,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -469,7 +469,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -488,7 +488,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
index 7820c06..e03a98d 100644
--- a/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
@@ -121,7 +121,7 @@
             .WillOnce(Invoke(makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     EXPECT_TRUE(result.has_value())
@@ -138,7 +138,7 @@
                                          V1_0::ErrorStatus::GENERAL_FAILURE)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -155,7 +155,7 @@
                     makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -171,7 +171,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -187,7 +187,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -205,7 +205,7 @@
     EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -218,7 +218,7 @@
     const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -235,7 +235,7 @@
             .WillRepeatedly(Invoke(makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -258,7 +258,7 @@
                                          V1_0::ErrorStatus::GENERAL_FAILURE)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -279,7 +279,7 @@
                     makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -299,7 +299,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -319,7 +319,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -341,7 +341,7 @@
     EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -358,7 +358,7 @@
     const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
diff --git a/neuralnetworks/1.1/utils/Android.bp b/neuralnetworks/1.1/utils/Android.bp
index 737ff58..4b8999f 100644
--- a/neuralnetworks/1.1/utils/Android.bp
+++ b/neuralnetworks/1.1/utils/Android.bp
@@ -31,17 +31,12 @@
     export_include_dirs: ["include"],
     cflags: ["-Wthread-safety"],
     static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
     ],
-    shared_libs: [
-        "android.hardware.neuralnetworks@1.0",
-        "android.hardware.neuralnetworks@1.1",
-    ],
-    export_static_lib_headers: [
-        "neuralnetworks_utils_hal_common",
-    ],
 }
 
 cc_test {
@@ -52,20 +47,15 @@
         "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
         "libgmock",
-        "libneuralnetworks_common",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
         "neuralnetworks_utils_hal_1_1",
     ],
     shared_libs: [
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
         "libbase",
         "libcutils",
-        "libfmq",
         "libhidlbase",
-        "libhidlmemory",
         "liblog",
         "libutils",
     ],
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
index d6bd36a..38ca138 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
@@ -64,8 +64,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache,
-            const nn::CacheToken& token) const override;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.1/utils/src/Device.cpp b/neuralnetworks/1.1/utils/src/Device.cpp
index 3effa84..28f3276 100644
--- a/neuralnetworks/1.1/utils/src/Device.cpp
+++ b/neuralnetworks/1.1/utils/src/Device.cpp
@@ -143,7 +143,9 @@
 nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
         const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
         nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
-        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that model is ready for IPC.
     std::optional<nn::Model> maybeModelInShared;
     const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.1/utils/test/DeviceTest.cpp b/neuralnetworks/1.1/utils/test/DeviceTest.cpp
index 2248da6..8ab87bc 100644
--- a/neuralnetworks/1.1/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.1/utils/test/DeviceTest.cpp
@@ -390,7 +390,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -409,7 +409,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -427,7 +427,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -445,7 +445,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -462,7 +462,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -479,7 +479,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -498,7 +498,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.2/utils/Android.bp b/neuralnetworks/1.2/utils/Android.bp
index 4eefb0f..4c5f065 100644
--- a/neuralnetworks/1.2/utils/Android.bp
+++ b/neuralnetworks/1.2/utils/Android.bp
@@ -31,19 +31,14 @@
     export_include_dirs: ["include"],
     cflags: ["-Wthread-safety"],
     static_libs: [
-        "neuralnetworks_types",
-        "neuralnetworks_utils_hal_common",
-        "neuralnetworks_utils_hal_1_0",
-        "neuralnetworks_utils_hal_1_1",
-    ],
-    shared_libs: [
         "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
         "android.hardware.neuralnetworks@1.2",
         "libfmq",
-    ],
-    export_static_lib_headers: [
+        "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
+        "neuralnetworks_utils_hal_1_0",
+        "neuralnetworks_utils_hal_1_1",
     ],
     product_variables: {
         debuggable: { // eng and userdebug builds
@@ -71,7 +66,6 @@
         "android.hardware.neuralnetworks@1.1",
         "android.hardware.neuralnetworks@1.2",
         "libgmock",
-        "libneuralnetworks_common",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
@@ -79,13 +73,10 @@
         "neuralnetworks_utils_hal_1_2",
     ],
     shared_libs: [
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
         "libbase",
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidlmemory",
         "liblog",
         "libutils",
     ],
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h
index ac9411c..1b28476 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h
@@ -170,13 +170,16 @@
     // See IBurst::execute for information on this method.
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     // See IBurst::createReusableExecution for information on this method.
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     // If fallback is not nullptr, this method will invoke the fallback function to try another
     // execution path if the packet could not be sent. Otherwise, failing to send the packet will
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
index c3348aa..4f13adc 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
@@ -37,7 +37,7 @@
 GeneralResult<Operand::ExtraParams> unvalidatedConvert(
         const hal::V1_2::Operand::ExtraParams& extraParams);
 GeneralResult<Model> unvalidatedConvert(const hal::V1_2::Model& model);
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
         const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
 GeneralResult<OutputShape> unvalidatedConvert(const hal::V1_2::OutputShape& outputShape);
 GeneralResult<MeasureTiming> unvalidatedConvert(const hal::V1_2::MeasureTiming& measureTiming);
@@ -78,7 +78,7 @@
         const nn::Operand::ExtraParams& extraParams);
 nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
 nn::GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
-        const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
+        const nn::ExtensionNameAndPrefix& extensionNameAndPrefix);
 nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape);
 nn::GeneralResult<MeasureTiming> unvalidatedConvert(const nn::MeasureTiming& measureTiming);
 nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing);
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
index e7ac172..d92cf50 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
@@ -83,8 +83,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache,
-            const nn::CacheToken& token) const override;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
index 1150e5e..72a5b2f 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
@@ -49,18 +49,23 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
             const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
             const nn::OptionalDuration& loopTimeoutDuration,
-            const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+            const nn::OptionalDuration& timeoutDurationAfterFence,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
 
diff --git a/neuralnetworks/1.2/utils/src/Burst.cpp b/neuralnetworks/1.2/utils/src/Burst.cpp
index 911fbfa..23e8070 100644
--- a/neuralnetworks/1.2/utils/src/Burst.cpp
+++ b/neuralnetworks/1.2/utils/src/Burst.cpp
@@ -305,8 +305,9 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalTimePoint& deadline,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // This is the first point when we know an execution is occurring, so begin to collect
     // systraces. Note that the first point we can begin collecting systraces in
     // ExecutionBurstServer is when the RequestChannelReceiver realizes there is data in the FMQ, so
@@ -317,7 +318,7 @@
     // fall back to another execution path
     if (!compliantVersion(request).ok()) {
         // fallback to another execution path if the packet could not be sent
-        return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
+        return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration, {}, {});
     }
 
     // ensure that request is ready for IPC
@@ -346,7 +347,7 @@
     // send request packet
     const auto requestPacket = serialize(hidlRequest, hidlMeasure, slots);
     const auto fallback = [this, &request, measure, &deadline, &loopTimeoutDuration] {
-        return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
+        return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration, {}, {});
     };
     return executeInternal(requestPacket, relocation, fallback);
 }
@@ -354,14 +355,17 @@
 // See IBurst::createReusableExecution for information on this method.
 nn::GeneralResult<nn::SharedExecution> Burst::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     NNTRACE_RT(NNTRACE_PHASE_EXECUTION, "Burst::createReusableExecution");
 
     // if the request is valid but of a higher version than what's supported in burst execution,
     // fall back to another execution path
     if (!compliantVersion(request).ok()) {
         // fallback to another execution path if the packet could not be sent
-        return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration);
+        return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration, {},
+                                                       {});
     }
 
     // ensure that request is ready for IPC
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index 838d9c4..62ec2ed 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -212,9 +212,9 @@
     };
 }
 
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
         const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
-    return Model::ExtensionNameAndPrefix{
+    return ExtensionNameAndPrefix{
             .name = extensionNameAndPrefix.name,
             .prefix = extensionNameAndPrefix.prefix,
     };
@@ -495,7 +495,7 @@
 }
 
 nn::GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
-        const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
+        const nn::ExtensionNameAndPrefix& extensionNameAndPrefix) {
     return Model::ExtensionNameAndPrefix{
             .name = extensionNameAndPrefix.name,
             .prefix = extensionNameAndPrefix.prefix,
diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp
index e7acecd..3a58d2c 100644
--- a/neuralnetworks/1.2/utils/src/Device.cpp
+++ b/neuralnetworks/1.2/utils/src/Device.cpp
@@ -236,7 +236,9 @@
 nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
         const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
         nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& modelCache,
-        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that model is ready for IPC.
     std::optional<nn::Model> maybeModelInShared;
     const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
index 6df3df3..feb3951 100644
--- a/neuralnetworks/1.2/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
@@ -91,7 +91,9 @@
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
         const nn::Request& request, nn::MeasureTiming measure,
         const nn::OptionalTimePoint& /*deadline*/,
-        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
@@ -123,19 +125,22 @@
 }
 
 nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& /*request*/,
-                             const std::vector<nn::SyncFence>& /*waitFor*/,
-                             nn::MeasureTiming /*measure*/,
-                             const nn::OptionalTimePoint& /*deadline*/,
-                             const nn::OptionalDuration& /*loopTimeoutDuration*/,
-                             const nn::OptionalDuration& /*timeoutDurationAfterFence*/) const {
+PreparedModel::executeFenced(
+        const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+        nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const nn::OptionalDuration& /*timeoutDurationAfterFence*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
            << "IPreparedModel::executeFenced is not supported on 1.2 HAL service";
 }
 
 nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
diff --git a/neuralnetworks/1.2/utils/test/DeviceTest.cpp b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
index 1dc6285..0d8c141 100644
--- a/neuralnetworks/1.2/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
@@ -636,7 +636,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -655,7 +655,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -673,7 +673,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -691,7 +691,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -708,7 +708,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -725,7 +725,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -746,7 +746,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
index 5e2ad79..a5ec9d3 100644
--- a/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
@@ -154,7 +154,7 @@
             .WillOnce(Invoke(makeExecuteSynchronously(V1_0::ErrorStatus::NONE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     EXPECT_TRUE(result.has_value())
@@ -172,7 +172,7 @@
                     makeExecuteSynchronously(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -189,7 +189,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -206,7 +206,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -224,7 +224,7 @@
                                                        V1_0::ErrorStatus::NONE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     EXPECT_TRUE(result.has_value())
@@ -243,7 +243,7 @@
                                                        kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -261,7 +261,7 @@
                     V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -278,7 +278,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -295,7 +295,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -314,7 +314,7 @@
     EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -328,7 +328,7 @@
             PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -347,7 +347,7 @@
                     Invoke(makeExecuteSynchronously(V1_0::ErrorStatus::NONE, {}, kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -371,7 +371,7 @@
                     makeExecuteSynchronously(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -392,7 +392,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -413,7 +413,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -436,7 +436,7 @@
                     V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, {}, kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -461,7 +461,7 @@
                                                        kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -483,7 +483,7 @@
                     V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -504,7 +504,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -525,7 +525,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -548,7 +548,7 @@
     EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -566,7 +566,7 @@
             PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
diff --git a/neuralnetworks/1.3/utils/Android.bp b/neuralnetworks/1.3/utils/Android.bp
index 7acb4fc..c512dda 100644
--- a/neuralnetworks/1.3/utils/Android.bp
+++ b/neuralnetworks/1.3/utils/Android.bp
@@ -31,21 +31,16 @@
     export_include_dirs: ["include"],
     cflags: ["-Wthread-safety"],
     static_libs: [
-        "neuralnetworks_types",
-        "neuralnetworks_utils_hal_common",
-        "neuralnetworks_utils_hal_1_0",
-        "neuralnetworks_utils_hal_1_1",
-        "neuralnetworks_utils_hal_1_2",
-    ],
-    shared_libs: [
         "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
         "android.hardware.neuralnetworks@1.2",
         "android.hardware.neuralnetworks@1.3",
         "libfmq",
-    ],
-    export_static_lib_headers: [
+        "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
+        "neuralnetworks_utils_hal_1_0",
+        "neuralnetworks_utils_hal_1_1",
+        "neuralnetworks_utils_hal_1_2",
     ],
     target: {
         host: {
@@ -69,7 +64,6 @@
         "android.hardware.neuralnetworks@1.2",
         "android.hardware.neuralnetworks@1.3",
         "libgmock",
-        "libneuralnetworks_common",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
@@ -78,13 +72,10 @@
         "neuralnetworks_utils_hal_1_3",
     ],
     shared_libs: [
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
         "libbase",
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidlmemory",
         "liblog",
         "libutils",
     ],
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
index c3c6fc4..cf5e5ea0 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
@@ -66,8 +66,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache,
-            const nn::CacheToken& token) const override;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
index 480438d..124cc43 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
@@ -48,18 +48,23 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
             const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
             const nn::OptionalDuration& loopTimeoutDuration,
-            const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+            const nn::OptionalDuration& timeoutDurationAfterFence,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
 
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index a1d414c..09e9d80 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -396,7 +396,7 @@
 }
 
 nn::GeneralResult<V1_2::Model::ExtensionNameAndPrefix> unvalidatedConvert(
-        const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
+        const nn::ExtensionNameAndPrefix& extensionNameAndPrefix) {
     return V1_2::utils::unvalidatedConvert(extensionNameAndPrefix);
 }
 
diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp
index 9517fda..824cec6 100644
--- a/neuralnetworks/1.3/utils/src/Device.cpp
+++ b/neuralnetworks/1.3/utils/src/Device.cpp
@@ -187,7 +187,9 @@
 nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
         const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
         nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that model is ready for IPC.
     std::optional<nn::Model> maybeModelInShared;
     const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
index ce977e5..b92f877 100644
--- a/neuralnetworks/1.3/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
@@ -135,8 +135,9 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalTimePoint& deadline,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
@@ -174,10 +175,13 @@
 }
 
 nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
-                             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
-                             const nn::OptionalDuration& loopTimeoutDuration,
-                             const nn::OptionalDuration& timeoutDurationAfterFence) const {
+PreparedModel::executeFenced(
+        const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+        nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const nn::OptionalDuration& timeoutDurationAfterFence,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
@@ -230,7 +234,9 @@
 
 nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
diff --git a/neuralnetworks/1.3/utils/test/DeviceTest.cpp b/neuralnetworks/1.3/utils/test/DeviceTest.cpp
index 7eba4bc..6f48837 100644
--- a/neuralnetworks/1.3/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.3/utils/test/DeviceTest.cpp
@@ -658,7 +658,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -677,7 +677,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -695,7 +695,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -713,7 +713,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -730,7 +730,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -747,7 +747,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -768,7 +768,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
index 6dbbd6b..51b5d29 100644
--- a/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
@@ -182,7 +182,7 @@
             .WillOnce(Invoke(makeExecuteSynchronously(V1_3::ErrorStatus::NONE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     EXPECT_TRUE(result.has_value())
@@ -200,7 +200,7 @@
                     makeExecuteSynchronously(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -217,7 +217,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -234,7 +234,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -252,7 +252,7 @@
                                                        V1_3::ErrorStatus::NONE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     EXPECT_TRUE(result.has_value())
@@ -271,7 +271,7 @@
                                                        kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -289,7 +289,7 @@
                     V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -306,7 +306,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -323,7 +323,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -344,7 +344,7 @@
             .WillOnce(InvokeWithoutArgs(ret));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -366,7 +366,7 @@
             .WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -396,7 +396,7 @@
             .WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -422,7 +422,7 @@
                     makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, {}, nullptr)));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -439,7 +439,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -456,7 +456,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -475,7 +475,7 @@
                     Invoke(makeExecuteSynchronously(V1_3::ErrorStatus::NONE, {}, kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -499,7 +499,7 @@
                     makeExecuteSynchronously(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -520,7 +520,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -541,7 +541,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -564,7 +564,7 @@
                     V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, {}, kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -589,7 +589,7 @@
                                                        kNoTiming)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -611,7 +611,7 @@
                     V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -628,7 +628,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -649,7 +649,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -674,7 +674,7 @@
             .WillOnce(InvokeWithoutArgs(ret));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -702,7 +702,7 @@
                     Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -738,7 +738,7 @@
             .WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -768,7 +768,7 @@
                     makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, {}, nullptr)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -789,7 +789,7 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -810,7 +810,7 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
diff --git a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
index e2fa6e4..af3641a 100644
--- a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
@@ -1158,12 +1158,15 @@
     auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}, kTestOperand.dimensions);
     if (buffer == nullptr) return;
 
-    Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
-    Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+    // Use an incompatible dimension and make sure the length matches with the bad dimension.
     auto badDimensions = kTestOperand.dimensions;
     badDimensions[0] = 2;
+    const uint32_t badTestOperandDataSize = kTestOperandDataSize * 2;
+
+    Request::MemoryPool sharedMemory = createSharedMemoryPool(badTestOperandDataSize);
+    Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
     RequestArgument sharedMemoryArg = {
-            .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize},
+            .location = {.poolIndex = 0, .offset = 0, .length = badTestOperandDataSize},
             .dimensions = badDimensions};
     RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
     RequestArgument deviceMemoryArgWithBadDimensions = {.location = {.poolIndex = 1},
diff --git a/neuralnetworks/OWNERS b/neuralnetworks/OWNERS
index def3ea9..04c5d72 100644
--- a/neuralnetworks/OWNERS
+++ b/neuralnetworks/OWNERS
@@ -1,10 +1,2 @@
 # Bug component: 195575
-# Neuralnetworks team
-butlermichael@google.com
-dgross@google.com
-galarragas@google.com
-ianhua@google.com
-jeanluc@google.com
-miaowang@google.com
-pszczepaniak@google.com
-xusongw@google.com
+include platform/packages/modules/NeuralNetworks:/NNAPI_OWNERS  # Neuralnetworks team
diff --git a/neuralnetworks/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index cbb6ce5..47f3b30 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -38,5 +38,6 @@
     versions: [
         "1",
         "2",
+        "3",
     ],
 }
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/.hash b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/.hash
new file mode 100644
index 0000000..3b9f018
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/.hash
@@ -0,0 +1 @@
+8c2c4ca2327e6f779dad6119c03d832ea4e1def1
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/BufferDesc.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/BufferDesc.aidl
new file mode 100644
index 0000000..05cec76
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/BufferDesc.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable BufferDesc {
+  int[] dimensions;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/BufferRole.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/BufferRole.aidl
new file mode 100644
index 0000000..10a6b75
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/BufferRole.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable BufferRole {
+  int modelIndex;
+  int ioIndex;
+  float probability;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Capabilities.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Capabilities.aidl
new file mode 100644
index 0000000..30877c0
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Capabilities.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Capabilities {
+  android.hardware.neuralnetworks.PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+  android.hardware.neuralnetworks.PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+  android.hardware.neuralnetworks.OperandPerformance[] operandPerformance;
+  android.hardware.neuralnetworks.PerformanceInfo ifPerformance;
+  android.hardware.neuralnetworks.PerformanceInfo whilePerformance;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DataLocation.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DataLocation.aidl
new file mode 100644
index 0000000..db49a38
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DataLocation.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable DataLocation {
+  int poolIndex;
+  long offset;
+  long length;
+  long padding;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DeviceBuffer.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DeviceBuffer.aidl
new file mode 100644
index 0000000..7cdd6db
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DeviceBuffer.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable DeviceBuffer {
+  android.hardware.neuralnetworks.IBuffer buffer;
+  int token;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DeviceType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DeviceType.aidl
new file mode 100644
index 0000000..82fe8ae
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/DeviceType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum DeviceType {
+  OTHER = 1,
+  CPU = 2,
+  GPU = 3,
+  ACCELERATOR = 4,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ErrorStatus.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ErrorStatus.aidl
new file mode 100644
index 0000000..57d5d6e
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ErrorStatus.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum ErrorStatus {
+  NONE = 0,
+  DEVICE_UNAVAILABLE = 1,
+  GENERAL_FAILURE = 2,
+  OUTPUT_INSUFFICIENT_SIZE = 3,
+  INVALID_ARGUMENT = 4,
+  MISSED_DEADLINE_TRANSIENT = 5,
+  MISSED_DEADLINE_PERSISTENT = 6,
+  RESOURCE_EXHAUSTED_TRANSIENT = 7,
+  RESOURCE_EXHAUSTED_PERSISTENT = 8,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExecutionPreference.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExecutionPreference.aidl
new file mode 100644
index 0000000..4352d8f
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExecutionPreference.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum ExecutionPreference {
+  LOW_POWER = 0,
+  FAST_SINGLE_ANSWER = 1,
+  SUSTAINED_SPEED = 2,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExecutionResult.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExecutionResult.aidl
new file mode 100644
index 0000000..44e9922
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExecutionResult.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable ExecutionResult {
+  boolean outputSufficientSize;
+  android.hardware.neuralnetworks.OutputShape[] outputShapes;
+  android.hardware.neuralnetworks.Timing timing;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Extension.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Extension.aidl
new file mode 100644
index 0000000..c47028d
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Extension.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Extension {
+  String name;
+  android.hardware.neuralnetworks.ExtensionOperandTypeInformation[] operandTypes;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
new file mode 100644
index 0000000..6c287fd
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable ExtensionNameAndPrefix {
+  String name;
+  char prefix;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
new file mode 100644
index 0000000..a3680aa
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable ExtensionOperandTypeInformation {
+  char type;
+  boolean isTensor;
+  int byteSize;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/FencedExecutionResult.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/FencedExecutionResult.aidl
new file mode 100644
index 0000000..7952b34
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/FencedExecutionResult.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.neuralnetworks;
+@VintfStability
+parcelable FencedExecutionResult {
+  android.hardware.neuralnetworks.IFencedExecutionCallback callback;
+  @nullable ParcelFileDescriptor syncFence;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/FusedActivationFunc.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/FusedActivationFunc.aidl
new file mode 100644
index 0000000..7e61bbb
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/FusedActivationFunc.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum FusedActivationFunc {
+  NONE = 0,
+  RELU = 1,
+  RELU1 = 2,
+  RELU6 = 3,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IBuffer.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IBuffer.aidl
new file mode 100644
index 0000000..f10e7e2
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IBuffer.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+interface IBuffer {
+  void copyFrom(in android.hardware.neuralnetworks.Memory src, in int[] dimensions);
+  void copyTo(in android.hardware.neuralnetworks.Memory dst);
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IBurst.aidl
new file mode 100644
index 0000000..eb3d0b0
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IBurst.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.neuralnetworks;
+@VintfStability
+interface IBurst {
+  android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
+  void releaseMemoryResource(in long memoryIdentifierToken);
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IDevice.aidl
new file mode 100644
index 0000000..c9c67f2
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IDevice.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+interface IDevice {
+  android.hardware.neuralnetworks.DeviceBuffer allocate(in android.hardware.neuralnetworks.BufferDesc desc, in android.hardware.neuralnetworks.IPreparedModelParcel[] preparedModels, in android.hardware.neuralnetworks.BufferRole[] inputRoles, in android.hardware.neuralnetworks.BufferRole[] outputRoles);
+  android.hardware.neuralnetworks.Capabilities getCapabilities();
+  android.hardware.neuralnetworks.NumberOfCacheFiles getNumberOfCacheFilesNeeded();
+  android.hardware.neuralnetworks.Extension[] getSupportedExtensions();
+  boolean[] getSupportedOperations(in android.hardware.neuralnetworks.Model model);
+  android.hardware.neuralnetworks.DeviceType getType();
+  String getVersionString();
+  void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+  void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+  const int BYTE_SIZE_OF_CACHE_TOKEN = 32;
+  const int MAX_NUMBER_OF_CACHE_FILES = 32;
+  const int EXTENSION_TYPE_HIGH_BITS_PREFIX = 15;
+  const int EXTENSION_TYPE_LOW_BITS_TYPE = 16;
+  const int OPERAND_TYPE_BASE_MAX = 65535;
+  const int OPERATION_TYPE_BASE_MAX = 65535;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
new file mode 100644
index 0000000..0bfb80a
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+interface IFencedExecutionCallback {
+  android.hardware.neuralnetworks.ErrorStatus getExecutionInfo(out android.hardware.neuralnetworks.Timing timingLaunched, out android.hardware.neuralnetworks.Timing timingFenced);
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModel.aidl
new file mode 100644
index 0000000..fccb5dc
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+interface IPreparedModel {
+  android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
+  android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs, in long durationNs);
+  android.hardware.neuralnetworks.IBurst configureExecutionBurst();
+  const long DEFAULT_LOOP_TIMEOUT_DURATION_NS = 2000000000;
+  const long MAXIMUM_LOOP_TIMEOUT_DURATION_NS = 15000000000;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModelCallback.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
new file mode 100644
index 0000000..e0c763b
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+interface IPreparedModelCallback {
+  void notify(in android.hardware.neuralnetworks.ErrorStatus status, in android.hardware.neuralnetworks.IPreparedModel preparedModel);
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModelParcel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
new file mode 100644
index 0000000..dbedf12
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable IPreparedModelParcel {
+  android.hardware.neuralnetworks.IPreparedModel preparedModel;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Memory.aidl
new file mode 100644
index 0000000..37fa102
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Memory.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+union Memory {
+  android.hardware.common.Ashmem ashmem;
+  android.hardware.common.MappableFile mappableFile;
+  android.hardware.graphics.common.HardwareBuffer hardwareBuffer;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Model.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Model.aidl
new file mode 100644
index 0000000..30d8dda
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Model.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Model {
+  android.hardware.neuralnetworks.Subgraph main;
+  android.hardware.neuralnetworks.Subgraph[] referenced;
+  byte[] operandValues;
+  android.hardware.neuralnetworks.Memory[] pools;
+  boolean relaxComputationFloat32toFloat16;
+  android.hardware.neuralnetworks.ExtensionNameAndPrefix[] extensionNameToPrefix;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/NumberOfCacheFiles.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/NumberOfCacheFiles.aidl
new file mode 100644
index 0000000..9314760
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/NumberOfCacheFiles.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable NumberOfCacheFiles {
+  int numModelCache;
+  int numDataCache;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Operand.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Operand.aidl
new file mode 100644
index 0000000..1d9bdd8
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Operand.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Operand {
+  android.hardware.neuralnetworks.OperandType type = android.hardware.neuralnetworks.OperandType.FLOAT32;
+  int[] dimensions;
+  float scale;
+  int zeroPoint;
+  android.hardware.neuralnetworks.OperandLifeTime lifetime = android.hardware.neuralnetworks.OperandLifeTime.TEMPORARY_VARIABLE;
+  android.hardware.neuralnetworks.DataLocation location;
+  @nullable android.hardware.neuralnetworks.OperandExtraParams extraParams;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandExtraParams.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandExtraParams.aidl
new file mode 100644
index 0000000..14792cf
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandExtraParams.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+union OperandExtraParams {
+  android.hardware.neuralnetworks.SymmPerChannelQuantParams channelQuant;
+  byte[] extension;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandLifeTime.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandLifeTime.aidl
new file mode 100644
index 0000000..40adfb1
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandLifeTime.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum OperandLifeTime {
+  TEMPORARY_VARIABLE = 0,
+  SUBGRAPH_INPUT = 1,
+  SUBGRAPH_OUTPUT = 2,
+  CONSTANT_COPY = 3,
+  CONSTANT_POOL = 4,
+  NO_VALUE = 5,
+  SUBGRAPH = 6,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandPerformance.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandPerformance.aidl
new file mode 100644
index 0000000..ebb361b
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandPerformance.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable OperandPerformance {
+  android.hardware.neuralnetworks.OperandType type = android.hardware.neuralnetworks.OperandType.FLOAT32;
+  android.hardware.neuralnetworks.PerformanceInfo info;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandType.aidl
new file mode 100644
index 0000000..9f2c759
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperandType.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum OperandType {
+  FLOAT32 = 0,
+  INT32 = 1,
+  UINT32 = 2,
+  TENSOR_FLOAT32 = 3,
+  TENSOR_INT32 = 4,
+  TENSOR_QUANT8_ASYMM = 5,
+  BOOL = 6,
+  TENSOR_QUANT16_SYMM = 7,
+  TENSOR_FLOAT16 = 8,
+  TENSOR_BOOL8 = 9,
+  FLOAT16 = 10,
+  TENSOR_QUANT8_SYMM_PER_CHANNEL = 11,
+  TENSOR_QUANT16_ASYMM = 12,
+  TENSOR_QUANT8_SYMM = 13,
+  TENSOR_QUANT8_ASYMM_SIGNED = 14,
+  SUBGRAPH = 15,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Operation.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Operation.aidl
new file mode 100644
index 0000000..a4a3fbe
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Operation.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Operation {
+  android.hardware.neuralnetworks.OperationType type = android.hardware.neuralnetworks.OperationType.ADD;
+  int[] inputs;
+  int[] outputs;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperationType.aidl
new file mode 100644
index 0000000..34506c8
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OperationType.aidl
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum OperationType {
+  ADD = 0,
+  AVERAGE_POOL_2D = 1,
+  CONCATENATION = 2,
+  CONV_2D = 3,
+  DEPTHWISE_CONV_2D = 4,
+  DEPTH_TO_SPACE = 5,
+  DEQUANTIZE = 6,
+  EMBEDDING_LOOKUP = 7,
+  FLOOR = 8,
+  FULLY_CONNECTED = 9,
+  HASHTABLE_LOOKUP = 10,
+  L2_NORMALIZATION = 11,
+  L2_POOL_2D = 12,
+  LOCAL_RESPONSE_NORMALIZATION = 13,
+  LOGISTIC = 14,
+  LSH_PROJECTION = 15,
+  LSTM = 16,
+  MAX_POOL_2D = 17,
+  MUL = 18,
+  RELU = 19,
+  RELU1 = 20,
+  RELU6 = 21,
+  RESHAPE = 22,
+  RESIZE_BILINEAR = 23,
+  RNN = 24,
+  SOFTMAX = 25,
+  SPACE_TO_DEPTH = 26,
+  SVDF = 27,
+  TANH = 28,
+  BATCH_TO_SPACE_ND = 29,
+  DIV = 30,
+  MEAN = 31,
+  PAD = 32,
+  SPACE_TO_BATCH_ND = 33,
+  SQUEEZE = 34,
+  STRIDED_SLICE = 35,
+  SUB = 36,
+  TRANSPOSE = 37,
+  ABS = 38,
+  ARGMAX = 39,
+  ARGMIN = 40,
+  AXIS_ALIGNED_BBOX_TRANSFORM = 41,
+  BIDIRECTIONAL_SEQUENCE_LSTM = 42,
+  BIDIRECTIONAL_SEQUENCE_RNN = 43,
+  BOX_WITH_NMS_LIMIT = 44,
+  CAST = 45,
+  CHANNEL_SHUFFLE = 46,
+  DETECTION_POSTPROCESSING = 47,
+  EQUAL = 48,
+  EXP = 49,
+  EXPAND_DIMS = 50,
+  GATHER = 51,
+  GENERATE_PROPOSALS = 52,
+  GREATER = 53,
+  GREATER_EQUAL = 54,
+  GROUPED_CONV_2D = 55,
+  HEATMAP_MAX_KEYPOINT = 56,
+  INSTANCE_NORMALIZATION = 57,
+  LESS = 58,
+  LESS_EQUAL = 59,
+  LOG = 60,
+  LOGICAL_AND = 61,
+  LOGICAL_NOT = 62,
+  LOGICAL_OR = 63,
+  LOG_SOFTMAX = 64,
+  MAXIMUM = 65,
+  MINIMUM = 66,
+  NEG = 67,
+  NOT_EQUAL = 68,
+  PAD_V2 = 69,
+  POW = 70,
+  PRELU = 71,
+  QUANTIZE = 72,
+  QUANTIZED_16BIT_LSTM = 73,
+  RANDOM_MULTINOMIAL = 74,
+  REDUCE_ALL = 75,
+  REDUCE_ANY = 76,
+  REDUCE_MAX = 77,
+  REDUCE_MIN = 78,
+  REDUCE_PROD = 79,
+  REDUCE_SUM = 80,
+  ROI_ALIGN = 81,
+  ROI_POOLING = 82,
+  RSQRT = 83,
+  SELECT = 84,
+  SIN = 85,
+  SLICE = 86,
+  SPLIT = 87,
+  SQRT = 88,
+  TILE = 89,
+  TOPK_V2 = 90,
+  TRANSPOSE_CONV_2D = 91,
+  UNIDIRECTIONAL_SEQUENCE_LSTM = 92,
+  UNIDIRECTIONAL_SEQUENCE_RNN = 93,
+  RESIZE_NEAREST_NEIGHBOR = 94,
+  QUANTIZED_LSTM = 95,
+  IF = 96,
+  WHILE = 97,
+  ELU = 98,
+  HARD_SWISH = 99,
+  FILL = 100,
+  RANK = 101,
+  BATCH_MATMUL = 102,
+  PACK = 103,
+  MIRROR_PAD = 104,
+  REVERSE = 105,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OutputShape.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OutputShape.aidl
new file mode 100644
index 0000000..f733505
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/OutputShape.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable OutputShape {
+  int[] dimensions;
+  boolean isSufficient;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/PerformanceInfo.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/PerformanceInfo.aidl
new file mode 100644
index 0000000..04910f5
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/PerformanceInfo.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable PerformanceInfo {
+  float execTime;
+  float powerUsage;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Priority.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Priority.aidl
new file mode 100644
index 0000000..8f35709
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Priority.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@Backing(type="int") @VintfStability
+enum Priority {
+  LOW = 0,
+  MEDIUM = 1,
+  HIGH = 2,
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Request.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Request.aidl
new file mode 100644
index 0000000..39ec7a9
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Request.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Request {
+  android.hardware.neuralnetworks.RequestArgument[] inputs;
+  android.hardware.neuralnetworks.RequestArgument[] outputs;
+  android.hardware.neuralnetworks.RequestMemoryPool[] pools;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/RequestArgument.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/RequestArgument.aidl
new file mode 100644
index 0000000..e3541c0
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/RequestArgument.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable RequestArgument {
+  boolean hasNoValue;
+  android.hardware.neuralnetworks.DataLocation location;
+  int[] dimensions;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/RequestMemoryPool.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/RequestMemoryPool.aidl
new file mode 100644
index 0000000..312f581
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/RequestMemoryPool.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+union RequestMemoryPool {
+  android.hardware.neuralnetworks.Memory pool;
+  int token;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Subgraph.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Subgraph.aidl
new file mode 100644
index 0000000..b7d4451
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Subgraph.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Subgraph {
+  android.hardware.neuralnetworks.Operand[] operands;
+  android.hardware.neuralnetworks.Operation[] operations;
+  int[] inputIndexes;
+  int[] outputIndexes;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
new file mode 100644
index 0000000..02d68f9
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable SymmPerChannelQuantParams {
+  float[] scales;
+  int channelDim;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Timing.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Timing.aidl
new file mode 100644
index 0000000..bcc83cf
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/3/android/hardware/neuralnetworks/Timing.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable Timing {
+  long timeOnDeviceNs;
+  long timeInDriverNs;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionConfig.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionConfig.aidl
new file mode 100644
index 0000000..cb85743
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.neuralnetworks;
+@VintfStability
+parcelable ExecutionConfig {
+  boolean measureTiming;
+  long loopTimeoutDurationNs;
+  android.hardware.neuralnetworks.TokenValuePair[] executionHints;
+  android.hardware.neuralnetworks.ExtensionNameAndPrefix[] extensionNameToPrefix;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
index eb3d0b0..461fdfa 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
@@ -36,4 +36,5 @@
 interface IBurst {
   android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
   void releaseMemoryResource(in long memoryIdentifierToken);
+  android.hardware.neuralnetworks.ExecutionResult executeSynchronouslyWithConfig(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in android.hardware.neuralnetworks.ExecutionConfig config, in long deadlineNs);
 }
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
index c9c67f2..c0fba47 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
@@ -43,6 +43,7 @@
   String getVersionString();
   void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
   void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+  void prepareModelWithConfig(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.PrepareModelConfig config, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
   const int BYTE_SIZE_OF_CACHE_TOKEN = 32;
   const int MAX_NUMBER_OF_CACHE_FILES = 32;
   const int EXTENSION_TYPE_HIGH_BITS_PREFIX = 15;
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IExecution.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IExecution.aidl
new file mode 100644
index 0000000..ab5275e
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IExecution.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.neuralnetworks;
+@VintfStability
+interface IExecution {
+  android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in long deadlineNs);
+  android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in ParcelFileDescriptor[] waitFor, in long deadlineNs, in long durationNs);
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
index fccb5dc..fb0c372 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -37,6 +37,9 @@
   android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
   android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs, in long durationNs);
   android.hardware.neuralnetworks.IBurst configureExecutionBurst();
+  android.hardware.neuralnetworks.IExecution createReusableExecution(in android.hardware.neuralnetworks.Request request, in android.hardware.neuralnetworks.ExecutionConfig config);
+  android.hardware.neuralnetworks.ExecutionResult executeSynchronouslyWithConfig(in android.hardware.neuralnetworks.Request request, in android.hardware.neuralnetworks.ExecutionConfig config, in long deadlineNs);
+  android.hardware.neuralnetworks.FencedExecutionResult executeFencedWithConfig(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in android.hardware.neuralnetworks.ExecutionConfig config, in long deadlineNs, in long durationNs);
   const long DEFAULT_LOOP_TIMEOUT_DURATION_NS = 2000000000;
   const long MAXIMUM_LOOP_TIMEOUT_DURATION_NS = 15000000000;
 }
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PrepareModelConfig.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PrepareModelConfig.aidl
new file mode 100644
index 0000000..85c924f
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PrepareModelConfig.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.neuralnetworks;
+@VintfStability
+parcelable PrepareModelConfig {
+  android.hardware.neuralnetworks.ExecutionPreference preference;
+  android.hardware.neuralnetworks.Priority priority;
+  long deadlineNs;
+  ParcelFileDescriptor[] modelCache;
+  ParcelFileDescriptor[] dataCache;
+  byte[] cacheToken;
+  android.hardware.neuralnetworks.TokenValuePair[] compilationHints;
+  android.hardware.neuralnetworks.ExtensionNameAndPrefix[] extensionNameToPrefix;
+}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/TokenValuePair.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/TokenValuePair.aidl
new file mode 100644
index 0000000..e477d6e
--- /dev/null
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/TokenValuePair.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.neuralnetworks;
+@VintfStability
+parcelable TokenValuePair {
+  int token;
+  byte[] value;
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionConfig.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionConfig.aidl
new file mode 100644
index 0000000..00f1e11
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionConfig.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks;
+
+import android.hardware.neuralnetworks.ExtensionNameAndPrefix;
+import android.hardware.neuralnetworks.TokenValuePair;
+
+/**
+ * A type that is used to represent all configuration related to
+ * an Execution.
+ */
+@VintfStability
+parcelable ExecutionConfig {
+    /**
+     * Specifies whether or not to measure duration of the execution.
+     * For {@link IPreparedModel::executeSynchronouslyWithConfig}, the duration runs from the time
+     * the driver sees the corresponding call to the execute function to the time the driver returns
+     * from the function. For {@link IPreparedModel::executeFencedWithConfig}, please refer to
+     * {@link IPreparedModelCallback} for details.
+     */
+    boolean measureTiming;
+    /**
+     * The maximum amount of time in nanoseconds that should be spent
+     * executing a {@link OperationType::WHILE} operation. If a loop
+     * condition model does not output false within this duration,
+     * the execution must be aborted. If -1 is provided, the maximum
+     * amount of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}.
+     * Other negative values are invalid. When provided, the duration
+     * must not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+     */
+    long loopTimeoutDurationNs;
+    /**
+     * A vector of token / value pairs represent vendor specific
+     * execution hints or metadata. The provided TokenValuePairs must not
+     * contain the same token twice. The driver must validate the
+     * data and ignore invalid hints. It is up to the driver to
+     * decide whether to respect the provided hints or not.
+     */
+    TokenValuePair[] executionHints;
+    /**
+     * The mapping between extension names and prefixes of token values.
+     * The driver must ignore the corresponding execution hint, if
+     * the extension is not supported.
+     */
+    ExtensionNameAndPrefix[] extensionNameToPrefix;
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
index 20109bd..9f70a53 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
@@ -20,6 +20,10 @@
 
 /**
  * Information about an extension.
+ *
+ * The extension can provide zero or more operation types (which are not enumerated), zero or more
+ * operand types (which are enumerated in {@link Extension::operandTypes}, and compilation and
+ * execution hints (which are not enumerated).
  */
 @VintfStability
 parcelable Extension {
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
index 29be93f..6c296e0 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
@@ -17,7 +17,8 @@
 package android.hardware.neuralnetworks;
 
 /**
- * The mapping between extension names and prefixes of operand and operation type values.
+ * The mapping between extension names and prefixes of values like operand and operation type, and
+ * token in {@link TokenValuePair}.
  *
  * An operand or operation whose numeric type value is above {@link IDevice::OPERAND_TYPE_BASE_MAX}
  * or {@link IDevice::OPERATION_TYPE_BASE_MAX} respectively should be interpreted as an extension
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
index decdc48..a05a7fb 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
@@ -17,6 +17,7 @@
 package android.hardware.neuralnetworks;
 
 import android.hardware.neuralnetworks.ErrorStatus;
+import android.hardware.neuralnetworks.ExecutionConfig;
 import android.hardware.neuralnetworks.ExecutionResult;
 import android.hardware.neuralnetworks.Request;
 
@@ -68,6 +69,8 @@
      *
      * Only a single execution on a given burst object may be active at any time.
      *
+     * Also see {@link IBurst::executeSynchronouslyWithConfig}.
+     *
      * @param request The input and output information on which the prepared model is to be
      *                executed.
      * @param memoryIdentifierTokens A list of tokens where each token is a non-negative number
@@ -78,10 +81,10 @@
      *                runs from the time the driver sees the call to the executeSynchronously
      *                function to the time the driver returns from the function.
      * @param deadlineNs The time by which the execution is expected to complete. The time is
-     *                   measured in nanoseconds since epoch of the steady clock (as from
-     *                   std::chrono::steady_clock). If the execution cannot be finished by the
-     *                   deadline, the execution may be aborted. Passing -1 means the deadline is
-     *                   omitted. Other negative values are invalid.
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the execution cannot be finished
+     *                   by the deadline, the execution may be aborted. Passing -1 means the
+     *                   deadline is omitted. Other negative values are invalid.
      * @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
      *                              executing a {@link OperationType::WHILE} operation. If a loop
      *                              condition model does not output false within this duration, the
@@ -117,4 +120,13 @@
      *     - INVALID_ARGUMENT if one of the input arguments is invalid
      */
     void releaseMemoryResource(in long memoryIdentifierToken);
+
+    /**
+     * For detailed specification, please refer to {@link IBurst::executeSynchronously}. The
+     * difference between the two methods is that executeSynchronouslyWithConfig takes {@link
+     * ExecutionConfig} instead of a list of configuration parameters, and ExecutionConfig contains
+     * more configuration parameters than are passed to executeSynchronously.
+     */
+    ExecutionResult executeSynchronouslyWithConfig(in Request request,
+            in long[] memoryIdentifierTokens, in ExecutionConfig config, in long deadlineNs);
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
index 72e2623..821b9fe 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
@@ -28,6 +28,7 @@
 import android.hardware.neuralnetworks.IPreparedModelParcel;
 import android.hardware.neuralnetworks.Model;
 import android.hardware.neuralnetworks.NumberOfCacheFiles;
+import android.hardware.neuralnetworks.PrepareModelConfig;
 import android.hardware.neuralnetworks.Priority;
 
 /**
@@ -148,7 +149,7 @@
      *
      * If the device reports that caching is not supported, the user may avoid calling
      * IDevice::prepareModelFromCache or providing cache file descriptors to
-     * IDevice::prepareModel.
+     * IDevice::prepareModel or IDevice::prepareModelWithConfig.
      *
      * @return NumberOfCacheFiles structure indicating how many files for model and data cache the
      *     driver needs to cache a single prepared model. It must be less than or equal to
@@ -302,6 +303,8 @@
      *
      * Multiple threads may call prepareModel on the same model concurrently.
      *
+     * Also see {@link IDevice::prepareModelWithConfig}.
+     *
      * @param model The model to be prepared for execution.
      * @param preference Indicates the intended execution behavior of a prepared model.
      * @param priority The priority of the prepared model relative to other prepared models owned by
@@ -403,17 +406,17 @@
      * @param modelCache A vector of file descriptors for the security-sensitive cache. The length
      *                   of the vector must match the numModelCache returned from
      *                   getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
-     *                   the same order as with prepareModel.
+     *                   the same order as with prepareModel or prepareModelWithConfig.
      * @param dataCache A vector of file descriptors for the constants' cache. The length of the
      *                  vector must match the numDataCache returned from
      *                  getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
-     *                  the same order as with prepareModel.
+     *                  the same order as with prepareModel or prepareModelWithConfig.
      * @param token A caching token of length BYTE_SIZE_OF_CACHE_TOKEN identifying the prepared
      *              model. It is the same token provided when saving the cache files with
-     *              prepareModel. Tokens should be chosen to have a low rate of collision for a
-     *              particular application. The driver cannot detect a collision; a collision will
-     *              result in a failed execution or in a successful execution that produces
-     *              incorrect output values.
+     *              prepareModel or prepareModelWithConfig. Tokens should be chosen to have a low
+     *              rate of collision for a particular application. The driver cannot detect a
+     *              collision; a collision will result in a failed execution or in a successful
+     *              execution that produces incorrect output values.
      * @param callback A callback object used to return the error status of preparing the model for
      *                 execution and the prepared model if successful, nullptr otherwise. The
      *                 callback object's notify function must be called exactly once, even if the
@@ -429,4 +432,28 @@
     void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache,
             in ParcelFileDescriptor[] dataCache, in byte[] token,
             in IPreparedModelCallback callback);
+
+    /**
+     * For detailed specification, please refer to {@link IDevice::prepareModel}. The only
+     * difference between the two methods is that prepareModelWithConfig takes {@link
+     * PrepareModelConfig} instead of standalone configuration parameters, which allows vendor
+     * specific compilation metadata to be passed.
+     *
+     * @param model The model to be prepared for execution.
+     * @param config Configuration parameters to prepare the model.
+     * @param callback A callback object used to return the error status of preparing the model for
+     *                 execution and the prepared model if successful, nullptr otherwise. The
+     *                 callback object's notify function must be called exactly once, even if the
+     *                 model could not be prepared.
+     * @throws ServiceSpecificException with one of the following ErrorStatus values:
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments related to preparing the model is
+     *       invalid
+     *     - MISSED_DEADLINE_* if the preparation is aborted because the model cannot be prepared by
+     *       the deadline
+     *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+     */
+    void prepareModelWithConfig(
+            in Model model, in PrepareModelConfig config, in IPreparedModelCallback callback);
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IExecution.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IExecution.aidl
new file mode 100644
index 0000000..3cb9c1a
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IExecution.aidl
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks;
+
+import android.hardware.neuralnetworks.ExecutionResult;
+import android.hardware.neuralnetworks.FencedExecutionResult;
+
+/**
+ * IExecution represents a reusable execution object with request and most other execution
+ * properties fixed. It is used to launch executions.
+ *
+ * At most one execution may occur on a reusable execution object at any given time, either by
+ * means of executeSynchronously or executeFenced.
+ *
+ * An IExecution object is used to control a set of executions on the same prepared model with
+ * the same request and properties. IExecution objects enable some optimizations:
+ * (1) An IExecution object can preserve resources between executions. For example, a driver can
+ *     map a memory object when the IExecution object is created and cache the mapping for reuse in
+ *     subsequent executions. Any cached resource can be released when the IExecution object is
+ *     destroyed.
+ * (2) Because an IExecution object may be used for at most one execution at a time, any transient
+ *     execution resources such as intermediate tensors can be allocated once when the IExecution
+ *     object is created and freed when the IExecution object is destroyed.
+ * (3) An IExecution object is created for a fixed request. This enables the implementation to apply
+ *     request-specific optimizations. For example, an implementation can avoid request validation
+ *     and conversions when the IExecution object is reused. An implementation may also choose to
+ *     specialize the dynamic tensor shapes in the IExecution object according to the request.
+ */
+@VintfStability
+interface IExecution {
+    /**
+     * Performs a synchronous execution on the reusable execution object.
+     *
+     * The execution is performed synchronously with respect to the caller. executeSynchronously
+     * must verify the inputs to the function are correct, and the usages of memory pools allocated
+     * by IDevice::allocate are valid. If there is an error, executeSynchronously must immediately
+     * return a service specific exception with the appropriate ErrorStatus value. If the inputs to
+     * the function are valid and there is no error, executeSynchronously must perform the
+     * execution, and must not return until the execution is complete.
+     *
+     * The caller must not change the content of any data object referenced by the 'request'
+     * provided in {@link IPreparedModel::createReusableExecution} (described by the
+     * {@link DataLocation} of a {@link RequestArgument}) until executeSynchronously returns.
+     * executeSynchronously must not change the content of any of the data objects corresponding to
+     * 'request' inputs.
+     *
+     * If the execution object was configured from a prepared model wherein all tensor operands have
+     * fully specified dimensions, and the inputs to the function are valid, and at execution time
+     * every operation's input operands have legal values, then the execution should complete
+     * successfully: there must be no failure unless the device itself is in a bad state.
+     *
+     * If the execution object was created with measureTiming being true and the execution is
+     * successful, the driver may report the timing information in the returning
+     * {@link ExecutionResult}. The duration runs from the time the driver sees the call to the time
+     * the driver returns from the function.
+     *
+     * executeSynchronously may be called with an optional deadline. If the execution is not able to
+     * be completed before the provided deadline, the execution may be aborted, and either
+     * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort must be
+     * sent the same way as other errors, described above.
+     *
+     * @param deadlineNs The time by which the execution is expected to complete. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the execution cannot be finished
+     *                   by the deadline, the execution may be aborted. Passing -1 means the
+     *                   deadline is omitted. Other negative values are invalid.
+     * @return ExecutionResult parcelable, containing the status of the execution, output shapes
+     *     and timing information.
+     * @throws ServiceSpecificException with one of the following ErrorStatus values:
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments is invalid
+     *     - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+     *       deadline
+     *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+     */
+    ExecutionResult executeSynchronously(in long deadlineNs);
+
+    /**
+     * Launch a fenced asynchronous execution on the reusable execution object.
+     *
+     * The execution is performed asynchronously with respect to the caller. executeFenced must
+     * verify the inputs to the function are correct, and the usages of memory pools allocated by
+     * IDevice::allocate are valid. If there is an error, executeFenced must immediately return a
+     * service specific exception with the corresponding ErrorStatus. If the inputs to the function
+     * are valid and there is no error, executeFenced must dispatch an asynchronous task to perform
+     * the execution in the background, and immediately return a {@link FencedExecutionResult}
+     * containing two fields: a callback (which can be used by the client to query the duration and
+     * runtime error status) and a sync fence (which will be signaled once the execution is
+     * completed). If the task has finished before the call returns, syncFence file descriptor may
+     * be set to -1. The execution must wait for all the sync fences (if any) in waitFor to be
+     * signaled before starting the actual execution.
+     *
+     * When the asynchronous task has finished its execution, it must immediately signal the
+     * syncFence returned from the executeFenced call. After the syncFence is signaled, the task
+     * must not modify the content of any data object referenced by the 'request' provided in
+     * IPreparedModel::createReusableExecution (described by the {@link DataLocation} of a
+     * {@link RequestArgument}).
+     *
+     * executeFenced may be called with an optional deadline and an optional duration. If the
+     * execution is not able to be completed before the provided deadline or within the timeout
+     * duration (measured from when all sync fences in waitFor are signaled), whichever comes
+     * earlier, the execution may be aborted, and either
+     * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort must be
+     * sent the same way as other errors, described above.
+     *
+     * If any of the sync fences in waitFor changes to error status after the executeFenced call
+     * succeeds, or the execution is aborted because it cannot finish before the deadline has been
+     * reached or the duration has elapsed, the driver must immediately set the returned syncFence
+     * to error status.
+     *
+     * @param waitFor A vector of sync fence file descriptors. Execution must not start until all
+     *                sync fences have been signaled.
+     * @param deadlineNs The time by which the execution is expected to complete. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the execution cannot be finished
+     *                   by the deadline, the execution may be aborted. Passing -1 means the
+     *                   deadline is omitted. Other negative values are invalid.
+     * @param durationNs The length of time in nanoseconds within which the execution is expected
+     *                   to complete after all sync fences in waitFor are signaled. If the
+     *                   execution cannot be finished within the duration, the execution may be
+     *                   aborted. Passing -1 means the duration is omitted. Other negative values
+     *                   are invalid.
+     * @return The FencedExecutionResult parcelable, containing IFencedExecutionCallback and the
+     *         sync fence.
+     * @throws ServiceSpecificException with one of the following ErrorStatus values:
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments is invalid, including fences in error
+     *       states.
+     *     - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+     *       deadline
+     *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+     */
+    FencedExecutionResult executeFenced(
+            in ParcelFileDescriptor[] waitFor, in long deadlineNs, in long durationNs);
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
index 956b626..949804e 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -18,9 +18,11 @@
 
 import android.hardware.common.NativeHandle;
 import android.hardware.neuralnetworks.ErrorStatus;
+import android.hardware.neuralnetworks.ExecutionConfig;
 import android.hardware.neuralnetworks.ExecutionResult;
 import android.hardware.neuralnetworks.FencedExecutionResult;
 import android.hardware.neuralnetworks.IBurst;
+import android.hardware.neuralnetworks.IExecution;
 import android.hardware.neuralnetworks.Request;
 
 /**
@@ -67,6 +69,8 @@
      * Any number of calls to the execute* functions, in any combination, may be made concurrently,
      * even on the same IPreparedModel object.
      *
+     * Also see {@link IPreparedModel::executeSynchronouslyWithConfig}.
+     *
      * @param request The input and output information on which the prepared model is to be
      *                executed.
      * @param measure Specifies whether or not to measure duration of the execution. The duration
@@ -105,11 +109,12 @@
      * IDevice::allocate are valid. If there is an error, executeFenced must immediately return a
      * service specific exception with the corresponding ErrorStatus. If the inputs to the function
      * are valid and there is no error, executeFenced must dispatch an asynchronous task to perform
-     * the execution in the background, assign a sync fence that will be signaled once the execution
-     * is completed and immediately return a callback that can be used by the client to query the
-     * duration and runtime error status. If the task has finished before the call returns,
-     * syncFence file descriptor may be set to -1. The execution must wait for all the sync fences
-     * (if any) in waitFor to be signaled before starting the actual execution.
+     * the execution in the background, and immediately return a {@link FencedExecutionResult}
+     * containing two fields: a callback (which can be used by the client to query the duration and
+     * runtime error status) and a sync fence (which will be signaled once the execution is
+     * completed). If the task has finished before the call returns, syncFence file descriptor may
+     * be set to -1. The execution must wait for all the sync fences (if any) in waitFor to be
+     * signaled before starting the actual execution.
      *
      * When the asynchronous task has finished its execution, it must immediately signal the
      * syncFence returned from the executeFenced call. After the syncFence is signaled, the task
@@ -132,6 +137,8 @@
      * Any number of calls to the execute* functions, in any combination, may be made concurrently,
      * even on the same IPreparedModel object.
      *
+     * Also see {@link IPreparedModel::executeFencedWithConfig}.
+     *
      * @param request The input and output information on which the prepared model is to be
      *                executed. The outputs in the request must have fully specified dimensions.
      * @param waitFor A vector of sync fence file descriptors. Execution must not start until all
@@ -186,4 +193,86 @@
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     IBurst configureExecutionBurst();
+
+    /**
+     * Create a reusable execution object to launch multiple executions with the same request and
+     * properties.
+     *
+     * createReusableExecution must verify the inputs to the function are correct, and the usages of
+     * memory pools allocated by IDevice::allocate are valid. If there is an error,
+     * createReusableExecution must immediately return a service specific exception with the
+     * appropriate ErrorStatus value. If the inputs to the function are valid and there is no error,
+     * createReusableExecution must construct a reusable execution.
+     *
+     * @param request The input and output information on which the prepared model is to be
+     *                executed.
+     * @param config Specifies the execution configuration parameters.
+     * @return execution An IExecution object representing a reusable execution that has been
+     *                   specialized for a fixed request.
+     * @throws ServiceSpecificException with one of the following ErrorStatus values:
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments is invalid
+     *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+     */
+    IExecution createReusableExecution(in Request request, in ExecutionConfig config);
+
+    /**
+     * For detailed specification, please refer to {@link IPreparedModel::executeSynchronously}. The
+     * difference between the two methods is that executeSynchronouslyWithConfig takes {@link
+     * ExecutionConfig} instead of a list of configuration parameters, and ExecutionConfig contains
+     * more configuration parameters than are passed to executeSynchronously.
+     *
+     * @param request The input and output information on which the prepared model is to be
+     *                executed.
+     * @param config Specifies the execution configuration parameters.
+     * @param deadlineNs The time by which the execution is expected to complete. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the execution cannot be finished
+     *                   by the deadline, the execution may be aborted. Passing -1 means the
+     *                   deadline is omitted. Other negative valueggs are invalid.
+     * @return ExecutionResult parcelable, containing the status of the execution, output shapes and
+     *     timing information.
+     *     - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+     *       deadline
+     *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+     */
+    ExecutionResult executeSynchronouslyWithConfig(
+            in Request request, in ExecutionConfig config, in long deadlineNs);
+
+    /**
+     * For detailed specification, please refer to {@link IPreparedModel::executeFenced}. The
+     * difference between the two methods is that executeFencedWithConfig takes {@link
+     * ExecutionConfig} instead of a list of configuration parameters, and ExecutionConfig contains
+     * more configuration parameters than are passed to executeFenced.
+     *
+     * @param request The input and output information on which the prepared model is to be
+     *                executed. The outputs in the request must have fully specified dimensions.
+     * @param waitFor A vector of sync fence file descriptors. Execution must not start until all
+     *                sync fences have been signaled.
+     * @param config Specifies the execution configuration parameters.
+     * @param deadlineNs The time by which the execution is expected to complete. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the execution cannot be finished
+     *                   by the deadline, the execution may be aborted. Passing -1 means the
+     *                   deadline is omitted. Other negative values are invalid.
+     * @param durationNs The length of time in nanoseconds within which the execution is expected to
+     *                   complete after all sync fences in waitFor are signaled. If the execution
+     *                   cannot be finished within the duration, the execution may be aborted.
+     *                   Passing -1 means the duration is omitted. Other negative values are
+     *                   invalid.
+     * @return The FencedExecutionResult parcelable, containing IFencedExecutionCallback and the
+     *         sync fence.
+     * @throws ServiceSpecificException with one of the following ErrorStatus values:
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments is invalid, including fences in error
+     *       states.
+     *     - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+     *       deadline
+     *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+     */
+    FencedExecutionResult executeFencedWithConfig(in Request request,
+            in ParcelFileDescriptor[] waitFor, in ExecutionConfig config, in long deadlineNs,
+            in long durationNs);
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
index aebe8d9..5f7810b 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
@@ -5331,6 +5331,18 @@
     /**
      * Pads a tensor with mirrored values.
      *
+     * This operator specifies one of two padding modes: REFLECT or SYMMETRIC.
+     * In the case of REFLECT mode, the mirroring excludes the border element
+     * on the padding side.
+     * In the case of SYMMETRIC mode, the mirroring includes the border element
+     * on the padding side.
+     *
+     * For example, if the input is the 1-D tensor `[1, 2, 3]` and the padding
+     * is `[0, 2]` (i.e., pad no elements before the first (and only) dimension,
+     * and two elements after the first (and only) dimension), then:
+     *     - REFLECT mode produces the output `[1, 2, 3, 2, 1]`
+     *     - SYMMETRIC mode produces the output `[1, 2, 3, 3, 2]`
+     *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16}
      * * {@link OperandType::TENSOR_FLOAT32}
@@ -5349,6 +5361,11 @@
      *      front of dimension i.
      *      padding[i, 1] specifies the number of elements to be padded after the
      *      end of dimension i.
+     *      Each padding value must be nonnegative.
+     *      In the case of REFLECT mode, each padding value must be less than the
+     *      corresponding dimension.
+     *      In the case of SYMMETRIC mode, each padding value must be less than or
+     *      equal to the corresponding dimension.
      * * 2: An {@link OperandType::INT32} scalar, specifying the mode.
      *      Options are 0:REFLECT and 1:SYMMETRIC.
      *
@@ -5385,7 +5402,7 @@
      *      must be in the range [0, n).
      *
      * Outputs:
-     * * 0: The reversed tensor.
+     * * 0: The reversed tensor of the same shape as the input tensor.
      *      For {@link OperandType::TENSOR_QUANT8_ASYMM} and
      *      {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensors,
      *      the scales and zeroPoint must be the same as input0.
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/PrepareModelConfig.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/PrepareModelConfig.aidl
new file mode 100644
index 0000000..96df968
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/PrepareModelConfig.aidl
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks;
+
+import android.hardware.neuralnetworks.ExecutionPreference;
+import android.hardware.neuralnetworks.ExtensionNameAndPrefix;
+import android.hardware.neuralnetworks.Priority;
+import android.hardware.neuralnetworks.TokenValuePair;
+
+/**
+ * A type that is used to represent all configuration needed to
+ * prepare a model.
+ */
+@VintfStability
+parcelable PrepareModelConfig {
+    /**
+     * Indicates the intended execution behavior of a prepared model.
+     */
+    ExecutionPreference preference;
+    /**
+     * The priority of the prepared model relative to other prepared
+     * models owned by the client.
+     */
+    Priority priority;
+    /**
+     * The time by which the model is expected to be prepared. The
+     * time is measured in nanoseconds since boot (as from
+     * clock_gettime(CLOCK_BOOTTIME, &ts) or
+     * ::android::base::boot_clock). If the model cannot be prepared
+     * by the deadline, the preparation may be aborted. Passing -1
+     * means the deadline is omitted. Other negative values are
+     * invalid.
+     */
+    long deadlineNs;
+    /**
+     * A vector of file descriptors for the security-sensitive cache.
+     * The length of the vector must either be 0 indicating that
+     * caching information is not provided, or match the
+     * numModelCache returned from IDevice::getNumberOfCacheFilesNeeded. The
+     * cache file descriptors will be provided in the same order when
+     * retrieving the preparedModel from cache files with
+     * IDevice::prepareModelFromCache.
+     */
+    ParcelFileDescriptor[] modelCache;
+    /**
+     * A vector of file descriptors for the constants' cache. The
+     * length of the vector must either be 0 indicating that caching
+     * information is not provided, or match the numDataCache
+     * returned from IDevice::getNumberOfCacheFilesNeeded. The cache file
+     * descriptors will be provided in the same order when retrieving
+     * the preparedModel from cache files with IDevice::prepareModelFromCache.
+     */
+    ParcelFileDescriptor[] dataCache;
+    /**
+     * A caching token of length IDevice::BYTE_SIZE_OF_CACHE_TOKEN identifying
+     * the prepared model. The same token will be provided when
+     * retrieving the prepared model from the cache files with
+     * IDevice::prepareModelFromCache.  Tokens should be chosen to have a low
+     * rate of collision for a particular application. The driver
+     * cannot detect a collision; a collision will result in a failed
+     * execution or in a successful execution that produces incorrect
+     * output values. If both modelCache and dataCache are empty
+     * indicating that caching information is not provided, this
+     * token must be ignored.
+     */
+    byte[] cacheToken;
+    /**
+     * A vector of token / value pairs represent vendor specific
+     * compilation hints or metadata. The provided TokenValuePairs must not
+     * contain the same token twice. The driver must validate the
+     * data and ignore invalid hints. It is up to the driver to
+     * decide whether to respect the provided hints or not.
+     */
+    TokenValuePair[] compilationHints;
+    /**
+     * The mapping between extension names and prefixes of token values.
+     * The driver must ignore the corresponding compilation hint, if
+     * the extension is not supported.
+     */
+    ExtensionNameAndPrefix[] extensionNameToPrefix;
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/TokenValuePair.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/TokenValuePair.aidl
new file mode 100644
index 0000000..ec665b4
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/TokenValuePair.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks;
+
+/**
+ * A type that is used to represent a token / byte array data pair.
+ */
+@VintfStability
+parcelable TokenValuePair {
+    /**
+     * A 32bit integer token. The token is created by combining the
+     * extension prefix and enum defined within the extension.
+     * The low {@link IDevice::EXTENSION_TYPE_LOW_BITS_TYPE} bits of the value
+     * correspond to the hint within the extension and the high
+     * {@link IDevice::EXTENSION_TYPE_HIGH_BITS_PREFIX} bits encode the "prefix", which maps
+     * uniquely to the extension name. The sign bit is always 0.
+     *
+     * For example, if a token value is 0x7AAA000B and the corresponding
+     * {@link ExtensionNameAndPrefix} contains an entry with prefix=0x7AAA and
+     * name="vendor.test.test_extension", then the token should be interpreted as the hint
+     * 0x000B of the extension named vendor.test.test_extension.
+     */
+    int token;
+    /**
+     * A byte array containing the raw data.
+     */
+    byte[] value;
+}
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index e356104..9148eac 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -26,7 +26,14 @@
 cc_defaults {
     name: "neuralnetworks_utils_hal_aidl_defaults",
     defaults: ["neuralnetworks_utils_defaults"],
-    srcs: ["src/*"],
+    srcs: [
+        // AIDL utils that a driver may depend on.
+        "src/BufferTracker.cpp",
+        "src/Conversions.cpp",
+        "src/HalUtils.cpp",
+        "src/Utils.cpp",
+        "src/ValidateHal.cpp",
+    ],
     local_include_dirs: ["include/nnapi/hal/aidl/"],
     export_include_dirs: ["include"],
     cflags: ["-Wthread-safety"],
@@ -47,6 +54,7 @@
     },
 }
 
+// Deprecated. Remove once all modules depending on this are migrated away.
 cc_library_static {
     name: "neuralnetworks_utils_hal_aidl_v1",
     defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
@@ -56,19 +64,25 @@
 }
 
 cc_library_static {
-    name: "neuralnetworks_utils_hal_aidl_v2",
-    defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
-    shared_libs: [
-        "android.hardware.neuralnetworks-V2-ndk",
-    ],
-}
-
-cc_library_static {
     name: "neuralnetworks_utils_hal_aidl",
     defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
-    shared_libs: [
-        "android.hardware.neuralnetworks-V3-ndk",
+    srcs: [
+        // Additional AIDL utils for the runtime.
+        "src/Assertions.cpp",
+        "src/Buffer.cpp",
+        "src/Burst.cpp",
+        "src/Callbacks.cpp",
+        "src/Device.cpp",
+        "src/Execution.cpp",
+        "src/InvalidDevice.cpp",
+        "src/PreparedModel.cpp",
+        "src/ProtectCallback.cpp",
+        "src/Service.cpp",
     ],
+    shared_libs: [
+        "android.hardware.neuralnetworks-V4-ndk",
+    ],
+    cflags: ["-DNN_AIDL_V4_OR_ABOVE"],
 }
 
 // A cc_defaults that includes the latest non-experimental AIDL utilities and other AIDL libraries
@@ -79,9 +93,10 @@
     static_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.graphics.common-V3-ndk",
-        "android.hardware.neuralnetworks-V3-ndk",
+        "android.hardware.neuralnetworks-V4-ndk",
         "neuralnetworks_utils_hal_aidl",
     ],
+    cflags: ["-DNN_AIDL_V4_OR_ABOVE"],
 }
 
 cc_test {
@@ -96,19 +111,13 @@
     static_libs: [
         "libaidlcommonsupport",
         "libgmock",
-        "libneuralnetworks_common",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
     ],
     shared_libs: [
-        "android.hidl.allocator@1.0",
         "libbase",
         "libbinder_ndk",
         "libcutils",
-        "libhidlbase",
-        "libhidlmemory",
-        "liblog",
-        "libutils",
     ],
     target: {
         android: {
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
index 0cc78d4..f2e6e75 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
@@ -86,10 +86,12 @@
                 GUARDED_BY(mMutex);
     };
 
+    // featureLevel is for testing purposes.
     static nn::GeneralResult<std::shared_ptr<const Burst>> create(
-            std::shared_ptr<aidl_hal::IBurst> burst);
+            std::shared_ptr<aidl_hal::IBurst> burst, nn::Version featureLevel);
 
-    Burst(PrivateConstructorTag tag, std::shared_ptr<aidl_hal::IBurst> burst);
+    Burst(PrivateConstructorTag tag, std::shared_ptr<aidl_hal::IBurst> burst,
+          nn::Version featureLevel);
 
     // See IBurst::cacheMemory for information.
     OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
@@ -97,23 +99,29 @@
     // See IBurst::execute for information.
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     // See IBurst::createReusableExecution for information.
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeInternal(
             const aidl_hal::Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
             bool measure, int64_t deadline, int64_t loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
             const hal::utils::RequestRelocation& relocation) const;
 
   private:
     mutable std::atomic_flag mExecutionInFlight = ATOMIC_FLAG_INIT;
     const std::shared_ptr<aidl_hal::IBurst> kBurst;
     const std::shared_ptr<MemoryCache> kMemoryCache;
+    const nn::Version kFeatureLevel;
 };
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h
index 168264b..960be2b 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h
@@ -36,6 +36,8 @@
   public:
     using Data = nn::GeneralResult<nn::SharedPreparedModel>;
 
+    PreparedModelCallback(nn::Version featureLevel) : kFeatureLevel(featureLevel) {}
+
     ndk::ScopedAStatus notify(ErrorStatus status,
                               const std::shared_ptr<IPreparedModel>& preparedModel) override;
 
@@ -44,6 +46,7 @@
     Data get();
 
   private:
+    const nn::Version kFeatureLevel;
     hal::utils::TransferValue<Data> mData;
 };
 
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
index 78433a7..af58715 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
@@ -46,6 +46,10 @@
 #include <aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.h>
 #include <aidl/android/hardware/neuralnetworks/Timing.h>
 
+#ifdef NN_AIDL_V4_OR_ABOVE
+#include <aidl/android/hardware/neuralnetworks/TokenValuePair.h>
+#endif  // NN_AIDL_V4_OR_ABOVE
+
 #include <android/binder_auto_utils.h>
 #include <nnapi/Result.h>
 #include <nnapi/Types.h>
@@ -74,7 +78,7 @@
         const aidl_hal::SymmPerChannelQuantParams& symmPerChannelQuantParams);
 GeneralResult<Operation> unvalidatedConvert(const aidl_hal::Operation& operation);
 GeneralResult<Model> unvalidatedConvert(const aidl_hal::Model& model);
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
         const aidl_hal::ExtensionNameAndPrefix& extensionNameAndPrefix);
 GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues);
 GeneralResult<Model::Subgraph> unvalidatedConvert(const aidl_hal::Subgraph& subgraph);
@@ -97,6 +101,10 @@
         const aidl_hal::ExtensionOperandTypeInformation& operandTypeInformation);
 GeneralResult<SharedHandle> unvalidatedConvert(const ndk::ScopedFileDescriptor& handle);
 
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<TokenValuePair> unvalidatedConvert(const aidl_hal::TokenValuePair& tokenValuePair);
+#endif  // NN_AIDL_V4_OR_ABOVE
+
 GeneralResult<std::vector<Operation>> unvalidatedConvert(
         const std::vector<aidl_hal::Operation>& operations);
 
@@ -112,11 +120,23 @@
 GeneralResult<Request> convert(const aidl_hal::Request& request);
 GeneralResult<Timing> convert(const aidl_hal::Timing& timing);
 GeneralResult<SharedHandle> convert(const ndk::ScopedFileDescriptor& handle);
+GeneralResult<BufferDesc> convert(const aidl_hal::BufferDesc& bufferDesc);
 
 GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension);
 GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories);
+GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+        const std::vector<aidl_hal::ExtensionNameAndPrefix>& extensionNameAndPrefix);
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<std::vector<TokenValuePair>> convert(
+        const std::vector<aidl_hal::TokenValuePair>& metaData);
+#endif  // NN_AIDL_V4_OR_ABOVE
+
 GeneralResult<std::vector<OutputShape>> convert(
         const std::vector<aidl_hal::OutputShape>& outputShapes);
+GeneralResult<std::vector<SharedHandle>> convert(
+        const std::vector<ndk::ScopedFileDescriptor>& handles);
+GeneralResult<std::vector<BufferRole>> convert(const std::vector<aidl_hal::BufferRole>& roles);
 
 GeneralResult<std::vector<uint32_t>> toUnsigned(const std::vector<int32_t>& vec);
 
@@ -129,6 +149,7 @@
 nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(const nn::CacheToken& cacheToken);
 nn::GeneralResult<BufferDesc> unvalidatedConvert(const nn::BufferDesc& bufferDesc);
 nn::GeneralResult<BufferRole> unvalidatedConvert(const nn::BufferRole& bufferRole);
+nn::GeneralResult<DeviceType> unvalidatedConvert(const nn::DeviceType& deviceType);
 nn::GeneralResult<bool> unvalidatedConvert(const nn::MeasureTiming& measureTiming);
 nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory);
 nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape);
@@ -147,21 +168,27 @@
 nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(
         const nn::Model::OperandValues& operandValues);
 nn::GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
-        const nn::Model::ExtensionNameAndPrefix& extensionNameToPrefix);
+        const nn::ExtensionNameAndPrefix& extensionNameToPrefix);
 nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
 nn::GeneralResult<Priority> unvalidatedConvert(const nn::Priority& priority);
 nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request);
 nn::GeneralResult<RequestArgument> unvalidatedConvert(const nn::Request::Argument& requestArgument);
 nn::GeneralResult<RequestMemoryPool> unvalidatedConvert(const nn::Request::MemoryPool& memoryPool);
 nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing);
-nn::GeneralResult<int64_t> unvalidatedConvert(const nn::Duration& duration);
 nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration);
 nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalTimePoint& optionalTimePoint);
 nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SyncFence& syncFence);
 nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SharedHandle& handle);
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension);
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<TokenValuePair> unvalidatedConvert(const nn::TokenValuePair& tokenValuePair);
+#endif  // NN_AIDL_V4_OR_ABOVE
 
 nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken);
 nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc);
+nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType);
 nn::GeneralResult<bool> convert(const nn::MeasureTiming& measureTiming);
 nn::GeneralResult<Memory> convert(const nn::SharedMemory& memory);
 nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus);
@@ -172,6 +199,8 @@
 nn::GeneralResult<Timing> convert(const nn::Timing& timing);
 nn::GeneralResult<int64_t> convert(const nn::OptionalDuration& optionalDuration);
 nn::GeneralResult<int64_t> convert(const nn::OptionalTimePoint& optionalTimePoint);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Extension> convert(const nn::Extension& extension);
 
 nn::GeneralResult<std::vector<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles);
 nn::GeneralResult<std::vector<OutputShape>> convert(
@@ -180,6 +209,14 @@
         const std::vector<nn::SharedHandle>& handles);
 nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
         const std::vector<nn::SyncFence>& syncFences);
+nn::GeneralResult<std::vector<Extension>> convert(const std::vector<nn::Extension>& extensions);
+nn::GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix);
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<std::vector<TokenValuePair>> convert(
+        const std::vector<nn::TokenValuePair>& metaData);
+#endif  // NN_AIDL_V4_OR_ABOVE
 
 nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec);
 
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
index d558f66..615c6de 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
@@ -42,6 +42,7 @@
     struct PrivateConstructorTag {};
 
   public:
+    // featureLevel is for testing purposes.
     static nn::GeneralResult<std::shared_ptr<const Device>> create(
             std::string name, std::shared_ptr<aidl_hal::IDevice> device, nn::Version featureLevel);
 
@@ -67,8 +68,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache,
-            const nn::CacheToken& token) const override;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h
index a77ea98..14802b9 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_EXECUTION_H
 #define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_EXECUTION_H
 
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
+
 #include <nnapi/IExecution.h>
 #include <nnapi/Result.h>
 #include <nnapi/Types.h>
@@ -33,17 +35,22 @@
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
-class Execution final : public nn::IExecution, public std::enable_shared_from_this<Execution> {
+// A reusable execution implementation with a cached Request, internally it is still passing the
+// request to the driver in every computation.
+class ExecutionWithCachedRequest final
+    : public nn::IExecution,
+      public std::enable_shared_from_this<ExecutionWithCachedRequest> {
     struct PrivateConstructorTag {};
 
   public:
-    static nn::GeneralResult<std::shared_ptr<const Execution>> create(
+    static nn::GeneralResult<std::shared_ptr<const ExecutionWithCachedRequest>> create(
             std::shared_ptr<const PreparedModel> preparedModel, Request request,
             hal::utils::RequestRelocation relocation, bool measure, int64_t loopTimeoutDuration);
 
-    Execution(PrivateConstructorTag tag, std::shared_ptr<const PreparedModel> preparedModel,
-              Request request, hal::utils::RequestRelocation relocation, bool measure,
-              int64_t loopTimeoutDuration);
+    ExecutionWithCachedRequest(PrivateConstructorTag tag,
+                               std::shared_ptr<const PreparedModel> preparedModel, Request request,
+                               hal::utils::RequestRelocation relocation, bool measure,
+                               int64_t loopTimeoutDuration);
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> compute(
             const nn::OptionalTimePoint& deadline) const override;
@@ -60,6 +67,30 @@
     const int64_t kLoopTimeoutDuration;
 };
 
+// A reusable execution implementation that is backed by an actual AIDL IExecution object.
+class Execution final : public nn::IExecution, public std::enable_shared_from_this<Execution> {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const Execution>> create(
+            std::shared_ptr<aidl_hal::IExecution> execution,
+            hal::utils::RequestRelocation relocation);
+
+    Execution(PrivateConstructorTag tag, std::shared_ptr<aidl_hal::IExecution> execution,
+              hal::utils::RequestRelocation relocation);
+
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> compute(
+            const nn::OptionalTimePoint& deadline) const override;
+
+    nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> computeFenced(
+            const std::vector<nn::SyncFence>& waitFor, const nn::OptionalTimePoint& deadline,
+            const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+
+  private:
+    const std::shared_ptr<aidl_hal::IExecution> kExecution;
+    const hal::utils::RequestRelocation kRelocation;
+};
+
 }  // namespace aidl::android::hardware::neuralnetworks::utils
 
 #endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_EXECUTION_H
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h
index 3fb443c..cacdc26 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h
@@ -61,6 +61,13 @@
 #include <aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.h>
 #include <aidl/android/hardware/neuralnetworks/Timing.h>
 
+#ifdef NN_AIDL_V4_OR_ABOVE
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionConfig.h>
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
+#include <aidl/android/hardware/neuralnetworks/PrepareModelConfig.h>
+#endif  // NN_AIDL_V4_OR_ABOVE
+
 namespace android::nn {
 
 namespace aidl_hal = ::aidl::android::hardware::neuralnetworks;
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
index e66507a..9375c1d 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
@@ -53,6 +53,9 @@
             const std::vector<ndk::ScopedFileDescriptor>& dataCache,
             const std::vector<uint8_t>& token,
             const std::shared_ptr<IPreparedModelCallback>& callback) override;
+    ndk::ScopedAStatus prepareModelWithConfig(
+            const Model& model, const PrepareModelConfig& config,
+            const std::shared_ptr<IPreparedModelCallback>& callback) override;
     ndk::ScopedAStatus prepareModelFromCache(
             int64_t deadline, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
             const std::vector<ndk::ScopedFileDescriptor>& dataCache,
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
index 4035764..cb6a85b 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
@@ -40,26 +40,33 @@
     struct PrivateConstructorTag {};
 
   public:
+    // featureLevel is for testing purposes.
     static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
-            std::shared_ptr<aidl_hal::IPreparedModel> preparedModel);
+            std::shared_ptr<aidl_hal::IPreparedModel> preparedModel, nn::Version featureLevel);
 
     PreparedModel(PrivateConstructorTag tag,
-                  std::shared_ptr<aidl_hal::IPreparedModel> preparedModel);
+                  std::shared_ptr<aidl_hal::IPreparedModel> preparedModel,
+                  nn::Version featureLevel);
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
             const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
             const nn::OptionalDuration& loopTimeoutDuration,
-            const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+            const nn::OptionalDuration& timeoutDurationAfterFence,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
 
@@ -67,6 +74,8 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeInternal(
             const Request& request, bool measure, int64_t deadline, int64_t loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
             const hal::utils::RequestRelocation& relocation) const;
 
     nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
@@ -74,10 +83,13 @@
                           const std::vector<ndk::ScopedFileDescriptor>& waitFor, bool measure,
                           int64_t deadline, int64_t loopTimeoutDuration,
                           int64_t timeoutDurationAfterFence,
+                          const std::vector<nn::TokenValuePair>& hints,
+                          const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
                           const hal::utils::RequestRelocation& relocation) const;
 
   private:
     const std::shared_ptr<aidl_hal::IPreparedModel> kPreparedModel;
+    const nn::Version kFeatureLevel;
 };
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
index a27487e..beca38b 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
@@ -38,6 +38,8 @@
             return nn::kVersionFeatureLevel6;
         case 3:
             return nn::kVersionFeatureLevel7;
+        case 4:
+            return nn::kVersionFeatureLevel8;
         default:
             return std::nullopt;
     }
diff --git a/neuralnetworks/aidl/utils/src/Burst.cpp b/neuralnetworks/aidl/utils/src/Burst.cpp
index fb00b26..6c7aa88 100644
--- a/neuralnetworks/aidl/utils/src/Burst.cpp
+++ b/neuralnetworks/aidl/utils/src/Burst.cpp
@@ -43,12 +43,16 @@
     static nn::GeneralResult<std::shared_ptr<const BurstExecution>> create(
             std::shared_ptr<const Burst> burst, Request request,
             std::vector<int64_t> memoryIdentifierTokens, bool measure, int64_t loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
             hal::utils::RequestRelocation relocation,
             std::vector<Burst::OptionalCacheHold> cacheHolds);
 
     BurstExecution(PrivateConstructorTag tag, std::shared_ptr<const Burst> burst, Request request,
                    std::vector<int64_t> memoryIdentifierTokens, bool measure,
-                   int64_t loopTimeoutDuration, hal::utils::RequestRelocation relocation,
+                   int64_t loopTimeoutDuration, const std::vector<nn::TokenValuePair>& hints,
+                   const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
+                   hal::utils::RequestRelocation relocation,
                    std::vector<Burst::OptionalCacheHold> cacheHolds);
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> compute(
@@ -64,6 +68,8 @@
     const std::vector<int64_t> kMemoryIdentifierTokens;
     const bool kMeasure;
     const int64_t kLoopTimeoutDuration;
+    const std::vector<nn::TokenValuePair> kHints;
+    const std::vector<nn::ExtensionNameAndPrefix> kExtensionNameToPrefix;
     const hal::utils::RequestRelocation kRelocation;
     const std::vector<Burst::OptionalCacheHold> kCacheHolds;
 };
@@ -149,17 +155,20 @@
 }
 
 nn::GeneralResult<std::shared_ptr<const Burst>> Burst::create(
-        std::shared_ptr<aidl_hal::IBurst> burst) {
+        std::shared_ptr<aidl_hal::IBurst> burst, nn::Version featureLevel) {
     if (burst == nullptr) {
         return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
                << "aidl_hal::utils::Burst::create must have non-null burst";
     }
 
-    return std::make_shared<const Burst>(PrivateConstructorTag{}, std::move(burst));
+    return std::make_shared<const Burst>(PrivateConstructorTag{}, std::move(burst), featureLevel);
 }
 
-Burst::Burst(PrivateConstructorTag /*tag*/, std::shared_ptr<aidl_hal::IBurst> burst)
-    : kBurst(std::move(burst)), kMemoryCache(std::make_shared<MemoryCache>(kBurst)) {
+Burst::Burst(PrivateConstructorTag /*tag*/, std::shared_ptr<aidl_hal::IBurst> burst,
+             nn::Version featureLevel)
+    : kBurst(std::move(burst)),
+      kMemoryCache(std::make_shared<MemoryCache>(kBurst)),
+      kFeatureLevel(featureLevel) {
     CHECK(kBurst != nullptr);
 }
 
@@ -170,8 +179,9 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalTimePoint& deadline,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
@@ -200,14 +210,14 @@
         memoryIdentifierTokens.push_back(-1);
     }
     CHECK_EQ(requestInShared.pools.size(), memoryIdentifierTokens.size());
-
     return executeInternal(aidlRequest, memoryIdentifierTokens, aidlMeasure, aidlDeadline,
-                           aidlLoopTimeoutDuration, relocation);
+                           aidlLoopTimeoutDuration, hints, extensionNameToPrefix, relocation);
 }
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::executeInternal(
         const Request& request, const std::vector<int64_t>& memoryIdentifierTokens, bool measure,
-        int64_t deadline, int64_t loopTimeoutDuration,
+        int64_t deadline, int64_t loopTimeoutDuration, const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
         const hal::utils::RequestRelocation& relocation) const {
     // Ensure that at most one execution is in flight at any given time.
     const bool alreadyInFlight = mExecutionInFlight.test_and_set();
@@ -221,9 +231,21 @@
     }
 
     ExecutionResult executionResult;
-    const auto ret = kBurst->executeSynchronously(request, memoryIdentifierTokens, measure,
-                                                  deadline, loopTimeoutDuration, &executionResult);
-    HANDLE_ASTATUS(ret) << "execute failed";
+    if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+        auto aidlHints = NN_TRY(convert(hints));
+        auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+        const auto ret = kBurst->executeSynchronouslyWithConfig(
+                request, memoryIdentifierTokens,
+                {measure, loopTimeoutDuration, std::move(aidlHints),
+                 std::move(aidlExtensionPrefix)},
+                deadline, &executionResult);
+        HANDLE_ASTATUS(ret) << "execute failed";
+    } else {
+        const auto ret =
+                kBurst->executeSynchronously(request, memoryIdentifierTokens, measure, deadline,
+                                             loopTimeoutDuration, &executionResult);
+        HANDLE_ASTATUS(ret) << "execute failed";
+    }
     if (!executionResult.outputSufficientSize) {
         auto canonicalOutputShapes =
                 nn::convert(executionResult.outputShapes).value_or(std::vector<nn::OutputShape>{});
@@ -241,7 +263,9 @@
 
 nn::GeneralResult<nn::SharedExecution> Burst::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
@@ -272,12 +296,15 @@
 
     return BurstExecution::create(shared_from_this(), std::move(aidlRequest),
                                   std::move(memoryIdentifierTokens), aidlMeasure,
-                                  aidlLoopTimeoutDuration, std::move(relocation), std::move(holds));
+                                  aidlLoopTimeoutDuration, hints, extensionNameToPrefix,
+                                  std::move(relocation), std::move(holds));
 }
 
 nn::GeneralResult<std::shared_ptr<const BurstExecution>> BurstExecution::create(
         std::shared_ptr<const Burst> burst, Request request,
         std::vector<int64_t> memoryIdentifierTokens, bool measure, int64_t loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
         hal::utils::RequestRelocation relocation,
         std::vector<Burst::OptionalCacheHold> cacheHolds) {
     if (burst == nullptr) {
@@ -286,13 +313,15 @@
 
     return std::make_shared<const BurstExecution>(
             PrivateConstructorTag{}, std::move(burst), std::move(request),
-            std::move(memoryIdentifierTokens), measure, loopTimeoutDuration, std::move(relocation),
-            std::move(cacheHolds));
+            std::move(memoryIdentifierTokens), measure, loopTimeoutDuration, hints,
+            extensionNameToPrefix, std::move(relocation), std::move(cacheHolds));
 }
 
 BurstExecution::BurstExecution(PrivateConstructorTag /*tag*/, std::shared_ptr<const Burst> burst,
                                Request request, std::vector<int64_t> memoryIdentifierTokens,
                                bool measure, int64_t loopTimeoutDuration,
+                               const std::vector<nn::TokenValuePair>& hints,
+                               const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
                                hal::utils::RequestRelocation relocation,
                                std::vector<Burst::OptionalCacheHold> cacheHolds)
     : kBurst(std::move(burst)),
@@ -300,6 +329,8 @@
       kMemoryIdentifierTokens(std::move(memoryIdentifierTokens)),
       kMeasure(measure),
       kLoopTimeoutDuration(loopTimeoutDuration),
+      kHints(hints),
+      kExtensionNameToPrefix(extensionNameToPrefix),
       kRelocation(std::move(relocation)),
       kCacheHolds(std::move(cacheHolds)) {}
 
@@ -307,7 +338,8 @@
         const nn::OptionalTimePoint& deadline) const {
     const auto aidlDeadline = NN_TRY(convert(deadline));
     return kBurst->executeInternal(kRequest, kMemoryIdentifierTokens, kMeasure, aidlDeadline,
-                                   kLoopTimeoutDuration, kRelocation);
+                                   kLoopTimeoutDuration, kHints, kExtensionNameToPrefix,
+                                   kRelocation);
 }
 
 nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
diff --git a/neuralnetworks/aidl/utils/src/Callbacks.cpp b/neuralnetworks/aidl/utils/src/Callbacks.cpp
index 8084970..554f3fa 100644
--- a/neuralnetworks/aidl/utils/src/Callbacks.cpp
+++ b/neuralnetworks/aidl/utils/src/Callbacks.cpp
@@ -38,16 +38,17 @@
 // nn::kVersionFeatureLevel5. On failure, this function returns with the appropriate
 // nn::GeneralError.
 nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
-        ErrorStatus status, const std::shared_ptr<IPreparedModel>& preparedModel) {
+        ErrorStatus status, const std::shared_ptr<IPreparedModel>& preparedModel,
+        nn::Version featureLevel) {
     HANDLE_STATUS_AIDL(status) << "model preparation failed with " << toString(status);
-    return NN_TRY(PreparedModel::create(preparedModel));
+    return NN_TRY(PreparedModel::create(preparedModel, featureLevel));
 }
 
 }  // namespace
 
 ndk::ScopedAStatus PreparedModelCallback::notify(
         ErrorStatus status, const std::shared_ptr<IPreparedModel>& preparedModel) {
-    mData.put(prepareModelCallback(status, preparedModel));
+    mData.put(prepareModelCallback(status, preparedModel, kFeatureLevel));
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index 45628c8..eb28db7 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -302,9 +302,9 @@
     };
 }
 
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
         const aidl_hal::ExtensionNameAndPrefix& extensionNameAndPrefix) {
-    return Model::ExtensionNameAndPrefix{
+    return ExtensionNameAndPrefix{
             .name = extensionNameAndPrefix.name,
             .prefix = extensionNameAndPrefix.prefix,
     };
@@ -506,6 +506,12 @@
     return std::make_shared<const Handle>(std::move(duplicatedFd));
 }
 
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<TokenValuePair> unvalidatedConvert(const aidl_hal::TokenValuePair& tokenValuePair) {
+    return TokenValuePair{.token = tokenValuePair.token, .value = tokenValuePair.value};
+}
+#endif  // NN_AIDL_V4_OR_ABOVE
+
 GeneralResult<Capabilities> convert(const aidl_hal::Capabilities& capabilities) {
     return validatedConvert(capabilities);
 }
@@ -551,6 +557,10 @@
     return validatedConvert(handle);
 }
 
+GeneralResult<BufferDesc> convert(const aidl_hal::BufferDesc& bufferDesc) {
+    return validatedConvert(bufferDesc);
+}
+
 GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension) {
     return validatedConvert(extension);
 }
@@ -558,12 +568,32 @@
 GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories) {
     return validatedConvert(memories);
 }
+GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+        const std::vector<aidl_hal::ExtensionNameAndPrefix>& extensionNameAndPrefix) {
+    return unvalidatedConvert(extensionNameAndPrefix);
+}
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<std::vector<TokenValuePair>> convert(
+        const std::vector<aidl_hal::TokenValuePair>& metaData) {
+    return validatedConvert(metaData);
+}
+#endif  // NN_AIDL_V4_OR_ABOVE
 
 GeneralResult<std::vector<OutputShape>> convert(
         const std::vector<aidl_hal::OutputShape>& outputShapes) {
     return validatedConvert(outputShapes);
 }
 
+GeneralResult<std::vector<SharedHandle>> convert(
+        const std::vector<ndk::ScopedFileDescriptor>& handles) {
+    return validatedConvert(handles);
+}
+
+GeneralResult<std::vector<BufferRole>> convert(const std::vector<aidl_hal::BufferRole>& roles) {
+    return validatedConvert(roles);
+}
+
 GeneralResult<std::vector<uint32_t>> toUnsigned(const std::vector<int32_t>& vec) {
     if (!std::all_of(vec.begin(), vec.end(), [](int32_t v) { return v >= 0; })) {
         return NN_ERROR() << "Negative value passed to conversion from signed to unsigned";
@@ -576,42 +606,7 @@
 namespace aidl::android::hardware::neuralnetworks::utils {
 namespace {
 
-template <typename Input>
-using UnvalidatedConvertOutput =
-        std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
-
-template <typename Type>
-nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
-        const std::vector<Type>& arguments) {
-    std::vector<UnvalidatedConvertOutput<Type>> halObject;
-    halObject.reserve(arguments.size());
-    for (const auto& argument : arguments) {
-        halObject.push_back(NN_TRY(unvalidatedConvert(argument)));
-    }
-    return halObject;
-}
-
-template <typename Type>
-nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
-        const std::vector<Type>& arguments) {
-    return unvalidatedConvertVec(arguments);
-}
-
-template <typename Type>
-nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
-    NN_TRY(compliantVersion(canonical));
-    return utils::unvalidatedConvert(canonical);
-}
-
-template <typename Type>
-nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
-        const std::vector<Type>& arguments) {
-    std::vector<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
-    for (size_t i = 0; i < arguments.size(); ++i) {
-        halObject[i] = NN_TRY(validatedConvert(arguments[i]));
-    }
-    return halObject;
-}
+using utils::unvalidatedConvert;
 
 // Helper template for std::visit
 template <class... Ts>
@@ -721,6 +716,74 @@
             operator nn::GeneralResult<Memory>();
 }
 
+nn::GeneralResult<PerformanceInfo> unvalidatedConvert(
+        const nn::Capabilities::PerformanceInfo& info) {
+    return PerformanceInfo{.execTime = info.execTime, .powerUsage = info.powerUsage};
+}
+
+nn::GeneralResult<OperandPerformance> unvalidatedConvert(
+        const nn::Capabilities::OperandPerformance& operandPerformance) {
+    return OperandPerformance{.type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
+                              .info = NN_TRY(unvalidatedConvert(operandPerformance.info))};
+}
+
+nn::GeneralResult<std::vector<OperandPerformance>> unvalidatedConvert(
+        const nn::Capabilities::OperandPerformanceTable& table) {
+    std::vector<OperandPerformance> operandPerformances;
+    operandPerformances.reserve(table.asVector().size());
+    for (const auto& operandPerformance : table.asVector()) {
+        operandPerformances.push_back(NN_TRY(unvalidatedConvert(operandPerformance)));
+    }
+    return operandPerformances;
+}
+
+nn::GeneralResult<ExtensionOperandTypeInformation> unvalidatedConvert(
+        const nn::Extension::OperandTypeInformation& info) {
+    return ExtensionOperandTypeInformation{.type = info.type,
+                                           .isTensor = info.isTensor,
+                                           .byteSize = static_cast<int32_t>(info.byteSize)};
+}
+
+nn::GeneralResult<int64_t> unvalidatedConvert(const nn::Duration& duration) {
+    if (duration < nn::Duration::zero()) {
+        return NN_ERROR() << "Unable to convert invalid (negative) duration";
+    }
+    constexpr std::chrono::nanoseconds::rep kIntMax = std::numeric_limits<int64_t>::max();
+    const auto count = duration.count();
+    return static_cast<int64_t>(std::min(count, kIntMax));
+}
+
+template <typename Input>
+using UnvalidatedConvertOutput =
+        std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
+
+template <typename Type>
+nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
+        const std::vector<Type>& arguments) {
+    std::vector<UnvalidatedConvertOutput<Type>> halObject;
+    halObject.reserve(arguments.size());
+    for (const auto& argument : arguments) {
+        halObject.push_back(NN_TRY(unvalidatedConvert(argument)));
+    }
+    return halObject;
+}
+
+template <typename Type>
+nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
+    NN_TRY(compliantVersion(canonical));
+    return utils::unvalidatedConvert(canonical);
+}
+
+template <typename Type>
+nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
+        const std::vector<Type>& arguments) {
+    std::vector<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
+    for (size_t i = 0; i < arguments.size(); ++i) {
+        halObject[i] = NN_TRY(validatedConvert(arguments[i]));
+    }
+    return halObject;
+}
+
 }  // namespace
 
 nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(const nn::CacheToken& cacheToken) {
@@ -743,6 +806,19 @@
     };
 }
 
+nn::GeneralResult<DeviceType> unvalidatedConvert(const nn::DeviceType& deviceType) {
+    switch (deviceType) {
+        case nn::DeviceType::UNKNOWN:
+            break;
+        case nn::DeviceType::OTHER:
+        case nn::DeviceType::CPU:
+        case nn::DeviceType::GPU:
+        case nn::DeviceType::ACCELERATOR:
+            return static_cast<DeviceType>(deviceType);
+    }
+    return NN_ERROR() << "Invalid DeviceType " << deviceType;
+}
+
 nn::GeneralResult<bool> unvalidatedConvert(const nn::MeasureTiming& measureTiming) {
     return measureTiming == nn::MeasureTiming::YES;
 }
@@ -883,7 +959,7 @@
 }
 
 nn::GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
-        const nn::Model::ExtensionNameAndPrefix& extensionNameToPrefix) {
+        const nn::ExtensionNameAndPrefix& extensionNameToPrefix) {
     return ExtensionNameAndPrefix{
             .name = extensionNameToPrefix.name,
             .prefix = extensionNameToPrefix.prefix,
@@ -956,15 +1032,6 @@
     };
 }
 
-nn::GeneralResult<int64_t> unvalidatedConvert(const nn::Duration& duration) {
-    if (duration < nn::Duration::zero()) {
-        return NN_ERROR() << "Unable to convert invalid (negative) duration";
-    }
-    constexpr std::chrono::nanoseconds::rep kIntMax = std::numeric_limits<int64_t>::max();
-    const auto count = duration.count();
-    return static_cast<int64_t>(std::min(count, kIntMax));
-}
-
 nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration) {
     if (!optionalDuration.has_value()) {
         return kNoTiming;
@@ -989,6 +1056,28 @@
     return ndk::ScopedFileDescriptor(duplicatedFd.release());
 }
 
+nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
+    return Capabilities{
+            .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
+                    unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+            .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
+                    unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
+            .operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance)),
+            .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
+            .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
+    };
+}
+
+nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension) {
+    return Extension{.name = extension.name,
+                     .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes))};
+}
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<TokenValuePair> unvalidatedConvert(const nn::TokenValuePair& tokenValuePair) {
+    return TokenValuePair{.token = tokenValuePair.token, .value = tokenValuePair.value};
+}
+#endif  // NN_AIDL_V4_OR_ABOVE
+
 nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken) {
     return validatedConvert(cacheToken);
 }
@@ -997,6 +1086,10 @@
     return validatedConvert(bufferDesc);
 }
 
+nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType) {
+    return validatedConvert(deviceType);
+}
+
 nn::GeneralResult<bool> convert(const nn::MeasureTiming& measureTiming) {
     return validatedConvert(measureTiming);
 }
@@ -1037,6 +1130,14 @@
     return validatedConvert(outputShapes);
 }
 
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+    return validatedConvert(capabilities);
+}
+
+nn::GeneralResult<Extension> convert(const nn::Extension& extension) {
+    return validatedConvert(extension);
+}
+
 nn::GeneralResult<std::vector<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles) {
     return validatedConvert(bufferRoles);
 }
@@ -1055,6 +1156,21 @@
         const std::vector<nn::SyncFence>& syncFences) {
     return validatedConvert(syncFences);
 }
+nn::GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) {
+    return unvalidatedConvert(extensionNameToPrefix);
+}
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<std::vector<TokenValuePair>> convert(
+        const std::vector<nn::TokenValuePair>& metaData) {
+    return validatedConvert(metaData);
+}
+#endif  // NN_AIDL_V4_OR_ABOVE
+
+nn::GeneralResult<std::vector<Extension>> convert(const std::vector<nn::Extension>& extensions) {
+    return validatedConvert(extensions);
+}
 
 nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec) {
     if (!std::all_of(vec.begin(), vec.end(),
diff --git a/neuralnetworks/aidl/utils/src/Device.cpp b/neuralnetworks/aidl/utils/src/Device.cpp
index 5b7ec4e..f3f4fdb 100644
--- a/neuralnetworks/aidl/utils/src/Device.cpp
+++ b/neuralnetworks/aidl/utils/src/Device.cpp
@@ -215,7 +215,9 @@
 nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
         const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
         nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     // Ensure that model is ready for IPC.
     std::optional<nn::Model> maybeModelInShared;
     const nn::Model& modelInShared =
@@ -225,17 +227,28 @@
     const auto aidlPreference = NN_TRY(convert(preference));
     const auto aidlPriority = NN_TRY(convert(priority));
     const auto aidlDeadline = NN_TRY(convert(deadline));
-    const auto aidlModelCache = NN_TRY(convert(modelCache));
-    const auto aidlDataCache = NN_TRY(convert(dataCache));
+    auto aidlModelCache = NN_TRY(convert(modelCache));
+    auto aidlDataCache = NN_TRY(convert(dataCache));
     const auto aidlToken = NN_TRY(convert(token));
 
-    const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>();
+    const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>(kFeatureLevel);
     const auto scoped = kDeathHandler.protectCallback(cb.get());
 
+    if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+        auto aidlHints = NN_TRY(convert(hints));
+        auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+        const auto ret = kDevice->prepareModelWithConfig(
+                aidlModel,
+                {aidlPreference, aidlPriority, aidlDeadline, std::move(aidlModelCache),
+                 std::move(aidlDataCache), aidlToken, std::move(aidlHints),
+                 std::move(aidlExtensionPrefix)},
+                cb);
+        HANDLE_ASTATUS(ret) << "prepareModel failed";
+        return cb->get();
+    }
     const auto ret = kDevice->prepareModel(aidlModel, aidlPreference, aidlPriority, aidlDeadline,
                                            aidlModelCache, aidlDataCache, aidlToken, cb);
     HANDLE_ASTATUS(ret) << "prepareModel failed";
-
     return cb->get();
 }
 
@@ -247,7 +260,7 @@
     const auto aidlDataCache = NN_TRY(convert(dataCache));
     const auto aidlToken = NN_TRY(convert(token));
 
-    const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>();
+    const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>(kFeatureLevel);
     const auto scoped = kDeathHandler.protectCallback(cb.get());
 
     const auto ret = kDevice->prepareModelFromCache(aidlDeadline, aidlModelCache, aidlDataCache,
diff --git a/neuralnetworks/aidl/utils/src/Execution.cpp b/neuralnetworks/aidl/utils/src/Execution.cpp
index 94edd90..2fd88af 100644
--- a/neuralnetworks/aidl/utils/src/Execution.cpp
+++ b/neuralnetworks/aidl/utils/src/Execution.cpp
@@ -35,44 +35,61 @@
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
-nn::GeneralResult<std::shared_ptr<const Execution>> Execution::create(
-        std::shared_ptr<const PreparedModel> preparedModel, Request request,
-        hal::utils::RequestRelocation relocation, bool measure, int64_t loopTimeoutDuration) {
+nn::GeneralResult<std::shared_ptr<const ExecutionWithCachedRequest>>
+ExecutionWithCachedRequest::create(std::shared_ptr<const PreparedModel> preparedModel,
+                                   Request request, hal::utils::RequestRelocation relocation,
+                                   bool measure, int64_t loopTimeoutDuration) {
     if (preparedModel == nullptr) {
-        return NN_ERROR() << "aidl::utils::Execution::create must have non-null preparedModel";
+        return NN_ERROR() << "aidl::utils::ExecutionWithCachedRequest::create must have non-null "
+                             "preparedModel";
     }
 
-    return std::make_shared<const Execution>(PrivateConstructorTag{}, std::move(preparedModel),
-                                             std::move(request), std::move(relocation), measure,
-                                             loopTimeoutDuration);
+    return std::make_shared<const ExecutionWithCachedRequest>(
+            PrivateConstructorTag{}, std::move(preparedModel), std::move(request),
+            std::move(relocation), measure, loopTimeoutDuration);
 }
 
-Execution::Execution(PrivateConstructorTag /*tag*/,
-                     std::shared_ptr<const PreparedModel> preparedModel, Request request,
-                     hal::utils::RequestRelocation relocation, bool measure,
-                     int64_t loopTimeoutDuration)
+ExecutionWithCachedRequest::ExecutionWithCachedRequest(
+        PrivateConstructorTag /*tag*/, std::shared_ptr<const PreparedModel> preparedModel,
+        Request request, hal::utils::RequestRelocation relocation, bool measure,
+        int64_t loopTimeoutDuration)
     : kPreparedModel(std::move(preparedModel)),
       kRequest(std::move(request)),
       kRelocation(std::move(relocation)),
       kMeasure(measure),
       kLoopTimeoutDuration(loopTimeoutDuration) {}
 
-nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
-        const nn::OptionalTimePoint& deadline) const {
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+ExecutionWithCachedRequest::compute(const nn::OptionalTimePoint& deadline) const {
     const auto aidlDeadline = NN_TRY(convert(deadline));
     return kPreparedModel->executeInternal(kRequest, kMeasure, aidlDeadline, kLoopTimeoutDuration,
-                                           kRelocation);
+                                           {}, {}, kRelocation);
 }
 
-nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> Execution::computeFenced(
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+ExecutionWithCachedRequest::computeFenced(
         const std::vector<nn::SyncFence>& waitFor, const nn::OptionalTimePoint& deadline,
         const nn::OptionalDuration& timeoutDurationAfterFence) const {
     const auto aidlWaitFor = NN_TRY(convert(waitFor));
     const auto aidlDeadline = NN_TRY(convert(deadline));
     const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
-    return kPreparedModel->executeFencedInternal(kRequest, aidlWaitFor, kMeasure, aidlDeadline,
-                                                 kLoopTimeoutDuration,
-                                                 aidlTimeoutDurationAfterFence, kRelocation);
+    return kPreparedModel->executeFencedInternal(
+            kRequest, aidlWaitFor, kMeasure, aidlDeadline, kLoopTimeoutDuration,
+            aidlTimeoutDurationAfterFence, {}, {}, kRelocation);
 }
 
+nn::GeneralResult<std::shared_ptr<const Execution>> Execution::create(
+        std::shared_ptr<aidl_hal::IExecution> execution, hal::utils::RequestRelocation relocation) {
+    if (execution == nullptr) {
+        return NN_ERROR() << "aidl::utils::Execution::create must have non-null execution";
+    }
+
+    return std::make_shared<const Execution>(PrivateConstructorTag{}, std::move(execution),
+                                             std::move(relocation));
+}
+
+Execution::Execution(PrivateConstructorTag /*tag*/, std::shared_ptr<aidl_hal::IExecution> execution,
+                     hal::utils::RequestRelocation relocation)
+    : kExecution(std::move(execution)), kRelocation(std::move(relocation)) {}
+
 }  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/src/InvalidDevice.cpp b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
index c9d9955..33270ff 100644
--- a/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
+++ b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
@@ -167,6 +167,31 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus InvalidDevice::prepareModelWithConfig(
+        const Model& model, const PrepareModelConfig& config,
+        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    if (!utils::valid(config.extensionNameToPrefix)) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT, "Invalid extensionNameToPrefix");
+    }
+    for (const auto& hint : config.compilationHints) {
+        auto result = std::find_if(config.extensionNameToPrefix.begin(),
+                                   config.extensionNameToPrefix.end(),
+                                   [&hint](const ExtensionNameAndPrefix& extension) {
+                                       uint16_t prefix = static_cast<uint32_t>(hint.token) >>
+                                                         IDevice::EXTENSION_TYPE_LOW_BITS_TYPE;
+                                       return prefix == extension.prefix;
+                                   });
+        if (result == config.extensionNameToPrefix.end()) {
+            callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+            return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+                             "Invalid token for compilation hints: " + std::to_string(hint.token));
+        }
+    }
+    return prepareModel(model, config.preference, config.priority, config.deadlineNs,
+                        config.modelCache, config.dataCache, config.cacheToken, callback);
+}
+
 ndk::ScopedAStatus InvalidDevice::prepareModelFromCache(
         int64_t /*deadline*/, const std::vector<ndk::ScopedFileDescriptor>& /*modelCache*/,
         const std::vector<ndk::ScopedFileDescriptor>& /*dataCache*/,
diff --git a/neuralnetworks/aidl/utils/src/PreparedModel.cpp b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
index f25c2c8..7e3a31c 100644
--- a/neuralnetworks/aidl/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
@@ -54,61 +54,16 @@
     return std::make_pair(NN_TRY(nn::convert(timingLaunched)), NN_TRY(nn::convert(timingFenced)));
 }
 
-}  // namespace
-
-nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
-        std::shared_ptr<aidl_hal::IPreparedModel> preparedModel) {
-    if (preparedModel == nullptr) {
-        return NN_ERROR()
-               << "aidl_hal::utils::PreparedModel::create must have non-null preparedModel";
-    }
-
-    return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel));
-}
-
-PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/,
-                             std::shared_ptr<aidl_hal::IPreparedModel> preparedModel)
-    : kPreparedModel(std::move(preparedModel)) {}
-
-nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
-        const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalTimePoint& deadline,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
-    // Ensure that request is ready for IPC.
-    std::optional<nn::Request> maybeRequestInShared;
-    hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
-            &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
-            &maybeRequestInShared, &relocation));
-
-    const auto aidlRequest = NN_TRY(convert(requestInShared));
-    const auto aidlMeasure = NN_TRY(convert(measure));
-    const auto aidlDeadline = NN_TRY(convert(deadline));
-    const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
-    return executeInternal(aidlRequest, aidlMeasure, aidlDeadline, aidlLoopTimeoutDuration,
-                           relocation);
-}
-
-nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
-PreparedModel::executeInternal(const Request& request, bool measure, int64_t deadline,
-                               int64_t loopTimeoutDuration,
-                               const hal::utils::RequestRelocation& relocation) const {
-    if (relocation.input) {
-        relocation.input->flush();
-    }
-
-    ExecutionResult executionResult;
-    const auto ret = kPreparedModel->executeSynchronously(request, measure, deadline,
-                                                          loopTimeoutDuration, &executionResult);
-    HANDLE_ASTATUS(ret) << "executeSynchronously failed";
-    if (!executionResult.outputSufficientSize) {
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> handleExecutionResult(
+        const ExecutionResult& result, const hal::utils::RequestRelocation& relocation) {
+    if (!result.outputSufficientSize) {
         auto canonicalOutputShapes =
-                nn::convert(executionResult.outputShapes).value_or(std::vector<nn::OutputShape>{});
+                nn::convert(result.outputShapes).value_or(std::vector<nn::OutputShape>{});
         return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
                << "execution failed with " << nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
     }
     auto [outputShapes, timing] =
-            NN_TRY(convertExecutionResults(executionResult.outputShapes, executionResult.timing));
+            NN_TRY(convertExecutionResults(result.outputShapes, result.timing));
 
     if (relocation.output) {
         relocation.output->flush();
@@ -117,44 +72,8 @@
 }
 
 nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
-                             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
-                             const nn::OptionalDuration& loopTimeoutDuration,
-                             const nn::OptionalDuration& timeoutDurationAfterFence) const {
-    // Ensure that request is ready for IPC.
-    std::optional<nn::Request> maybeRequestInShared;
-    hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
-            &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
-            &maybeRequestInShared, &relocation));
-
-    const auto aidlRequest = NN_TRY(convert(requestInShared));
-    const auto aidlWaitFor = NN_TRY(convert(waitFor));
-    const auto aidlMeasure = NN_TRY(convert(measure));
-    const auto aidlDeadline = NN_TRY(convert(deadline));
-    const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
-    const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
-    return executeFencedInternal(aidlRequest, aidlWaitFor, aidlMeasure, aidlDeadline,
-                                 aidlLoopTimeoutDuration, aidlTimeoutDurationAfterFence,
-                                 relocation);
-}
-
-nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFencedInternal(const Request& request,
-                                     const std::vector<ndk::ScopedFileDescriptor>& waitFor,
-                                     bool measure, int64_t deadline, int64_t loopTimeoutDuration,
-                                     int64_t timeoutDurationAfterFence,
-                                     const hal::utils::RequestRelocation& relocation) const {
-    if (relocation.input) {
-        relocation.input->flush();
-    }
-
-    FencedExecutionResult result;
-    const auto ret =
-            kPreparedModel->executeFenced(request, waitFor, measure, deadline, loopTimeoutDuration,
-                                          timeoutDurationAfterFence, &result);
-    HANDLE_ASTATUS(ret) << "executeFenced failed";
-
+handleFencedExecutionResult(const FencedExecutionResult& result,
+                            const hal::utils::RequestRelocation& relocation) {
     auto resultSyncFence = nn::SyncFence::createAsSignaled();
     if (result.syncFence.get() != -1) {
         resultSyncFence = nn::SyncFence::create(NN_TRY(nn::convert(result.syncFence))).value();
@@ -165,7 +84,7 @@
         return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "callback is null";
     }
 
-    // If executeFenced required the request memory to be moved into shared memory, block here until
+    // If computeFenced required the request memory to be moved into shared memory, block here until
     // the fenced execution has completed and flush the memory back.
     if (relocation.output) {
         const auto state = resultSyncFence.syncWait({});
@@ -189,9 +108,133 @@
     return std::make_pair(std::move(resultSyncFence), std::move(resultCallback));
 }
 
+}  // namespace
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+        std::shared_ptr<aidl_hal::IPreparedModel> preparedModel, nn::Version featureLevel) {
+    if (preparedModel == nullptr) {
+        return NN_ERROR()
+               << "aidl_hal::utils::PreparedModel::create must have non-null preparedModel";
+    }
+
+    return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+                                                 featureLevel);
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/,
+                             std::shared_ptr<aidl_hal::IPreparedModel> preparedModel,
+                             nn::Version featureLevel)
+    : kPreparedModel(std::move(preparedModel)), kFeatureLevel(featureLevel) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+        const nn::Request& request, nn::MeasureTiming measure,
+        const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+    // Ensure that request is ready for IPC.
+    std::optional<nn::Request> maybeRequestInShared;
+    hal::utils::RequestRelocation relocation;
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+            &maybeRequestInShared, &relocation));
+
+    const auto aidlRequest = NN_TRY(convert(requestInShared));
+    const auto aidlMeasure = NN_TRY(convert(measure));
+    const auto aidlDeadline = NN_TRY(convert(deadline));
+    const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
+    return executeInternal(aidlRequest, aidlMeasure, aidlDeadline, aidlLoopTimeoutDuration, hints,
+                           extensionNameToPrefix, relocation);
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeInternal(const Request& request, bool measure, int64_t deadline,
+                               int64_t loopTimeoutDuration,
+                               const std::vector<nn::TokenValuePair>& hints,
+                               const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
+                               const hal::utils::RequestRelocation& relocation) const {
+    if (relocation.input) {
+        relocation.input->flush();
+    }
+
+    ExecutionResult executionResult;
+    if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+        auto aidlHints = NN_TRY(convert(hints));
+        auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+        const auto ret = kPreparedModel->executeSynchronouslyWithConfig(
+                request,
+                {measure, loopTimeoutDuration, std::move(aidlHints),
+                 std::move(aidlExtensionPrefix)},
+                deadline, &executionResult);
+        HANDLE_ASTATUS(ret) << "executeSynchronouslyWithConfig failed";
+    } else {
+        const auto ret = kPreparedModel->executeSynchronously(
+                request, measure, deadline, loopTimeoutDuration, &executionResult);
+        HANDLE_ASTATUS(ret) << "executeSynchronously failed";
+    }
+    return handleExecutionResult(executionResult, relocation);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(
+        const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+        nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const nn::OptionalDuration& timeoutDurationAfterFence,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+    // Ensure that request is ready for IPC.
+    std::optional<nn::Request> maybeRequestInShared;
+    hal::utils::RequestRelocation relocation;
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+            &maybeRequestInShared, &relocation));
+
+    const auto aidlRequest = NN_TRY(convert(requestInShared));
+    const auto aidlWaitFor = NN_TRY(convert(waitFor));
+    const auto aidlMeasure = NN_TRY(convert(measure));
+    const auto aidlDeadline = NN_TRY(convert(deadline));
+    const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
+    const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
+    return executeFencedInternal(aidlRequest, aidlWaitFor, aidlMeasure, aidlDeadline,
+                                 aidlLoopTimeoutDuration, aidlTimeoutDurationAfterFence, hints,
+                                 extensionNameToPrefix, relocation);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFencedInternal(
+        const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor, bool measure,
+        int64_t deadline, int64_t loopTimeoutDuration, int64_t timeoutDurationAfterFence,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
+        const hal::utils::RequestRelocation& relocation) const {
+    if (relocation.input) {
+        relocation.input->flush();
+    }
+
+    FencedExecutionResult result;
+    if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+        auto aidlHints = NN_TRY(convert(hints));
+        auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+        const auto ret = kPreparedModel->executeFencedWithConfig(
+                request, waitFor,
+                {measure, loopTimeoutDuration, std::move(aidlHints),
+                 std::move(aidlExtensionPrefix)},
+                deadline, timeoutDurationAfterFence, &result);
+        HANDLE_ASTATUS(ret) << "executeFencedWithConfig failed";
+    } else {
+        const auto ret = kPreparedModel->executeFenced(request, waitFor, measure, deadline,
+                                                       loopTimeoutDuration,
+                                                       timeoutDurationAfterFence, &result);
+        HANDLE_ASTATUS(ret) << "executeFenced failed";
+    }
+    return handleFencedExecutionResult(result, relocation);
+}
+
 nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
@@ -202,15 +245,31 @@
     auto aidlRequest = NN_TRY(convert(requestInShared));
     auto aidlMeasure = NN_TRY(convert(measure));
     auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
-    return Execution::create(shared_from_this(), std::move(aidlRequest), std::move(relocation),
-                             aidlMeasure, aidlLoopTimeoutDuration);
+
+    if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+        std::shared_ptr<IExecution> execution;
+        auto aidlHints = NN_TRY(convert(hints));
+        auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+
+        const auto ret = kPreparedModel->createReusableExecution(
+                aidlRequest,
+                {aidlMeasure, aidlLoopTimeoutDuration, std::move(aidlHints),
+                 std::move(aidlExtensionPrefix)},
+                &execution);
+        HANDLE_ASTATUS(ret) << "createReusableExecution failed";
+        return Execution::create(std::move(execution), std::move(relocation));
+    }
+
+    return ExecutionWithCachedRequest::create(shared_from_this(), std::move(aidlRequest),
+                                              std::move(relocation), aidlMeasure,
+                                              aidlLoopTimeoutDuration);
 }
 
 nn::GeneralResult<nn::SharedBurst> PreparedModel::configureExecutionBurst() const {
     std::shared_ptr<IBurst> burst;
     const auto ret = kPreparedModel->configureExecutionBurst(&burst);
     HANDLE_ASTATUS(ret) << "configureExecutionBurst failed";
-    return Burst::create(std::move(burst));
+    return Burst::create(std::move(burst), kFeatureLevel);
 }
 
 std::any PreparedModel::getUnderlyingResource() const {
@@ -218,4 +277,36 @@
     return resource;
 }
 
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
+        const nn::OptionalTimePoint& deadline) const {
+    const auto aidlDeadline = NN_TRY(convert(deadline));
+
+    if (kRelocation.input) {
+        kRelocation.input->flush();
+    }
+
+    ExecutionResult executionResult;
+    auto ret = kExecution->executeSynchronously(aidlDeadline, &executionResult);
+    HANDLE_ASTATUS(ret) << "executeSynchronously failed";
+    return handleExecutionResult(executionResult, kRelocation);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> Execution::computeFenced(
+        const std::vector<nn::SyncFence>& waitFor, const nn::OptionalTimePoint& deadline,
+        const nn::OptionalDuration& timeoutDurationAfterFence) const {
+    const auto aidlWaitFor = NN_TRY(convert(waitFor));
+    const auto aidlDeadline = NN_TRY(convert(deadline));
+    const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
+
+    if (kRelocation.input) {
+        kRelocation.input->flush();
+    }
+
+    FencedExecutionResult result;
+    const auto ret = kExecution->executeFenced(aidlWaitFor, aidlDeadline,
+                                               aidlTimeoutDurationAfterFence, &result);
+    HANDLE_ASTATUS(ret) << "executeFenced failed";
+    return handleFencedExecutionResult(result, kRelocation);
+}
+
 }  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/DeviceTest.cpp b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
index 0366e7d..73727b3 100644
--- a/neuralnetworks/aidl/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
@@ -17,6 +17,7 @@
 #include "MockBuffer.h"
 #include "MockDevice.h"
 #include "MockPreparedModel.h"
+#include "TestUtils.h"
 
 #include <aidl/android/hardware/neuralnetworks/BnDevice.h>
 #include <android/binder_auto_utils.h>
@@ -60,7 +61,6 @@
                                                 .powerUsage = std::numeric_limits<float>::max()};
 constexpr NumberOfCacheFiles kNumberOfCacheFiles = {.numModelCache = nn::kMaxNumberOfCacheFiles - 1,
                                                     .numDataCache = nn::kMaxNumberOfCacheFiles};
-
 constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
 
 std::shared_ptr<MockDevice> createMockDevice() {
@@ -123,6 +123,18 @@
     };
 }
 
+const std::vector<nn::TokenValuePair> kHints = {nn::TokenValuePair{.token = 0, .value = {1}}};
+const std::vector<nn::ExtensionNameAndPrefix> kExtensionNameToPrefix = {
+        nn::ExtensionNameAndPrefix{.name = "com.android.nn_test", .prefix = 1}};
+auto makePreparedModelWithConfigReturn(ErrorStatus launchStatus, ErrorStatus returnStatus,
+                                       const std::shared_ptr<MockPreparedModel>& preparedModel) {
+    return [launchStatus, returnStatus, preparedModel](
+                   const Model& /*model*/, const PrepareModelConfig& /*config*/,
+                   const std::shared_ptr<IPreparedModelCallback>& cb) -> ndk::ScopedAStatus {
+        return makePreparedModelReturnImpl(launchStatus, returnStatus, preparedModel, cb);
+    };
+}
+
 auto makePreparedModelFromCacheReturn(ErrorStatus launchStatus, ErrorStatus returnStatus,
                                       const std::shared_ptr<MockPreparedModel>& preparedModel) {
     return [launchStatus, returnStatus, preparedModel](
@@ -146,26 +158,7 @@
     return ndk::ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
 };
 
-class DeviceTest : public ::testing::TestWithParam<nn::Version> {
-  protected:
-    const nn::Version kVersion = GetParam();
-};
-
-std::string printDeviceTest(const testing::TestParamInfo<nn::Version>& info) {
-    const nn::Version version = info.param;
-    CHECK(!version.runtimeOnlyFeatures);
-    switch (version.level) {
-        case nn::Version::Level::FEATURE_LEVEL_5:
-            return "v1";
-        case nn::Version::Level::FEATURE_LEVEL_6:
-            return "v2";
-        case nn::Version::Level::FEATURE_LEVEL_7:
-            return "v3";
-        default:
-            LOG(FATAL) << "Invalid AIDL version: " << version;
-            return "invalid";
-    }
-}
+class DeviceTest : public VersionedAidlUtilsTestBase {};
 
 }  // namespace
 
@@ -578,6 +571,8 @@
 }
 
 TEST_P(DeviceTest, prepareModel) {
+    if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
     // setup call
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -589,7 +584,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -598,6 +593,8 @@
 }
 
 TEST_P(DeviceTest, prepareModelLaunchError) {
+    if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
     // setup call
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -608,7 +605,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -616,6 +613,8 @@
 }
 
 TEST_P(DeviceTest, prepareModelReturnError) {
+    if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
     // setup call
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -626,7 +625,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -634,6 +633,8 @@
 }
 
 TEST_P(DeviceTest, prepareModelNullptrError) {
+    if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
     // setup call
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -644,7 +645,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -652,6 +653,8 @@
 }
 
 TEST_P(DeviceTest, prepareModelTransportFailure) {
+    if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
     // setup call
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -661,7 +664,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -669,6 +672,8 @@
 }
 
 TEST_P(DeviceTest, prepareModelDeadObject) {
+    if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
     // setup call
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -678,7 +683,7 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -686,6 +691,8 @@
 }
 
 TEST_P(DeviceTest, prepareModelAsyncCrash) {
+    if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
     // setup test
     const auto mockDevice = createMockDevice();
     const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -699,7 +706,157 @@
 
     // run test
     const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
-                                             nn::Priority::DEFAULT, {}, {}, {}, {});
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfig) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockDevice = createMockDevice();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
+    const auto mockPreparedModel = MockPreparedModel::create();
+    EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makePreparedModelWithConfigReturn(ErrorStatus::NONE, ErrorStatus::NONE,
+                                                               mockPreparedModel)));
+
+    // run test
+    const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+                                             kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    EXPECT_NE(result.value(), nullptr);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigLaunchError) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockDevice = createMockDevice();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
+    EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makePreparedModelWithConfigReturn(
+                    ErrorStatus::GENERAL_FAILURE, ErrorStatus::GENERAL_FAILURE, nullptr)));
+
+    // run test
+    const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+                                             kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigReturnError) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockDevice = createMockDevice();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
+    EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makePreparedModelWithConfigReturn(
+                    ErrorStatus::NONE, ErrorStatus::GENERAL_FAILURE, nullptr)));
+
+    // run test
+    const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+                                             kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigNullptrError) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockDevice = createMockDevice();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
+    EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makePreparedModelWithConfigReturn(ErrorStatus::NONE, ErrorStatus::NONE,
+                                                               nullptr)));
+
+    // run test
+    const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+                                             kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigTransportFailure) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockDevice = createMockDevice();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
+    EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+    // run test
+    const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+                                             kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigDeadObject) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockDevice = createMockDevice();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
+    EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+    // run test
+    const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+                                             kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigAsyncCrash) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockDevice = createMockDevice();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
+    const auto ret = [&device]() {
+        DeathMonitor::serviceDied(device->getDeathMonitor());
+        return ndk::ScopedAStatus::ok();
+    };
+    EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(ret));
+
+    // run test
+    const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+                                             nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+                                             kExtensionNameToPrefix);
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -894,9 +1051,6 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-INSTANTIATE_TEST_SUITE_P(TestDevice, DeviceTest,
-                         ::testing::Values(nn::kVersionFeatureLevel5, nn::kVersionFeatureLevel6,
-                                           nn::kVersionFeatureLevel7),
-                         printDeviceTest);
+INSTANTIATE_VERSIONED_AIDL_UTILS_TEST(DeviceTest, kAllAidlVersions);
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/ExecutionTest.cpp b/neuralnetworks/aidl/utils/test/ExecutionTest.cpp
new file mode 100644
index 0000000..8519290
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/ExecutionTest.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockExecution.h"
+#include "MockFencedExecutionCallback.h"
+
+#include <aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <nnapi/IExecution.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/aidl/Execution.h>
+
+#include <functional>
+#include <memory>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+namespace {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::InvokeWithoutArgs;
+using ::testing::SetArgPointee;
+
+const std::shared_ptr<IExecution> kInvalidExecution;
+constexpr auto kNoTiming = Timing{.timeOnDeviceNs = -1, .timeInDriverNs = -1};
+
+constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
+
+constexpr auto makeGeneralFailure = [] {
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+            static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+};
+constexpr auto makeGeneralTransportFailure = [] {
+    return ndk::ScopedAStatus::fromStatus(STATUS_NO_MEMORY);
+};
+constexpr auto makeDeadObjectFailure = [] {
+    return ndk::ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
+};
+
+auto makeFencedExecutionResult(const std::shared_ptr<MockFencedExecutionCallback>& callback) {
+    return [callback](const std::vector<ndk::ScopedFileDescriptor>& /*waitFor*/,
+                      int64_t /*deadline*/, int64_t /*duration*/,
+                      FencedExecutionResult* fencedExecutionResult) {
+        *fencedExecutionResult = FencedExecutionResult{.callback = callback,
+                                                       .syncFence = ndk::ScopedFileDescriptor(-1)};
+        return ndk::ScopedAStatus::ok();
+    };
+}
+
+}  // namespace
+
+TEST(ExecutionTest, invalidExecution) {
+    // run test
+    const auto result = Execution::create(kInvalidExecution, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeSync) {
+    // setup call
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    const auto mockExecutionResult = ExecutionResult{
+            .outputSufficientSize = true,
+            .outputShapes = {},
+            .timing = kNoTiming,
+    };
+    EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+            .Times(1)
+            .WillOnce(
+                    DoAll(SetArgPointee<1>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
+
+    // run test
+    const auto result = execution->compute({});
+
+    // verify result
+    EXPECT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+}
+
+TEST(ExecutionTest, executeSyncError) {
+    // setup test
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+            .Times(1)
+            .WillOnce(Invoke(makeGeneralFailure));
+
+    // run test
+    const auto result = execution->compute({});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeSyncTransportFailure) {
+    // setup test
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+    // run test
+    const auto result = execution->compute({});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeSyncDeadObject) {
+    // setup test
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+    // run test
+    const auto result = execution->compute({});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST(ExecutionTest, executeFenced) {
+    // setup call
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    const auto mockCallback = MockFencedExecutionCallback::create();
+    EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+            .Times(1)
+            .WillOnce(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+                            SetArgPointee<2>(ErrorStatus::NONE), Invoke(makeStatusOk)));
+    EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
+
+    // run test
+    const auto result = execution->computeFenced({}, {}, {});
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    const auto& [syncFence, callback] = result.value();
+    EXPECT_EQ(syncFence.syncWait({}), nn::SyncFence::FenceState::SIGNALED);
+    ASSERT_NE(callback, nullptr);
+
+    // get results from callback
+    const auto callbackResult = callback();
+    ASSERT_TRUE(callbackResult.has_value()) << "Failed with " << callbackResult.error().code << ": "
+                                            << callbackResult.error().message;
+}
+
+TEST(ExecutionTest, executeFencedCallbackError) {
+    // setup call
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    const auto mockCallback = MockFencedExecutionCallback::create();
+    EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+            .Times(1)
+            .WillOnce(Invoke(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+                                   SetArgPointee<2>(ErrorStatus::GENERAL_FAILURE),
+                                   Invoke(makeStatusOk))));
+    EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
+
+    // run test
+    const auto result = execution->computeFenced({}, {}, {});
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    const auto& [syncFence, callback] = result.value();
+    EXPECT_NE(syncFence.syncWait({}), nn::SyncFence::FenceState::ACTIVE);
+    ASSERT_NE(callback, nullptr);
+
+    // verify callback failure
+    const auto callbackResult = callback();
+    ASSERT_FALSE(callbackResult.has_value());
+    EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeFencedError) {
+    // setup test
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
+
+    // run test
+    const auto result = execution->computeFenced({}, {}, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeFencedTransportFailure) {
+    // setup test
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+    // run test
+    const auto result = execution->computeFenced({}, {}, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeFencedDeadObject) {
+    // setup test
+    const auto mockExecution = MockExecution::create();
+    const auto execution = Execution::create(mockExecution, {}).value();
+    EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+    // run test
+    const auto result = execution->computeFenced({}, {}, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/MockBuffer.h b/neuralnetworks/aidl/utils/test/MockBuffer.h
index f77fa86..7a05a0f 100644
--- a/neuralnetworks/aidl/utils/test/MockBuffer.h
+++ b/neuralnetworks/aidl/utils/test/MockBuffer.h
@@ -21,7 +21,6 @@
 #include <android/binder_interface_utils.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <hidl/Status.h>
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
diff --git a/neuralnetworks/aidl/utils/test/MockBurst.h b/neuralnetworks/aidl/utils/test/MockBurst.h
index 5083bbd..609bd30 100644
--- a/neuralnetworks/aidl/utils/test/MockBurst.h
+++ b/neuralnetworks/aidl/utils/test/MockBurst.h
@@ -21,7 +21,6 @@
 #include <android/binder_interface_utils.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <hidl/Status.h>
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
@@ -32,6 +31,10 @@
                  bool measureTiming, int64_t deadline, int64_t loopTimeoutDuration,
                  ExecutionResult* executionResult),
                 (override));
+    MOCK_METHOD(ndk::ScopedAStatus, executeSynchronouslyWithConfig,
+                (const Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
+                 const ExecutionConfig& config, int64_t deadline, ExecutionResult* executionResult),
+                (override));
     MOCK_METHOD(ndk::ScopedAStatus, releaseMemoryResource, (int64_t memoryIdentifierToken),
                 (override));
 };
diff --git a/neuralnetworks/aidl/utils/test/MockDevice.h b/neuralnetworks/aidl/utils/test/MockDevice.h
index 3a28d55..47b8346 100644
--- a/neuralnetworks/aidl/utils/test/MockDevice.h
+++ b/neuralnetworks/aidl/utils/test/MockDevice.h
@@ -50,6 +50,10 @@
                  const std::vector<uint8_t>& token,
                  const std::shared_ptr<IPreparedModelCallback>& callback),
                 (override));
+    MOCK_METHOD(ndk::ScopedAStatus, prepareModelWithConfig,
+                (const Model& model, const PrepareModelConfig& config,
+                 const std::shared_ptr<IPreparedModelCallback>& callback),
+                (override));
     MOCK_METHOD(ndk::ScopedAStatus, prepareModelFromCache,
                 (int64_t deadline, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
                  const std::vector<ndk::ScopedFileDescriptor>& dataCache,
diff --git a/neuralnetworks/aidl/utils/test/MockExecution.h b/neuralnetworks/aidl/utils/test/MockExecution.h
new file mode 100644
index 0000000..782e54f
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/MockExecution.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_EXECUTION_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_EXECUTION_H
+
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
+#include <android/binder_interface_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+class MockExecution final : public BnExecution {
+  public:
+    static std::shared_ptr<MockExecution> create();
+
+    MOCK_METHOD(ndk::ScopedAStatus, executeSynchronously,
+                (int64_t deadline, ExecutionResult* executionResult), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, executeFenced,
+                (const std::vector<ndk::ScopedFileDescriptor>& waitFor, int64_t deadline,
+                 int64_t duration, FencedExecutionResult* fencedExecutionResult),
+                (override));
+};
+
+inline std::shared_ptr<MockExecution> MockExecution::create() {
+    return ndk::SharedRefBase::make<MockExecution>();
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_EXECUTION_H
diff --git a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
index 06f9ea2..29449bb 100644
--- a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
+++ b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
@@ -22,7 +22,6 @@
 #include <android/binder_interface_utils.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <hidl/Status.h>
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
diff --git a/neuralnetworks/aidl/utils/test/MockPreparedModel.h b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
index a4ae2b7..a5b3b66 100644
--- a/neuralnetworks/aidl/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
@@ -17,12 +17,11 @@
 #ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL_H
 #define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL_H
 
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
 #include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
 #include <android/binder_interface_utils.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/Status.h>
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
@@ -39,8 +38,21 @@
                  bool measureTiming, int64_t deadline, int64_t loopTimeoutDuration,
                  int64_t duration, FencedExecutionResult* fencedExecutionResult),
                 (override));
+    MOCK_METHOD(ndk::ScopedAStatus, executeSynchronouslyWithConfig,
+                (const Request& request, const ExecutionConfig& config, int64_t deadline,
+                 ExecutionResult* executionResult),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, executeFencedWithConfig,
+                (const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+                 const ExecutionConfig& config, int64_t deadline, int64_t duration,
+                 FencedExecutionResult* fencedExecutionResult),
+                (override));
     MOCK_METHOD(ndk::ScopedAStatus, configureExecutionBurst, (std::shared_ptr<IBurst> * burst),
                 (override));
+    MOCK_METHOD(ndk::ScopedAStatus, createReusableExecution,
+                (const Request& request, const ExecutionConfig& config,
+                 std::shared_ptr<IExecution>* execution),
+                (override));
 };
 
 inline std::shared_ptr<MockPreparedModel> MockPreparedModel::create() {
diff --git a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
index 8bb5c90..bf6136d 100644
--- a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
@@ -15,8 +15,10 @@
  */
 
 #include "MockBurst.h"
+#include "MockExecution.h"
 #include "MockFencedExecutionCallback.h"
 #include "MockPreparedModel.h"
+#include "TestUtils.h"
 
 #include <aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.h>
 #include <gmock/gmock.h>
@@ -66,21 +68,40 @@
     };
 }
 
+class PreparedModelTest : public VersionedAidlUtilsTestBase {};
+
+const std::vector<nn::TokenValuePair> kHints = {nn::TokenValuePair{.token = 0, .value = {1}}};
+const std::vector<nn::ExtensionNameAndPrefix> kExtensionNameToPrefix = {
+        nn::ExtensionNameAndPrefix{.name = "com.android.nn_test", .prefix = 1}};
+auto makeFencedExecutionWithConfigResult(
+        const std::shared_ptr<MockFencedExecutionCallback>& callback) {
+    return [callback](const Request& /*request*/,
+                      const std::vector<ndk::ScopedFileDescriptor>& /*waitFor*/,
+                      const ExecutionConfig& /*config*/, int64_t /*deadline*/, int64_t /*duration*/,
+                      FencedExecutionResult* fencedExecutionResult) {
+        *fencedExecutionResult = FencedExecutionResult{.callback = callback,
+                                                       .syncFence = ndk::ScopedFileDescriptor(-1)};
+        return ndk::ScopedAStatus::ok();
+    };
+}
+
 }  // namespace
 
-TEST(PreparedModelTest, invalidPreparedModel) {
+TEST_P(PreparedModelTest, invalidPreparedModel) {
     // run test
-    const auto result = PreparedModel::create(kInvalidPreparedModel);
+    const auto result = PreparedModel::create(kInvalidPreparedModel, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, executeSync) {
+TEST_P(PreparedModelTest, executeSync) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup call
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     const auto mockExecutionResult = ExecutionResult{
             .outputSufficientSize = true,
             .outputShapes = {},
@@ -92,65 +113,73 @@
                     DoAll(SetArgPointee<4>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     EXPECT_TRUE(result.has_value())
             << "Failed with " << result.error().code << ": " << result.error().message;
 }
 
-TEST(PreparedModelTest, executeSyncError) {
+TEST_P(PreparedModelTest, executeSyncError) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
             .Times(1)
             .WillOnce(Invoke(makeGeneralFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, executeSyncTransportFailure) {
+TEST_P(PreparedModelTest, executeSyncTransportFailure) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, executeSyncDeadObject) {
+TEST_P(PreparedModelTest, executeSyncDeadObject) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(PreparedModelTest, executeFenced) {
+TEST_P(PreparedModelTest, executeFenced) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup call
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     const auto mockCallback = MockFencedExecutionCallback::create();
     EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
             .Times(1)
@@ -161,7 +190,7 @@
             .WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -176,10 +205,12 @@
                                             << callbackResult.error().message;
 }
 
-TEST(PreparedModelTest, executeFencedCallbackError) {
+TEST_P(PreparedModelTest, executeFencedCallbackError) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup call
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     const auto mockCallback = MockFencedExecutionCallback::create();
     EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
             .Times(1)
@@ -191,7 +222,7 @@
             .WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -206,59 +237,67 @@
     EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, executeFencedError) {
+TEST_P(PreparedModelTest, executeFencedError) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, executeFencedTransportFailure) {
+TEST_P(PreparedModelTest, executeFencedTransportFailure) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, executeFencedDeadObject) {
+TEST_P(PreparedModelTest, executeFencedDeadObject) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(PreparedModelTest, reusableExecuteSync) {
+TEST_P(PreparedModelTest, reusableExecuteSync) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup call
     const uint32_t kNumberOfComputations = 2;
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     const auto mockExecutionResult = ExecutionResult{
             .outputSufficientSize = true,
             .outputShapes = {},
@@ -270,7 +309,7 @@
                     DoAll(SetArgPointee<4>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -283,16 +322,18 @@
     }
 }
 
-TEST(PreparedModelTest, reusableExecuteSyncError) {
+TEST_P(PreparedModelTest, reusableExecuteSyncError) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
             .Times(1)
             .WillOnce(Invoke(makeGeneralFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -303,16 +344,18 @@
     EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, reusableExecuteSyncTransportFailure) {
+TEST_P(PreparedModelTest, reusableExecuteSyncTransportFailure) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -323,16 +366,18 @@
     EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, reusableExecuteSyncDeadObject) {
+TEST_P(PreparedModelTest, reusableExecuteSyncDeadObject) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -343,11 +388,13 @@
     EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(PreparedModelTest, reusableExecuteFenced) {
+TEST_P(PreparedModelTest, reusableExecuteFenced) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup call
     const uint32_t kNumberOfComputations = 2;
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     const auto mockCallback = MockFencedExecutionCallback::create();
     EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
             .Times(kNumberOfComputations)
@@ -358,7 +405,7 @@
             .WillRepeatedly(Invoke(makeFencedExecutionResult(mockCallback)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -379,10 +426,12 @@
     }
 }
 
-TEST(PreparedModelTest, reusableExecuteFencedCallbackError) {
+TEST_P(PreparedModelTest, reusableExecuteFencedCallbackError) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup call
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     const auto mockCallback = MockFencedExecutionCallback::create();
     EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
             .Times(1)
@@ -394,7 +443,7 @@
             .WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -413,16 +462,18 @@
     EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, reusableExecuteFencedError) {
+TEST_P(PreparedModelTest, reusableExecuteFencedError) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -433,16 +484,18 @@
     EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, reusableExecuteFencedTransportFailure) {
+TEST_P(PreparedModelTest, reusableExecuteFencedTransportFailure) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -453,16 +506,18 @@
     EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, reusableExecuteFencedDeadObject) {
+TEST_P(PreparedModelTest, reusableExecuteFencedDeadObject) {
+    if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
     EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // create execution
-    const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+    const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
     ASSERT_TRUE(createResult.has_value())
             << "Failed with " << createResult.error().code << ": " << createResult.error().message;
     ASSERT_NE(createResult.value(), nullptr);
@@ -473,14 +528,214 @@
     EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(PreparedModelTest, configureExecutionBurst) {
+TEST_P(PreparedModelTest, executeSyncWithConfig) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    const auto mockExecutionResult = ExecutionResult{
+            .outputSufficientSize = true,
+            .outputShapes = {},
+            .timing = kNoTiming,
+    };
+    EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+            .Times(1)
+            .WillOnce(
+                    DoAll(SetArgPointee<3>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
+
+    // run test
+    const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    EXPECT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+}
+
+TEST_P(PreparedModelTest, executeSyncWithConfigError) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makeGeneralFailure));
+
+    // run test
+    const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeSyncWithConfigTransportFailure) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+    // run test
+    const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeSyncWithConfigDeadObject) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+    // run test
+    const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfig) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    const auto mockCallback = MockFencedExecutionCallback::create();
+    EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+            .Times(1)
+            .WillOnce(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+                            SetArgPointee<2>(ErrorStatus::NONE), Invoke(makeStatusOk)));
+    EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makeFencedExecutionWithConfigResult(mockCallback)));
+
+    // run test
+    const auto result =
+            preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    const auto& [syncFence, callback] = result.value();
+    EXPECT_EQ(syncFence.syncWait({}), nn::SyncFence::FenceState::SIGNALED);
+    ASSERT_NE(callback, nullptr);
+
+    // get results from callback
+    const auto callbackResult = callback();
+    ASSERT_TRUE(callbackResult.has_value()) << "Failed with " << callbackResult.error().code << ": "
+                                            << callbackResult.error().message;
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigCallbackError) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup call
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    const auto mockCallback = MockFencedExecutionCallback::create();
+    EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+            .Times(1)
+            .WillOnce(Invoke(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+                                   SetArgPointee<2>(ErrorStatus::GENERAL_FAILURE),
+                                   Invoke(makeStatusOk))));
+    EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+            .Times(1)
+            .WillOnce(Invoke(makeFencedExecutionWithConfigResult(mockCallback)));
+
+    // run test
+    const auto result =
+            preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    const auto& [syncFence, callback] = result.value();
+    EXPECT_NE(syncFence.syncWait({}), nn::SyncFence::FenceState::ACTIVE);
+    ASSERT_NE(callback, nullptr);
+
+    // verify callback failure
+    const auto callbackResult = callback();
+    ASSERT_FALSE(callbackResult.has_value());
+    EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigError) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
+
+    // run test
+    const auto result =
+            preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigTransportFailure) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+    // run test
+    const auto result =
+            preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigDeadObject) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+    EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+    // run test
+    const auto result =
+            preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(PreparedModelTest, configureExecutionBurst) {
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
     const auto mockBurst = ndk::SharedRefBase::make<MockBurst>();
     EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
             .Times(1)
             .WillOnce(DoAll(SetArgPointee<0>(mockBurst), Invoke(makeStatusOk)));
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
 
     // run test
     const auto result = preparedModel->configureExecutionBurst();
@@ -491,13 +746,13 @@
     EXPECT_NE(result.value(), nullptr);
 }
 
-TEST(PreparedModelTest, configureExecutionBurstError) {
+TEST_P(PreparedModelTest, configureExecutionBurstError) {
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
     EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
 
     // run test
     const auto result = preparedModel->configureExecutionBurst();
@@ -507,13 +762,13 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, configureExecutionBurstTransportFailure) {
+TEST_P(PreparedModelTest, configureExecutionBurstTransportFailure) {
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
     EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
 
     // run test
     const auto result = preparedModel->configureExecutionBurst();
@@ -523,13 +778,13 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(PreparedModelTest, configureExecutionBurstDeadObject) {
+TEST_P(PreparedModelTest, configureExecutionBurstDeadObject) {
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
     EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
 
     // run test
     const auto result = preparedModel->configureExecutionBurst();
@@ -539,10 +794,84 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(PreparedModelTest, getUnderlyingResource) {
+TEST_P(PreparedModelTest, createReusableExecution) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
     // setup test
     const auto mockPreparedModel = MockPreparedModel::create();
-    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+    const auto mockExecution = ndk::SharedRefBase::make<MockExecution>();
+    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+            .Times(1)
+            .WillOnce(DoAll(SetArgPointee<2>(mockExecution), Invoke(makeStatusOk)));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+    // run test
+    const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    EXPECT_NE(result.value(), nullptr);
+}
+
+TEST_P(PreparedModelTest, createReusableExecutionError) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+    // run test
+    const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, createReusableExecutionTransportFailure) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+    // run test
+    const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, createReusableExecutionDeadObject) {
+    if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+    // run test
+    const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(PreparedModelTest, getUnderlyingResource) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
 
     // run test
     const auto resource = preparedModel->getUnderlyingResource();
@@ -554,4 +883,6 @@
     EXPECT_EQ(maybeMock->get(), mockPreparedModel.get());
 }
 
+INSTANTIATE_VERSIONED_AIDL_UTILS_TEST(PreparedModelTest, kAllAidlVersions);
+
 }  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/TestUtils.cpp b/neuralnetworks/aidl/utils/test/TestUtils.cpp
new file mode 100644
index 0000000..9abec88
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/TestUtils.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestUtils.h"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <string>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+std::string printTestVersion(const testing::TestParamInfo<nn::Version>& info) {
+    switch (info.param.level) {
+        case nn::Version::Level::FEATURE_LEVEL_5:
+            return "v1";
+        case nn::Version::Level::FEATURE_LEVEL_6:
+            return "v2";
+        case nn::Version::Level::FEATURE_LEVEL_7:
+            return "v3";
+        case nn::Version::Level::FEATURE_LEVEL_8:
+            return "v4";
+        default:
+            LOG(FATAL) << "Invalid AIDL version: " << info.param;
+            return "invalid";
+    }
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/TestUtils.h b/neuralnetworks/aidl/utils/test/TestUtils.h
new file mode 100644
index 0000000..23f734a
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/TestUtils.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_TEST_UTILS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_TEST_UTILS_H
+
+#include <gtest/gtest.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <string>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+class VersionedAidlUtilsTestBase : public ::testing::TestWithParam<nn::Version> {
+  protected:
+    const nn::Version kVersion = GetParam();
+};
+
+std::string printTestVersion(const testing::TestParamInfo<nn::Version>& info);
+
+inline const auto kAllAidlVersions =
+        ::testing::Values(nn::kVersionFeatureLevel5, nn::kVersionFeatureLevel6,
+                          nn::kVersionFeatureLevel7, nn::kVersionFeatureLevel8);
+
+#define INSTANTIATE_VERSIONED_AIDL_UTILS_TEST(TestSuite, versions) \
+    INSTANTIATE_TEST_SUITE_P(Versioned, TestSuite, versions, printTestVersion)
+
+}  // namespace aidl::android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_TEST_UTILS_H
diff --git a/neuralnetworks/aidl/vts/functional/Android.bp b/neuralnetworks/aidl/vts/functional/Android.bp
index a102fe0..356cdb0 100644
--- a/neuralnetworks/aidl/vts/functional/Android.bp
+++ b/neuralnetworks/aidl/vts/functional/Android.bp
@@ -30,6 +30,7 @@
         "neuralnetworks_vts_functional_defaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
+    host_supported: true,
     srcs: [
         "BasicTests.cpp",
         "Callbacks.cpp",
@@ -46,20 +47,14 @@
     ],
     shared_libs: [
         "libbinder_ndk",
-        "libnativewindow",
-        "libvndksupport",
     ],
     static_libs: [
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
         "libaidlcommonsupport",
-        "libgmock",
-        "libhidlmemory",
         "libneuralnetworks_common",
         "libneuralnetworks_generated_test_harness",
-        "libsync",
     ],
     whole_static_libs: [
+        "neuralnetworks_generated_AIDL_V3_example",
         "neuralnetworks_generated_AIDL_V2_example",
         "neuralnetworks_generated_V1_0_example",
         "neuralnetworks_generated_V1_1_example",
@@ -72,6 +67,34 @@
     ],
     test_suites: [
         "general-tests",
-        "vts",
     ],
+    target: {
+        android: {
+            shared_libs: [
+                "libnativewindow",
+                "libvndksupport",
+            ],
+            static_libs: [
+                "libsync",
+            ],
+            test_suites: [
+                "vts",
+            ],
+            test_config: "AndroidTestDevice.xml",
+        },
+        host: {
+            shared_libs: [
+                "libtextclassifier_hash",
+            ],
+            static_libs: [
+                "neuralnetworks_canonical_sample_driver",
+                "neuralnetworks_utils_hal_adapter_aidl",
+            ],
+            exclude_static_libs: [
+                "VtsHalHidlTestUtils",
+                "libaidlvintf_gtest_helper",
+            ],
+            test_config: "AndroidTestHost.xml",
+        },
+    },
 }
diff --git a/neuralnetworks/aidl/vts/functional/AndroidTest.xml b/neuralnetworks/aidl/vts/functional/AndroidTestDevice.xml
similarity index 100%
rename from neuralnetworks/aidl/vts/functional/AndroidTest.xml
rename to neuralnetworks/aidl/vts/functional/AndroidTestDevice.xml
diff --git a/neuralnetworks/aidl/vts/functional/AndroidTestHost.xml b/neuralnetworks/aidl/vts/functional/AndroidTestHost.xml
new file mode 100644
index 0000000..7372a31
--- /dev/null
+++ b/neuralnetworks/aidl/vts/functional/AndroidTestHost.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalNeuralnetworksTargetTest.">
+    <test class="com.android.tradefed.testtype.HostGTest" >
+        <option name="module-name" value="VtsHalNeuralnetworksTargetTest" />
+        <option name="native-test-timeout" value="15m" />
+    </test>
+</configuration>
+
diff --git a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
index 77208aa..7451f7e 100644
--- a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
@@ -23,7 +23,6 @@
 #include <fcntl.h>
 #include <ftw.h>
 #include <gtest/gtest.h>
-#include <hidlmemory/mapping.h>
 #include <unistd.h>
 
 #include <cstdio>
@@ -34,7 +33,6 @@
 
 #include "Callbacks.h"
 #include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
 #include "TestHarness.h"
 #include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
@@ -229,7 +227,11 @@
 
         // Create cache directory. The cache directory and a temporary cache file is always created
         // to test the behavior of prepareModelFromCache, even when caching is not supported.
+#ifdef __ANDROID__
         char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX";
+#else   // __ANDROID__
+        char cacheDirTemp[] = "/tmp/TestCompilationCachingXXXXXX";
+#endif  // __ANDROID__
         char* cacheDir = mkdtemp(cacheDirTemp);
         ASSERT_NE(cacheDir, nullptr);
         mCacheDir = cacheDir;
diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
index f67fd34..40f6cd1 100644
--- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
@@ -20,7 +20,6 @@
 #include <aidl/android/hardware/neuralnetworks/RequestMemoryPool.h>
 #include <android-base/logging.h>
 #include <android/binder_auto_utils.h>
-#include <android/sync.h>
 #include <gtest/gtest.h>
 
 #include <algorithm>
@@ -30,7 +29,6 @@
 #include <numeric>
 #include <vector>
 
-#include <MemoryUtils.h>
 #include <android/binder_status.h>
 #include <nnapi/Result.h>
 #include <nnapi/SharedMemory.h>
@@ -43,6 +41,10 @@
 #include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
+#ifdef __ANDROID__
+#include <android/sync.h>
+#endif  // __ANDROID__
+
 namespace aidl::android::hardware::neuralnetworks::vts::functional {
 
 namespace nn = ::android::nn;
@@ -58,25 +60,66 @@
     bool measureTiming;
     OutputType outputType;
     MemoryType memoryType;
+    bool reusable;
     // `reportSkipping` indicates if a test should print an info message in case
     // it is skipped. The field is set to true by default and is set to false in
     // quantization coupling tests to suppress skipping a test
     bool reportSkipping;
-    TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType)
-        : executor(executor),
-          measureTiming(measureTiming),
-          outputType(outputType),
-          memoryType(memoryType),
-          reportSkipping(true) {}
+    // `useConfig` indicates if a test should use execute*WithConfig functions for the execution.
+    bool useConfig;
     TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType,
-               bool reportSkipping)
+               bool reusable)
         : executor(executor),
           measureTiming(measureTiming),
           outputType(outputType),
           memoryType(memoryType),
-          reportSkipping(reportSkipping) {}
+          reusable(reusable),
+          reportSkipping(true),
+          useConfig(false) {}
+    TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType,
+               bool reusable, bool reportSkipping)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          memoryType(memoryType),
+          reusable(reusable),
+          reportSkipping(reportSkipping),
+          useConfig(false) {}
+    TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType,
+               bool reusable, bool reportSkipping, bool useConfig)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          memoryType(memoryType),
+          reusable(reusable),
+          reportSkipping(reportSkipping),
+          useConfig(useConfig) {}
 };
 
+std::string toString(OutputType type) {
+    switch (type) {
+        case OutputType::FULLY_SPECIFIED:
+            return "FULLY_SPECIFIED";
+        case OutputType::UNSPECIFIED:
+            return "UNSPECIFIED";
+        case OutputType::INSUFFICIENT:
+            return "INSUFFICIENT";
+        case OutputType::MISSED_DEADLINE:
+            return "MISSED_DEADLINE";
+    }
+}
+
+std::string toString(const TestConfig& config) {
+    std::stringstream ss;
+    ss << "TestConfig{.executor=" << toString(config.executor)
+       << ", .measureTiming=" << (config.measureTiming ? "true" : "false")
+       << ", .outputType=" << toString(config.outputType)
+       << ", .memoryType=" << toString(config.memoryType)
+       << ", .reusable=" << (config.reusable ? "true" : "false")
+       << ", .useConfig=" << (config.useConfig ? "true" : "false") << "}";
+    return ss.str();
+}
+
 enum class IOType { INPUT, OUTPUT };
 
 class DeviceMemoryAllocator {
@@ -240,10 +283,14 @@
 }  // namespace
 
 void waitForSyncFence(int syncFd) {
-    constexpr int kInfiniteTimeout = -1;
     ASSERT_GT(syncFd, 0);
+#ifdef __ANDROID__
+    constexpr int kInfiniteTimeout = -1;
     int r = sync_wait(syncFd, kInfiniteTimeout);
     ASSERT_GE(r, 0);
+#else   // __ANDROID__
+    LOG(FATAL) << "waitForSyncFence not supported on host";
+#endif  // __ANDROID__
 }
 
 Model createModel(const TestModel& testModel) {
@@ -558,209 +605,266 @@
         loopTimeoutDurationNs = 1 * kMillisecond;
     }
 
-    ErrorStatus executionStatus;
-    std::vector<OutputShape> outputShapes;
-    Timing timing = kNoTiming;
-    switch (testConfig.executor) {
-        case Executor::SYNC: {
-            SCOPED_TRACE("synchronous");
+    std::shared_ptr<IExecution> execution;
+    if (testConfig.reusable) {
+        const auto ret = preparedModel->createReusableExecution(
+                request, {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}}, &execution);
+        ASSERT_TRUE(ret.isOk()) << static_cast<nn::ErrorStatus>(ret.getServiceSpecificError());
+        ASSERT_NE(nullptr, execution.get());
+    }
 
-            ExecutionResult executionResult;
-            // execute
-            const auto ret = preparedModel->executeSynchronously(request, testConfig.measureTiming,
-                                                                 kNoDeadline, loopTimeoutDurationNs,
-                                                                 &executionResult);
-            ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
-                    << ret.getDescription();
-            if (ret.isOk()) {
-                executionStatus = executionResult.outputSufficientSize
-                                          ? ErrorStatus::NONE
-                                          : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
-                outputShapes = std::move(executionResult.outputShapes);
-                timing = executionResult.timing;
-            } else {
-                executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
-            }
-            break;
-        }
-        case Executor::BURST: {
-            SCOPED_TRACE("burst");
+    const auto executeAndCheckResults = [&preparedModel, &execution, &testConfig, &testModel,
+                                         &context, &request, loopTimeoutDurationNs, skipped]() {
+        ErrorStatus executionStatus;
+        std::vector<OutputShape> outputShapes;
+        Timing timing = kNoTiming;
+        switch (testConfig.executor) {
+            case Executor::SYNC: {
+                SCOPED_TRACE("synchronous");
 
-            // create burst
-            std::shared_ptr<IBurst> burst;
-            auto ret = preparedModel->configureExecutionBurst(&burst);
-            ASSERT_TRUE(ret.isOk()) << ret.getDescription();
-            ASSERT_NE(nullptr, burst.get());
-
-            // associate a unique slot with each memory pool
-            int64_t currentSlot = 0;
-            std::vector<int64_t> slots;
-            slots.reserve(request.pools.size());
-            for (const auto& pool : request.pools) {
-                if (pool.getTag() == RequestMemoryPool::Tag::pool) {
-                    slots.push_back(currentSlot++);
+                ExecutionResult executionResult;
+                // execute
+                ::ndk::ScopedAStatus ret;
+                if (testConfig.reusable) {
+                    ret = execution->executeSynchronously(kNoDeadline, &executionResult);
+                } else if (testConfig.useConfig) {
+                    ret = preparedModel->executeSynchronouslyWithConfig(
+                            request, {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}},
+                            kNoDeadline, &executionResult);
                 } else {
-                    EXPECT_EQ(pool.getTag(), RequestMemoryPool::Tag::token);
-                    slots.push_back(-1);
+                    ret = preparedModel->executeSynchronously(request, testConfig.measureTiming,
+                                                              kNoDeadline, loopTimeoutDurationNs,
+                                                              &executionResult);
                 }
+                ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
+                        << ret.getDescription();
+                if (ret.isOk()) {
+                    executionStatus = executionResult.outputSufficientSize
+                                              ? ErrorStatus::NONE
+                                              : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
+                    outputShapes = std::move(executionResult.outputShapes);
+                    timing = executionResult.timing;
+                } else {
+                    executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
+                }
+                break;
             }
+            case Executor::BURST: {
+                SCOPED_TRACE("burst");
 
-            ExecutionResult executionResult;
-            // execute
-            ret = burst->executeSynchronously(request, slots, testConfig.measureTiming, kNoDeadline,
-                                              loopTimeoutDurationNs, &executionResult);
-            ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
-                    << ret.getDescription();
-            if (ret.isOk()) {
-                executionStatus = executionResult.outputSufficientSize
-                                          ? ErrorStatus::NONE
-                                          : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
-                outputShapes = std::move(executionResult.outputShapes);
-                timing = executionResult.timing;
-            } else {
-                executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
-            }
-
-            // Mark each slot as unused after the execution. This is unnecessary because the burst
-            // is freed after this scope ends, but this is here to test the functionality.
-            for (int64_t slot : slots) {
-                ret = burst->releaseMemoryResource(slot);
+                // create burst
+                std::shared_ptr<IBurst> burst;
+                auto ret = preparedModel->configureExecutionBurst(&burst);
                 ASSERT_TRUE(ret.isOk()) << ret.getDescription();
-            }
+                ASSERT_NE(nullptr, burst.get());
 
-            break;
-        }
-        case Executor::FENCED: {
-            SCOPED_TRACE("fenced");
-            ErrorStatus result = ErrorStatus::NONE;
-            FencedExecutionResult executionResult;
-            auto ret = preparedModel->executeFenced(request, {}, testConfig.measureTiming,
-                                                    kNoDeadline, loopTimeoutDurationNs, kNoDuration,
-                                                    &executionResult);
-            ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
-                    << ret.getDescription();
-            if (!ret.isOk()) {
-                result = static_cast<ErrorStatus>(ret.getServiceSpecificError());
-                executionStatus = result;
-            } else if (executionResult.syncFence.get() != -1) {
-                std::vector<ndk::ScopedFileDescriptor> waitFor;
-                auto dupFd = dup(executionResult.syncFence.get());
-                ASSERT_NE(dupFd, -1);
-                waitFor.emplace_back(dupFd);
-                // If a sync fence is returned, try start another run waiting for the sync fence.
-                ret = preparedModel->executeFenced(request, waitFor, testConfig.measureTiming,
-                                                   kNoDeadline, loopTimeoutDurationNs, kNoDuration,
-                                                   &executionResult);
-                ASSERT_TRUE(ret.isOk());
-                waitForSyncFence(executionResult.syncFence.get());
-            }
-            if (result == ErrorStatus::NONE) {
-                ASSERT_NE(executionResult.callback, nullptr);
-                Timing timingFenced;
-                auto ret = executionResult.callback->getExecutionInfo(&timing, &timingFenced,
-                                                                      &executionStatus);
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-        }
-        default: {
-            FAIL() << "Unsupported execution mode for AIDL interface.";
-        }
-    }
-
-    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
-        executionStatus == ErrorStatus::GENERAL_FAILURE) {
-        if (skipped != nullptr) {
-            *skipped = true;
-        }
-        if (!testConfig.reportSkipping) {
-            return;
-        }
-        LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
-                     "execute model that it does not support.";
-        std::cout << "[          ]   Early termination of test because vendor service cannot "
-                     "execute model that it does not support."
-                  << std::endl;
-        GTEST_SKIP();
-    }
-    if (!testConfig.measureTiming) {
-        EXPECT_EQ(timing, kNoTiming);
-    } else {
-        if (timing.timeOnDeviceNs != -1 && timing.timeInDriverNs != -1) {
-            EXPECT_LE(timing.timeOnDeviceNs, timing.timeInDriverNs);
-        }
-    }
-
-    switch (testConfig.outputType) {
-        case OutputType::FULLY_SPECIFIED:
-            if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) {
-                // Executor::FENCED does not support zero-sized output.
-                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
-                return;
-            }
-            // If the model output operands are fully specified, outputShapes must be either
-            // either empty, or have the same number of elements as the number of outputs.
-            ASSERT_EQ(ErrorStatus::NONE, executionStatus);
-            ASSERT_TRUE(outputShapes.size() == 0 ||
-                        outputShapes.size() == testModel.main.outputIndexes.size());
-            break;
-        case OutputType::UNSPECIFIED:
-            if (testConfig.executor == Executor::FENCED) {
-                // For Executor::FENCED, the output shape must be fully specified.
-                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
-                return;
-            }
-            // If the model output operands are not fully specified, outputShapes must have
-            // the same number of elements as the number of outputs.
-            ASSERT_EQ(ErrorStatus::NONE, executionStatus);
-            ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
-            break;
-        case OutputType::INSUFFICIENT:
-            if (testConfig.executor == Executor::FENCED) {
-                // For Executor::FENCED, the output shape must be fully specified.
-                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
-                return;
-            }
-            ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
-            ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
-            // Check that all returned output dimensions are at least as fully specified as the
-            // union of the information about the corresponding operand in the model and in the
-            // request. In this test, all model outputs have known rank with all dimensions
-            // unspecified, and no dimensional information is provided in the request.
-            for (uint32_t i = 0; i < outputShapes.size(); i++) {
-                ASSERT_EQ(outputShapes[i].isSufficient, i != kInsufficientOutputIndex);
-                const auto& actual = outputShapes[i].dimensions;
-                const auto& golden =
-                        testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
-                ASSERT_EQ(actual.size(), golden.size());
-                for (uint32_t j = 0; j < actual.size(); j++) {
-                    if (actual[j] == 0) continue;
-                    EXPECT_EQ(actual[j], golden[j]) << "index: " << j;
+                // associate a unique slot with each memory pool
+                int64_t currentSlot = 0;
+                std::vector<int64_t> slots;
+                slots.reserve(request.pools.size());
+                for (const auto& pool : request.pools) {
+                    if (pool.getTag() == RequestMemoryPool::Tag::pool) {
+                        slots.push_back(currentSlot++);
+                    } else {
+                        EXPECT_EQ(pool.getTag(), RequestMemoryPool::Tag::token);
+                        slots.push_back(-1);
+                    }
                 }
+
+                ExecutionResult executionResult;
+                // execute
+                if (testConfig.useConfig) {
+                    ret = burst->executeSynchronouslyWithConfig(
+                            request, slots,
+                            {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}}, kNoDeadline,
+                            &executionResult);
+                } else {
+                    ret = burst->executeSynchronously(request, slots, testConfig.measureTiming,
+                                                      kNoDeadline, loopTimeoutDurationNs,
+                                                      &executionResult);
+                }
+                ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
+                        << ret.getDescription();
+                if (ret.isOk()) {
+                    executionStatus = executionResult.outputSufficientSize
+                                              ? ErrorStatus::NONE
+                                              : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
+                    outputShapes = std::move(executionResult.outputShapes);
+                    timing = executionResult.timing;
+                } else {
+                    executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
+                }
+
+                // Mark each slot as unused after the execution. This is unnecessary because the
+                // burst is freed after this scope ends, but this is here to test the functionality.
+                for (int64_t slot : slots) {
+                    ret = burst->releaseMemoryResource(slot);
+                    ASSERT_TRUE(ret.isOk()) << ret.getDescription();
+                }
+
+                break;
             }
-            return;
-        case OutputType::MISSED_DEADLINE:
-            ASSERT_TRUE(executionStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
-                        executionStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT)
-                    << "executionStatus = " << executionStatus;
-            return;
+            case Executor::FENCED: {
+                SCOPED_TRACE("fenced");
+                ErrorStatus result = ErrorStatus::NONE;
+                FencedExecutionResult executionResult;
+                ::ndk::ScopedAStatus ret;
+                if (testConfig.reusable) {
+                    ret = execution->executeFenced({}, kNoDeadline, kNoDuration, &executionResult);
+                } else if (testConfig.useConfig) {
+                    ret = preparedModel->executeFencedWithConfig(
+                            request, {}, {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}},
+                            kNoDeadline, kNoDuration, &executionResult);
+                } else {
+                    ret = preparedModel->executeFenced(request, {}, testConfig.measureTiming,
+                                                       kNoDeadline, loopTimeoutDurationNs,
+                                                       kNoDuration, &executionResult);
+                }
+                ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
+                        << ret.getDescription();
+                if (!ret.isOk()) {
+                    result = static_cast<ErrorStatus>(ret.getServiceSpecificError());
+                    executionStatus = result;
+                } else if (executionResult.syncFence.get() != -1) {
+                    std::vector<ndk::ScopedFileDescriptor> waitFor;
+                    auto dupFd = dup(executionResult.syncFence.get());
+                    ASSERT_NE(dupFd, -1);
+                    waitFor.emplace_back(dupFd);
+                    // If a sync fence is returned, try start another run waiting for the sync
+                    // fence.
+                    if (testConfig.reusable) {
+                        ret = execution->executeFenced(waitFor, kNoDeadline, kNoDuration,
+                                                       &executionResult);
+                    } else if (testConfig.useConfig) {
+                        ret = preparedModel->executeFencedWithConfig(
+                                request, waitFor,
+                                {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}},
+                                kNoDeadline, kNoDuration, &executionResult);
+                    } else {
+                        ret = preparedModel->executeFenced(
+                                request, waitFor, testConfig.measureTiming, kNoDeadline,
+                                loopTimeoutDurationNs, kNoDuration, &executionResult);
+                    }
+                    ASSERT_TRUE(ret.isOk());
+                    waitForSyncFence(executionResult.syncFence.get());
+                }
+                if (result == ErrorStatus::NONE) {
+                    ASSERT_NE(executionResult.callback, nullptr);
+                    Timing timingFenced;
+                    auto ret = executionResult.callback->getExecutionInfo(&timing, &timingFenced,
+                                                                          &executionStatus);
+                    ASSERT_TRUE(ret.isOk());
+                }
+                break;
+            }
+            default: {
+                FAIL() << "Unsupported execution mode for AIDL interface.";
+            }
+        }
+
+        if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
+            executionStatus == ErrorStatus::GENERAL_FAILURE) {
+            if (skipped != nullptr) {
+                *skipped = true;
+            }
+            if (!testConfig.reportSkipping) {
+                return;
+            }
+            LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                         "execute model that it does not support.";
+            std::cout << "[          ]   Early termination of test because vendor service cannot "
+                         "execute model that it does not support."
+                      << std::endl;
+            GTEST_SKIP();
+        }
+        if (!testConfig.measureTiming) {
+            EXPECT_EQ(timing, kNoTiming);
+        } else {
+            if (timing.timeOnDeviceNs != -1 && timing.timeInDriverNs != -1) {
+                EXPECT_LE(timing.timeOnDeviceNs, timing.timeInDriverNs);
+            }
+        }
+
+        switch (testConfig.outputType) {
+            case OutputType::FULLY_SPECIFIED:
+                if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) {
+                    // Executor::FENCED does not support zero-sized output.
+                    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+                    return;
+                }
+                // If the model output operands are fully specified, outputShapes must be either
+                // either empty, or have the same number of elements as the number of outputs.
+                ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+                ASSERT_TRUE(outputShapes.size() == 0 ||
+                            outputShapes.size() == testModel.main.outputIndexes.size());
+                break;
+            case OutputType::UNSPECIFIED:
+                if (testConfig.executor == Executor::FENCED) {
+                    // For Executor::FENCED, the output shape must be fully specified.
+                    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+                    return;
+                }
+                // If the model output operands are not fully specified, outputShapes must have
+                // the same number of elements as the number of outputs.
+                ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+                ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
+                break;
+            case OutputType::INSUFFICIENT:
+                if (testConfig.executor == Executor::FENCED) {
+                    // For Executor::FENCED, the output shape must be fully specified.
+                    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+                    return;
+                }
+                ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
+                ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
+                // Check that all returned output dimensions are at least as fully specified as the
+                // union of the information about the corresponding operand in the model and in the
+                // request. In this test, all model outputs have known rank with all dimensions
+                // unspecified, and no dimensional information is provided in the request.
+                for (uint32_t i = 0; i < outputShapes.size(); i++) {
+                    ASSERT_EQ(outputShapes[i].isSufficient, i != kInsufficientOutputIndex);
+                    const auto& actual = outputShapes[i].dimensions;
+                    const auto& golden =
+                            testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
+                    ASSERT_EQ(actual.size(), golden.size());
+                    for (uint32_t j = 0; j < actual.size(); j++) {
+                        if (actual[j] == 0) continue;
+                        EXPECT_EQ(actual[j], golden[j]) << "index: " << j;
+                    }
+                }
+                return;
+            case OutputType::MISSED_DEADLINE:
+                ASSERT_TRUE(executionStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+                            executionStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT)
+                        << "executionStatus = " << executionStatus;
+                return;
+        }
+
+        // Go through all outputs, check returned output shapes.
+        for (uint32_t i = 0; i < outputShapes.size(); i++) {
+            EXPECT_TRUE(outputShapes[i].isSufficient);
+            const auto& expect =
+                    testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
+            const auto unsignedActual = nn::toUnsigned(outputShapes[i].dimensions);
+            ASSERT_TRUE(unsignedActual.has_value());
+            const std::vector<uint32_t>& actual = unsignedActual.value();
+            EXPECT_EQ(expect, actual);
+        }
+
+        // Retrieve execution results.
+        const std::vector<TestBuffer> outputs = context.getOutputBuffers(testModel, request);
+
+        // We want "close-enough" results.
+        checkResults(testModel, outputs);
+    };
+
+    executeAndCheckResults();
+
+    // For reusable execution tests, run the execution twice.
+    if (testConfig.reusable) {
+        SCOPED_TRACE("Second execution");
+        executeAndCheckResults();
     }
-
-    // Go through all outputs, check returned output shapes.
-    for (uint32_t i = 0; i < outputShapes.size(); i++) {
-        EXPECT_TRUE(outputShapes[i].isSufficient);
-        const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
-        const auto unsignedActual = nn::toUnsigned(outputShapes[i].dimensions);
-        ASSERT_TRUE(unsignedActual.has_value());
-        const std::vector<uint32_t>& actual = unsignedActual.value();
-        EXPECT_EQ(expect, actual);
-    }
-
-    // Retrieve execution results.
-    const std::vector<TestBuffer> outputs = context.getOutputBuffers(testModel, request);
-
-    // We want "close-enough" results.
-    checkResults(testModel, outputs);
 }
 
 void EvaluatePreparedModel(const std::shared_ptr<IDevice>& device,
@@ -770,6 +874,15 @@
     std::vector<bool> measureTimingList;
     std::vector<Executor> executorList;
     std::vector<MemoryType> memoryTypeList;
+    std::vector<bool> reusableList = {false};
+    std::vector<bool> useConfigList = {false};
+
+    int deviceVersion;
+    ASSERT_TRUE(device->getInterfaceVersion(&deviceVersion).isOk());
+    if (deviceVersion >= kMinAidlLevelForFL8) {
+        reusableList.push_back(true);
+        useConfigList.push_back(true);
+    }
 
     switch (testKind) {
         case TestKind::GENERAL: {
@@ -788,7 +901,11 @@
             outputTypesList = {OutputType::FULLY_SPECIFIED};
             measureTimingList = {false};
             executorList = {Executor::SYNC, Executor::BURST, Executor::FENCED};
+#ifdef __ANDROID__
             memoryTypeList = {MemoryType::BLOB_AHWB, MemoryType::DEVICE};
+#else   // __ANDROID__
+            memoryTypeList = {MemoryType::DEVICE};  // BLOB_AHWB is not supported on the host.
+#endif  // __ANDROID__
         } break;
         case TestKind::FENCED_COMPUTE: {
             outputTypesList = {OutputType::FULLY_SPECIFIED};
@@ -812,8 +929,16 @@
         for (const bool measureTiming : measureTimingList) {
             for (const Executor executor : executorList) {
                 for (const MemoryType memoryType : memoryTypeList) {
-                    const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
-                    EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+                    for (const bool reusable : reusableList) {
+                        for (const bool useConfig : useConfigList) {
+                            if ((useConfig || executor == Executor::BURST) && reusable) continue;
+                            const TestConfig testConfig(executor, measureTiming, outputType,
+                                                        memoryType, reusable,
+                                                        /*reportSkipping=*/true, useConfig);
+                            SCOPED_TRACE(toString(testConfig));
+                            EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+                        }
+                    }
                 }
             }
         }
@@ -833,7 +958,7 @@
         for (const bool measureTiming : measureTimingList) {
             for (const Executor executor : executorList) {
                 const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::ASHMEM,
-                                            /*reportSkipping=*/false);
+                                            /*reusable=*/false, /*reportSkipping=*/false);
                 bool baseSkipped = false;
                 EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped);
                 bool coupledSkipped = false;
@@ -871,6 +996,13 @@
             createPreparedModel(device, model, &preparedModel);
             if (preparedModel == nullptr) return;
             EvaluatePreparedModel(device, preparedModel, testModel, testKind);
+            int32_t deviceVersion;
+            ASSERT_TRUE(device->getInterfaceVersion(&deviceVersion).isOk());
+            if (deviceVersion >= kMinAidlLevelForFL8) {
+                createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ true,
+                                    /*useConfig*/ true);
+                EvaluatePreparedModel(device, preparedModel, testModel, testKind);
+            }
         } break;
         case TestKind::QUANTIZATION_COUPLING: {
             ASSERT_TRUE(testModel.hasQuant8CoupledOperands());
diff --git a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
index cd5475c..f8341b1 100644
--- a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "neuralnetworks_aidl_hal_test"
 
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidl/android/hardware/neuralnetworks/IPreparedModel.h>
 #include <android-base/logging.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_interface_utils.h>
@@ -33,7 +34,6 @@
 
 #include "Callbacks.h"
 #include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
 #include "Utils.h"
 #include "VtsHalNeuralnetworks.h"
 
@@ -191,7 +191,7 @@
 }
 
 // A placeholder invalid IPreparedModel class for MemoryDomainAllocateTest.InvalidPreparedModel
-class InvalidPreparedModel : public BnPreparedModel {
+class InvalidPreparedModel final : public IPreparedModel {
   public:
     ndk::ScopedAStatus executeSynchronously(const Request&, bool, int64_t, int64_t,
                                             ExecutionResult*) override {
@@ -204,10 +204,37 @@
         return ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
     }
+    ndk::ScopedAStatus executeSynchronouslyWithConfig(const Request&, const ExecutionConfig&,
+                                                      int64_t, ExecutionResult*) override {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+    }
+    ndk::ScopedAStatus executeFencedWithConfig(const Request&,
+                                               const std::vector<ndk::ScopedFileDescriptor>&,
+                                               const ExecutionConfig&, int64_t, int64_t,
+                                               FencedExecutionResult*) override {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+    }
     ndk::ScopedAStatus configureExecutionBurst(std::shared_ptr<IBurst>*) override {
         return ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
     }
+    ndk::ScopedAStatus createReusableExecution(const aidl_hal::Request&, const ExecutionConfig&,
+                                               std::shared_ptr<aidl_hal::IExecution>*) override {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+    }
+    ndk::ScopedAStatus getInterfaceVersion(int32_t* /*interfaceVersion*/) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+    }
+    ndk::ScopedAStatus getInterfaceHash(std::string* /*interfaceHash*/) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+    }
+    ndk::SpAIBinder asBinder() override { return ::ndk::SpAIBinder{}; }
+    bool isRemote() override { return true; }
 };
 
 template <typename... Args>
diff --git a/neuralnetworks/aidl/vts/functional/Utils.cpp b/neuralnetworks/aidl/vts/functional/Utils.cpp
index 325a436..1bc76f2 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.cpp
+++ b/neuralnetworks/aidl/vts/functional/Utils.cpp
@@ -21,18 +21,20 @@
 #include <aidl/android/hardware/neuralnetworks/OperandType.h>
 #include <android-base/logging.h>
 #include <android/binder_status.h>
-#include <android/hardware_buffer.h>
 
 #include <sys/mman.h>
 #include <iostream>
 #include <limits>
 #include <numeric>
 
-#include <MemoryUtils.h>
 #include <nnapi/SharedMemory.h>
 #include <nnapi/hal/aidl/Conversions.h>
 #include <nnapi/hal/aidl/Utils.h>
 
+#ifdef __ANDROID__
+#include <android/hardware_buffer.h>
+#endif  // __ANDROID__
+
 namespace aidl::android::hardware::neuralnetworks {
 
 using test_helper::TestBuffer;
@@ -140,7 +142,8 @@
     return ahwb->mIsValid ? std::move(ahwb) : nullptr;
 }
 
-void TestBlobAHWB::initialize(uint32_t size) {
+void TestBlobAHWB::initialize([[maybe_unused]] uint32_t size) {
+#ifdef __ANDROID__
     mIsValid = false;
     ASSERT_GT(size, 0);
     const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
@@ -164,6 +167,9 @@
     mAidlMemory = utils::convert(mMemory).value();
 
     mIsValid = true;
+#else   // __ANDROID__
+    LOG(FATAL) << "TestBlobAHWB::initialize not supported on host";
+#endif  // __ANDROID__
 }
 
 std::string gtestCompliantName(std::string name) {
@@ -177,6 +183,17 @@
     return os << toString(errorStatus);
 }
 
+std::string toString(MemoryType type) {
+    switch (type) {
+        case MemoryType::ASHMEM:
+            return "ASHMEM";
+        case MemoryType::BLOB_AHWB:
+            return "BLOB_AHWB";
+        case MemoryType::DEVICE:
+            return "DEVICE";
+    }
+}
+
 Request ExecutionContext::createRequest(const TestModel& testModel, MemoryType memoryType) {
     CHECK(memoryType == MemoryType::ASHMEM || memoryType == MemoryType::BLOB_AHWB);
 
diff --git a/neuralnetworks/aidl/vts/functional/Utils.h b/neuralnetworks/aidl/vts/functional/Utils.h
index ca81418..4e0a4aa 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.h
+++ b/neuralnetworks/aidl/vts/functional/Utils.h
@@ -18,7 +18,6 @@
 #define ANDROID_HARDWARE_NEURALNETWORKS_AIDL_UTILS_H
 
 #include <android-base/logging.h>
-#include <android/hardware_buffer.h>
 #include <gtest/gtest.h>
 
 #include <algorithm>
@@ -111,6 +110,8 @@
 
 enum class MemoryType { ASHMEM, BLOB_AHWB, DEVICE };
 
+std::string toString(MemoryType type);
+
 // Manages the lifetime of memory resources used in an execution.
 class ExecutionContext {
     DISALLOW_COPY_AND_ASSIGN(ExecutionContext);
diff --git a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
index fdc7eff..931ba25 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
@@ -77,6 +77,28 @@
     ASSERT_EQ(nullptr, preparedModel.get());
 }
 
+static void validatePrepareModelWithConfig(const std::shared_ptr<IDevice>& device,
+                                           const std::string& message, const Model& model,
+                                           ExecutionPreference preference, Priority priority) {
+    SCOPED_TRACE(message + " [prepareModelWithConfig]");
+
+    std::shared_ptr<PreparedModelCallback> preparedModelCallback =
+            ndk::SharedRefBase::make<PreparedModelCallback>();
+    const auto prepareLaunchStatus = device->prepareModelWithConfig(
+            model, {preference, priority, kNoDeadline, {}, {}, kEmptyCacheToken, {}, {}},
+            preparedModelCallback);
+    ASSERT_FALSE(prepareLaunchStatus.isOk());
+    ASSERT_EQ(prepareLaunchStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorStatus>(prepareLaunchStatus.getServiceSpecificError()),
+              ErrorStatus::INVALID_ARGUMENT);
+
+    preparedModelCallback->wait();
+    ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
+    std::shared_ptr<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+    ASSERT_EQ(nullptr, preparedModel.get());
+}
+
 static bool validExecutionPreference(ExecutionPreference preference) {
     return preference == ExecutionPreference::LOW_POWER ||
            preference == ExecutionPreference::FAST_SINGLE_ANSWER ||
@@ -103,6 +125,13 @@
     }
 
     validatePrepareModel(device, message, model, preference, priority);
+
+    int32_t aidlVersion;
+    ASSERT_TRUE(device->getInterfaceVersion(&aidlVersion).isOk());
+    if (aidlVersion >= kMinAidlLevelForFL8) {
+        // prepareModelWithConfig must satisfy all requirements enforced by prepareModel.
+        validatePrepareModelWithConfig(device, message, model, preference, priority);
+    }
 }
 
 static uint32_t addOperand(Model* model) {
diff --git a/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp b/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp
index 29e2471..d749841 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp
@@ -36,6 +36,51 @@
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
+// Test request validation with reusable execution.
+static void validateReusableExecution(const std::shared_ptr<IPreparedModel>& preparedModel,
+                                      const std::string& message, const Request& request,
+                                      bool measure) {
+    // createReusableExecution
+    std::shared_ptr<IExecution> execution;
+    {
+        SCOPED_TRACE(message + " [createReusableExecution]");
+        const auto createStatus = preparedModel->createReusableExecution(
+                request, {measure, kOmittedTimeoutDuration, {}, {}}, &execution);
+        if (!createStatus.isOk()) {
+            ASSERT_EQ(createStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+            ASSERT_EQ(static_cast<ErrorStatus>(createStatus.getServiceSpecificError()),
+                      ErrorStatus::INVALID_ARGUMENT);
+            ASSERT_EQ(nullptr, execution);
+            return;
+        } else {
+            ASSERT_NE(nullptr, execution);
+        }
+    }
+
+    // synchronous
+    {
+        SCOPED_TRACE(message + " [executeSynchronously]");
+        ExecutionResult executionResult;
+        const auto executeStatus = execution->executeSynchronously(kNoDeadline, &executionResult);
+        ASSERT_FALSE(executeStatus.isOk());
+        ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+                  ErrorStatus::INVALID_ARGUMENT);
+    }
+
+    // fenced
+    {
+        SCOPED_TRACE(message + " [executeFenced]");
+        FencedExecutionResult executionResult;
+        const auto executeStatus =
+                execution->executeFenced({}, kNoDeadline, kNoDuration, &executionResult);
+        ASSERT_FALSE(executeStatus.isOk());
+        ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+                  ErrorStatus::INVALID_ARGUMENT);
+    }
+}
+
 // Primary validation function. This function will take a valid request, apply a
 // mutation to it to invalidate the request, then pass it to interface calls
 // that use the request.
@@ -101,6 +146,63 @@
         ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
                   ErrorStatus::INVALID_ARGUMENT);
     }
+
+    int32_t aidlVersion;
+    ASSERT_TRUE(preparedModel->getInterfaceVersion(&aidlVersion).isOk());
+    if (aidlVersion < kMinAidlLevelForFL8) {
+        return;
+    }
+
+    // validate reusable execution
+    validateReusableExecution(preparedModel, message, request, measure);
+
+    // synchronous with empty hints
+    {
+        SCOPED_TRACE(message + " [executeSynchronouslyWithConfig]");
+        ExecutionResult executionResult;
+        const auto executeStatus = preparedModel->executeSynchronouslyWithConfig(
+                request, {measure, kOmittedTimeoutDuration, {}, {}}, kNoDeadline, &executionResult);
+        ASSERT_FALSE(executeStatus.isOk());
+        ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+                  ErrorStatus::INVALID_ARGUMENT);
+    }
+
+    // fenced with empty hints
+    {
+        SCOPED_TRACE(message + " [executeFencedWithConfig]");
+        FencedExecutionResult executionResult;
+        const auto executeStatus = preparedModel->executeFencedWithConfig(
+                request, {}, {false, kOmittedTimeoutDuration, {}, {}}, kNoDeadline, kNoDuration,
+                &executionResult);
+        ASSERT_FALSE(executeStatus.isOk());
+        ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+                  ErrorStatus::INVALID_ARGUMENT);
+    }
+
+    // burst with empty hints
+    {
+        SCOPED_TRACE(message + " [burst executeSynchronouslyWithConfig]");
+
+        // create burst
+        std::shared_ptr<IBurst> burst;
+        auto ret = preparedModel->configureExecutionBurst(&burst);
+        ASSERT_TRUE(ret.isOk()) << ret.getDescription();
+        ASSERT_NE(nullptr, burst.get());
+
+        // use -1 for all memory identifier tokens
+        const std::vector<int64_t> slots(request.pools.size(), -1);
+
+        ExecutionResult executionResult;
+        const auto executeStatus = burst->executeSynchronouslyWithConfig(
+                request, slots, {measure, kOmittedTimeoutDuration, {}, {}}, kNoDeadline,
+                &executionResult);
+        ASSERT_FALSE(executeStatus.isOk());
+        ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+                  ErrorStatus::INVALID_ARGUMENT);
+    }
 }
 
 std::shared_ptr<IBurst> createBurst(const std::shared_ptr<IPreparedModel>& preparedModel) {
diff --git a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
index c417356..51b4805 100644
--- a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "neuralnetworks_aidl_hal_test"
+
 #include "VtsHalNeuralnetworks.h"
 
 #include <android-base/logging.h>
@@ -28,20 +29,27 @@
 #include <utility>
 
 #include <TestHarness.h>
-#include <aidl/Vintf.h>
 #include <nnapi/hal/aidl/Conversions.h>
 
 #include "Callbacks.h"
 #include "GeneratedTestHarness.h"
 #include "Utils.h"
 
+#ifdef __ANDROID__
+#include <aidl/Vintf.h>
+#else  // __ANDROID__
+#include <CanonicalDevice.h>
+#include <nnapi/hal/aidl/Adapter.h>
+#endif  // __ANDROID__
+
 namespace aidl::android::hardware::neuralnetworks::vts::functional {
 
 using implementation::PreparedModelCallback;
 
 // internal helper function
 void createPreparedModel(const std::shared_ptr<IDevice>& device, const Model& model,
-                         std::shared_ptr<IPreparedModel>* preparedModel, bool reportSkipping) {
+                         std::shared_ptr<IPreparedModel>* preparedModel, bool reportSkipping,
+                         bool useConfig) {
     ASSERT_NE(nullptr, preparedModel);
     *preparedModel = nullptr;
 
@@ -56,11 +64,25 @@
     // launch prepare model
     const std::shared_ptr<PreparedModelCallback> preparedModelCallback =
             ndk::SharedRefBase::make<PreparedModelCallback>();
-    const auto prepareLaunchStatus =
-            device->prepareModel(model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority,
-                                 kNoDeadline, {}, {}, kEmptyCacheToken, preparedModelCallback);
-    ASSERT_TRUE(prepareLaunchStatus.isOk()) << prepareLaunchStatus.getDescription();
-
+    if (useConfig) {
+        const auto prepareLaunchStatus =
+                device->prepareModelWithConfig(model,
+                                               {ExecutionPreference::FAST_SINGLE_ANSWER,
+                                                kDefaultPriority,
+                                                kNoDeadline,
+                                                {},
+                                                {},
+                                                kEmptyCacheToken,
+                                                {},
+                                                {}},
+                                               preparedModelCallback);
+        ASSERT_TRUE(prepareLaunchStatus.isOk()) << prepareLaunchStatus.getDescription();
+    } else {
+        const auto prepareLaunchStatus = device->prepareModel(
+                model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, kNoDeadline, {},
+                {}, kEmptyCacheToken, preparedModelCallback);
+        ASSERT_TRUE(prepareLaunchStatus.isOk()) << prepareLaunchStatus.getDescription();
+    }
     // retrieve prepared model
     preparedModelCallback->wait();
     const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
@@ -96,6 +118,7 @@
     ASSERT_TRUE(deviceIsResponsive);
 }
 
+#ifdef __ANDROID__
 static NamedDevice makeNamedDevice(const std::string& name) {
     ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
     return {name, IDevice::fromBinder(binder)};
@@ -112,6 +135,14 @@
     std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
     return namedDevices;
 }
+#else   // __ANDROID__
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    const std::string name = "nnapi-sample";
+    auto device = std::make_shared<const ::android::nn::sample::Device>(name);
+    auto aidlDevice = adapter::adapt(device);
+    return {{name, aidlDevice}};
+}
+#endif  // __ANDROID__
 
 const std::vector<NamedDevice>& getNamedDevices() {
     const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
diff --git a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h
index 4312d3a..00d705c 100644
--- a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h
@@ -30,6 +30,8 @@
 using NamedDevice = Named<std::shared_ptr<IDevice>>;
 using NeuralNetworksAidlTestParam = NamedDevice;
 
+constexpr int kMinAidlLevelForFL8 = 4;
+
 class NeuralNetworksAidlTest : public testing::TestWithParam<NeuralNetworksAidlTestParam> {
   protected:
     void SetUp() override;
@@ -49,8 +51,8 @@
 // Create an IPreparedModel object. If the model cannot be prepared,
 // "preparedModel" will be nullptr instead.
 void createPreparedModel(const std::shared_ptr<IDevice>& device, const Model& model,
-                         std::shared_ptr<IPreparedModel>* preparedModel,
-                         bool reportSkipping = true);
+                         std::shared_ptr<IPreparedModel>* preparedModel, bool reportSkipping = true,
+                         bool useConfig = false);
 
 enum class Executor { SYNC, BURST, FENCED };
 
diff --git a/neuralnetworks/utils/adapter/Android.bp b/neuralnetworks/utils/adapter/Android.bp
deleted file mode 100644
index d073106..0000000
--- a/neuralnetworks/utils/adapter/Android.bp
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_library_static {
-    name: "neuralnetworks_utils_hal_adapter",
-    defaults: ["neuralnetworks_utils_defaults"],
-    srcs: ["src/*"],
-    local_include_dirs: ["include/nnapi/hal"],
-    export_include_dirs: ["include"],
-    static_libs: [
-        "neuralnetworks_types",
-        "neuralnetworks_utils_hal_1_0",
-        "neuralnetworks_utils_hal_1_1",
-        "neuralnetworks_utils_hal_1_2",
-        "neuralnetworks_utils_hal_1_3",
-    ],
-    shared_libs: [
-        "android.hardware.neuralnetworks@1.0",
-        "android.hardware.neuralnetworks@1.1",
-        "android.hardware.neuralnetworks@1.2",
-        "android.hardware.neuralnetworks@1.3",
-        "libfmq",
-    ],
-}
diff --git a/neuralnetworks/utils/adapter/aidl/Android.bp b/neuralnetworks/utils/adapter/aidl/Android.bp
new file mode 100644
index 0000000..8269a3d
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_adapter_aidl",
+    defaults: [
+        "neuralnetworks_use_latest_utils_hal_aidl",
+        "neuralnetworks_utils_defaults",
+    ],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal/aidl/"],
+    export_include_dirs: ["include"],
+    static_libs: [
+        "neuralnetworks_types",
+        "neuralnetworks_utils_hal_common",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+}
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
new file mode 100644
index 0000000..4c0b328
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_ADAPTER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_ADAPTER_H
+
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+/**
+ * A self-contained unit of work to be executed.
+ */
+using Task = std::function<void()>;
+
+/**
+ * A type-erased executor which executes a task asynchronously.
+ *
+ * This executor is also provided an optional deadline for when the caller expects is the upper
+ * bound for the amount of time to complete the task. If needed, the Executor can retrieve the
+ * Application ID (Android User ID) by calling AIBinder_getCallingUid in android/binder_ibinder.h.
+ */
+using Executor = std::function<void(Task, ::android::nn::OptionalTimePoint)>;
+
+/**
+ * Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
+ *
+ * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
+ * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
+ *
+ * @param device NNAPI canonical IDevice interface object to be adapted.
+ * @param executor Type-erased executor to handle executing tasks asynchronously.
+ * @return AIDL NN HAL IDevice interface object.
+ */
+std::shared_ptr<BnDevice> adapt(::android::nn::SharedDevice device, Executor executor);
+
+/**
+ * Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
+ *
+ * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
+ * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
+ *
+ * This function uses a default executor, which will execute tasks from a detached thread.
+ *
+ * @param device NNAPI canonical IDevice interface object to be adapted.
+ * @return AIDL NN HAL IDevice interface object.
+ */
+std::shared_ptr<BnDevice> adapt(::android::nn::SharedDevice device);
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_ADAPTER_H
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Buffer.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Buffer.h
new file mode 100644
index 0000000..701e43e
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Buffer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_BUFFER_H
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/Memory.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IBuffer.h>
+
+#include <memory>
+#include <vector>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+// Class that adapts nn::IBuffer to BnBuffer.
+class Buffer : public BnBuffer {
+  public:
+    explicit Buffer(::android::nn::SharedBuffer buffer);
+
+    ndk::ScopedAStatus copyFrom(const Memory& src, const std::vector<int32_t>& dimensions) override;
+    ndk::ScopedAStatus copyTo(const Memory& dst) override;
+
+  private:
+    const ::android::nn::SharedBuffer kBuffer;
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_BUFFER_H
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Burst.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Burst.h
new file mode 100644
index 0000000..8d42e2f
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Burst.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_BURST_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_BURST_H
+
+#include <aidl/android/hardware/neuralnetworks/BnBurst.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/Request.h>
+#include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IBurst.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+// Class that adapts nn::Burst to BnBurst.
+class Burst : public BnBurst {
+  public:
+    // Precondition: burst != nullptr
+    explicit Burst(::android::nn::SharedBurst burst);
+
+    ndk::ScopedAStatus executeSynchronously(const Request& request,
+                                            const std::vector<int64_t>& memoryIdentifierTokens,
+                                            bool measureTiming, int64_t deadlineNs,
+                                            int64_t loopTimeoutDurationNs,
+                                            ExecutionResult* executionResult) override;
+    ndk::ScopedAStatus executeSynchronouslyWithConfig(
+            const Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
+            const ExecutionConfig& config, int64_t deadlineNs,
+            ExecutionResult* executionResult) override;
+
+    ndk::ScopedAStatus releaseMemoryResource(int64_t memoryIdentifierToken) override;
+
+    class ThreadSafeMemoryCache {
+      public:
+        using Value =
+                std::pair<::android::nn::SharedMemory, ::android::nn::IBurst::OptionalCacheHold>;
+
+        Value add(int64_t token, const ::android::nn::SharedMemory& memory,
+                  const ::android::nn::IBurst& burst) const;
+        void remove(int64_t token) const;
+
+      private:
+        mutable std::mutex mMutex;
+        mutable std::unordered_map<int64_t, Value> mCache GUARDED_BY(mMutex);
+    };
+
+  private:
+    const ::android::nn::SharedBurst kBurst;
+    const ThreadSafeMemoryCache kMemoryCache;
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_BURST_H
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Device.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Device.h
new file mode 100644
index 0000000..c94f270
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Device.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_DEVICE_H
+
+#include "nnapi/hal/aidl/Adapter.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BufferDesc.h>
+#include <aidl/android/hardware/neuralnetworks/BufferRole.h>
+#include <aidl/android/hardware/neuralnetworks/Capabilities.h>
+#include <aidl/android/hardware/neuralnetworks/DeviceBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/DeviceType.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionPreference.h>
+#include <aidl/android/hardware/neuralnetworks/Extension.h>
+#include <aidl/android/hardware/neuralnetworks/IPreparedModelCallback.h>
+#include <aidl/android/hardware/neuralnetworks/IPreparedModelParcel.h>
+#include <aidl/android/hardware/neuralnetworks/Model.h>
+#include <aidl/android/hardware/neuralnetworks/NumberOfCacheFiles.h>
+#include <aidl/android/hardware/neuralnetworks/PrepareModelConfig.h>
+#include <aidl/android/hardware/neuralnetworks/Priority.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IDevice.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+// Class that adapts nn::IDevice to BnDevice.
+class Device : public BnDevice {
+  public:
+    Device(::android::nn::SharedDevice device, Executor executor);
+
+    ndk::ScopedAStatus allocate(const BufferDesc& desc,
+                                const std::vector<IPreparedModelParcel>& preparedModels,
+                                const std::vector<BufferRole>& inputRoles,
+                                const std::vector<BufferRole>& outputRoles,
+                                DeviceBuffer* buffer) override;
+    ndk::ScopedAStatus getCapabilities(Capabilities* capabilities) override;
+    ndk::ScopedAStatus getNumberOfCacheFilesNeeded(NumberOfCacheFiles* numberOfCacheFiles) override;
+    ndk::ScopedAStatus getSupportedExtensions(std::vector<Extension>* extensions) override;
+    ndk::ScopedAStatus getSupportedOperations(const Model& model,
+                                              std::vector<bool>* supported) override;
+    ndk::ScopedAStatus getType(DeviceType* deviceType) override;
+    ndk::ScopedAStatus getVersionString(std::string* version) override;
+    ndk::ScopedAStatus prepareModel(
+            const Model& model, ExecutionPreference preference, Priority priority,
+            int64_t deadlineNs, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+            const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+            const std::vector<uint8_t>& token,
+            const std::shared_ptr<IPreparedModelCallback>& callback) override;
+    ndk::ScopedAStatus prepareModelFromCache(
+            int64_t deadlineNs, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+            const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+            const std::vector<uint8_t>& token,
+            const std::shared_ptr<IPreparedModelCallback>& callback) override;
+    ndk::ScopedAStatus prepareModelWithConfig(
+            const Model& model, const PrepareModelConfig& config,
+            const std::shared_ptr<IPreparedModelCallback>& callback) override;
+
+  protected:
+    const ::android::nn::SharedDevice kDevice;
+    const Executor kExecutor;
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_DEVICE_H
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Execution.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Execution.h
new file mode 100644
index 0000000..6a9ac57
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Execution.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_EXECUTION_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_EXECUTION_H
+
+#include "nnapi/hal/aidl/Adapter.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/FencedExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
+#include <aidl/android/hardware/neuralnetworks/Request.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IExecution.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <vector>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+// Class that adapts nn::IExecution to BnExecution.
+class Execution : public BnExecution {
+  public:
+    explicit Execution(::android::nn::SharedExecution execution);
+
+    ndk::ScopedAStatus executeSynchronously(int64_t deadlineNs,
+                                            ExecutionResult* executionResult) override;
+    ndk::ScopedAStatus executeFenced(const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+                                     int64_t deadlineNs, int64_t durationNs,
+                                     FencedExecutionResult* fencedExecutionResult) override;
+
+  protected:
+    const ::android::nn::SharedExecution kExecution;
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_EXECUTION_H
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/PreparedModel.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/PreparedModel.h
new file mode 100644
index 0000000..d1359d6
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/PreparedModel.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_PREPARED_MDOEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_PREPARED_MDOEL_H
+
+#include "nnapi/hal/aidl/Adapter.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/FencedExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/IBurst.h>
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
+#include <aidl/android/hardware/neuralnetworks/Request.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <vector>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+// Class that adapts nn::IPreparedModel to BnPreparedModel.
+class PreparedModel : public BnPreparedModel {
+  public:
+    explicit PreparedModel(::android::nn::SharedPreparedModel preparedModel);
+
+    ndk::ScopedAStatus executeSynchronously(const Request& request, bool measureTiming,
+                                            int64_t deadlineNs, int64_t loopTimeoutDurationNs,
+                                            ExecutionResult* executionResult) override;
+    ndk::ScopedAStatus executeFenced(const Request& request,
+                                     const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+                                     bool measureTiming, int64_t deadlineNs,
+                                     int64_t loopTimeoutDurationNs, int64_t durationNs,
+                                     FencedExecutionResult* executionResult) override;
+    ndk::ScopedAStatus configureExecutionBurst(std::shared_ptr<IBurst>* burst) override;
+    ndk::ScopedAStatus createReusableExecution(const Request& request,
+                                               const ExecutionConfig& config,
+                                               std::shared_ptr<IExecution>* execution) override;
+    ndk::ScopedAStatus executeSynchronouslyWithConfig(const Request& request,
+                                                      const ExecutionConfig& config,
+                                                      int64_t deadlineNs,
+                                                      ExecutionResult* executionResult) override;
+    ndk::ScopedAStatus executeFencedWithConfig(
+            const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+            const ExecutionConfig& config, int64_t deadlineNs, int64_t durationNs,
+            FencedExecutionResult* executionResult) override;
+
+    ::android::nn::SharedPreparedModel getUnderlyingPreparedModel() const;
+
+  protected:
+    const ::android::nn::SharedPreparedModel kPreparedModel;
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_PREPARED_MDOEL_H
diff --git a/neuralnetworks/utils/adapter/aidl/src/Adapter.cpp b/neuralnetworks/utils/adapter/aidl/src/Adapter.cpp
new file mode 100644
index 0000000..d0b56e8
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/src/Adapter.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Adapter.h"
+
+#include "Device.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <android/binder_interface_utils.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <thread>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+std::shared_ptr<BnDevice> adapt(::android::nn::SharedDevice device, Executor executor) {
+    return ndk::SharedRefBase::make<Device>(std::move(device), std::move(executor));
+}
+
+std::shared_ptr<BnDevice> adapt(::android::nn::SharedDevice device) {
+    Executor defaultExecutor = [](Task task, ::android::nn::OptionalTimePoint /*deadline*/) {
+        std::thread(std::move(task)).detach();
+    };
+    return adapt(std::move(device), std::move(defaultExecutor));
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/aidl/src/Buffer.cpp b/neuralnetworks/utils/adapter/aidl/src/Buffer.cpp
new file mode 100644
index 0000000..c15ab65
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/src/Buffer.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Buffer.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/Memory.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/aidl/Conversions.h>
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+namespace {
+
+template <typename Type>
+auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
+    auto result = nn::convert(object);
+    if (!result.has_value()) {
+        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return result;
+}
+
+nn::GeneralResult<std::vector<uint32_t>> inputToUnsigned(const std::vector<int32_t>& dims) {
+    auto result = nn::toUnsigned(dims);
+    if (!result.has_value()) {
+        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return result;
+}
+
+nn::GeneralResult<void> copyTo(const nn::IBuffer& buffer, const Memory& dst) {
+    const auto nnDst = NN_TRY(convertInput(dst));
+    return buffer.copyTo(nnDst);
+}
+
+nn::GeneralResult<void> copyFrom(const nn::IBuffer& buffer, const Memory& src,
+                                 const std::vector<int32_t>& dimensions) {
+    const auto nnSrc = NN_TRY(convertInput(src));
+    const auto nnDims = NN_TRY(inputToUnsigned(dimensions));
+    return buffer.copyFrom(nnSrc, nnDims);
+}
+
+}  // namespace
+
+Buffer::Buffer(nn::SharedBuffer buffer) : kBuffer(std::move(buffer)) {
+    CHECK(kBuffer != nullptr);
+}
+
+ndk::ScopedAStatus Buffer::copyTo(const Memory& dst) {
+    const auto result = adapter::copyTo(*kBuffer, dst);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Buffer::copyFrom(const Memory& src, const std::vector<int32_t>& dimensions) {
+    const auto result = adapter::copyFrom(*kBuffer, src, dimensions);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/aidl/src/Burst.cpp b/neuralnetworks/utils/adapter/aidl/src/Burst.cpp
new file mode 100644
index 0000000..a4a80fa
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/src/Burst.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Burst.h"
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IBurst.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/aidl/Conversions.h>
+#include <nnapi/hal/aidl/Utils.h>
+
+#include <algorithm>
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <utility>
+#include <variant>
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+namespace {
+
+using Value = Burst::ThreadSafeMemoryCache::Value;
+
+template <typename Type>
+auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
+    auto result = nn::convert(object);
+    if (!result.has_value()) {
+        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return result;
+}
+
+nn::Duration makeDuration(int64_t durationNs) {
+    return nn::Duration(std::chrono::nanoseconds(durationNs));
+}
+
+nn::GeneralResult<nn::OptionalDuration> makeOptionalDuration(int64_t durationNs) {
+    if (durationNs < -1) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid duration " << durationNs;
+    }
+    return durationNs < 0 ? nn::OptionalDuration{} : makeDuration(durationNs);
+}
+
+nn::GeneralResult<nn::OptionalTimePoint> makeOptionalTimePoint(int64_t durationNs) {
+    if (durationNs < -1) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid time point " << durationNs;
+    }
+    return durationNs < 0 ? nn::OptionalTimePoint{} : nn::TimePoint(makeDuration(durationNs));
+}
+
+std::vector<nn::IBurst::OptionalCacheHold> ensureAllMemoriesAreCached(
+        nn::Request* request, const std::vector<int64_t>& memoryIdentifierTokens,
+        const nn::IBurst& burst, const Burst::ThreadSafeMemoryCache& cache) {
+    std::vector<nn::IBurst::OptionalCacheHold> holds;
+    holds.reserve(memoryIdentifierTokens.size());
+
+    for (size_t i = 0; i < memoryIdentifierTokens.size(); ++i) {
+        const auto& pool = request->pools[i];
+        const auto token = memoryIdentifierTokens[i];
+        constexpr int64_t kNoToken = -1;
+        if (token == kNoToken || !std::holds_alternative<nn::SharedMemory>(pool)) {
+            continue;
+        }
+
+        const auto& memory = std::get<nn::SharedMemory>(pool);
+        auto [storedMemory, hold] = cache.add(token, memory, burst);
+
+        request->pools[i] = std::move(storedMemory);
+        holds.push_back(std::move(hold));
+    }
+
+    return holds;
+}
+
+nn::ExecutionResult<ExecutionResult> executeSynchronously(
+        const nn::IBurst& burst, const Burst::ThreadSafeMemoryCache& cache, const Request& request,
+        const std::vector<int64_t>& memoryIdentifierTokens, bool measureTiming, int64_t deadlineNs,
+        int64_t loopTimeoutDurationNs, const std::vector<TokenValuePair>& hints,
+        const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
+    if (request.pools.size() != memoryIdentifierTokens.size()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "request.pools.size() != memoryIdentifierTokens.size()";
+    }
+    if (!std::all_of(memoryIdentifierTokens.begin(), memoryIdentifierTokens.end(),
+                     [](int64_t token) { return token >= -1; })) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid memoryIdentifierTokens";
+    }
+
+    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
+    const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+    const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
+    auto nnHints = NN_TRY(convertInput(hints));
+    auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
+
+    const auto hold = ensureAllMemoriesAreCached(&nnRequest, memoryIdentifierTokens, burst, cache);
+
+    const auto result = burst.execute(nnRequest, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration,
+                                      nnHints, nnExtensionNameToPrefix);
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+        const auto& [message, code, outputShapes] = result.error();
+        return ExecutionResult{.outputSufficientSize = false,
+                               .outputShapes = utils::convert(outputShapes).value(),
+                               .timing = {.timeInDriverNs = -1, .timeOnDeviceNs = -1}};
+    }
+
+    const auto& [outputShapes, timing] = NN_TRY(result);
+    return ExecutionResult{.outputSufficientSize = true,
+                           .outputShapes = utils::convert(outputShapes).value(),
+                           .timing = utils::convert(timing).value()};
+}
+
+}  // namespace
+
+Value Burst::ThreadSafeMemoryCache::add(int64_t token, const nn::SharedMemory& memory,
+                                        const nn::IBurst& burst) const {
+    std::lock_guard guard(mMutex);
+    if (const auto it = mCache.find(token); it != mCache.end()) {
+        return it->second;
+    }
+    auto hold = burst.cacheMemory(memory);
+    auto [it, _] = mCache.emplace(token, std::make_pair(memory, std::move(hold)));
+    return it->second;
+}
+
+void Burst::ThreadSafeMemoryCache::remove(int64_t token) const {
+    std::lock_guard guard(mMutex);
+    mCache.erase(token);
+}
+
+Burst::Burst(nn::SharedBurst burst) : kBurst(std::move(burst)) {
+    CHECK(kBurst != nullptr);
+}
+
+ndk::ScopedAStatus Burst::executeSynchronously(const Request& request,
+                                               const std::vector<int64_t>& memoryIdentifierTokens,
+                                               bool measureTiming, int64_t deadlineNs,
+                                               int64_t loopTimeoutDurationNs,
+                                               ExecutionResult* executionResult) {
+    auto result =
+            adapter::executeSynchronously(*kBurst, kMemoryCache, request, memoryIdentifierTokens,
+                                          measureTiming, deadlineNs, loopTimeoutDurationNs, {}, {});
+    if (!result.has_value()) {
+        auto [message, code, _] = std::move(result).error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Burst::executeSynchronouslyWithConfig(
+        const Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
+        const ExecutionConfig& config, int64_t deadlineNs, ExecutionResult* executionResult) {
+    auto result = adapter::executeSynchronously(
+            *kBurst, kMemoryCache, request, memoryIdentifierTokens, config.measureTiming,
+            deadlineNs, config.loopTimeoutDurationNs, config.executionHints,
+            config.extensionNameToPrefix);
+    if (!result.has_value()) {
+        auto [message, code, _] = std::move(result).error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Burst::releaseMemoryResource(int64_t memoryIdentifierToken) {
+    if (memoryIdentifierToken < -1) {
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(ErrorStatus::INVALID_ARGUMENT),
+                "Invalid memoryIdentifierToken");
+    }
+    kMemoryCache.remove(memoryIdentifierToken);
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/aidl/src/Device.cpp b/neuralnetworks/utils/adapter/aidl/src/Device.cpp
new file mode 100644
index 0000000..84aaddb
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/src/Device.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Device.h"
+
+#include "Adapter.h"
+#include "Buffer.h"
+#include "PreparedModel.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BufferDesc.h>
+#include <aidl/android/hardware/neuralnetworks/BufferRole.h>
+#include <aidl/android/hardware/neuralnetworks/DeviceBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/DeviceType.h>
+#include <aidl/android/hardware/neuralnetworks/ErrorStatus.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionPreference.h>
+#include <aidl/android/hardware/neuralnetworks/Extension.h>
+#include <aidl/android/hardware/neuralnetworks/IPreparedModelCallback.h>
+#include <aidl/android/hardware/neuralnetworks/IPreparedModelParcel.h>
+#include <aidl/android/hardware/neuralnetworks/Model.h>
+#include <aidl/android/hardware/neuralnetworks/NumberOfCacheFiles.h>
+#include <aidl/android/hardware/neuralnetworks/Priority.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/aidl/Conversions.h>
+
+#include <chrono>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+namespace {
+
+template <typename Type>
+auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
+    auto result = nn::convert(object);
+    if (!result.has_value()) {
+        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return result;
+}
+
+nn::Duration makeDuration(int64_t durationNs) {
+    return nn::Duration(std::chrono::nanoseconds(durationNs));
+}
+
+nn::GeneralResult<nn::OptionalTimePoint> makeOptionalTimePoint(int64_t durationNs) {
+    if (durationNs < -1) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid time point " << durationNs;
+    }
+    return durationNs < 0 ? nn::OptionalTimePoint{} : nn::TimePoint(makeDuration(durationNs));
+}
+
+nn::GeneralResult<nn::CacheToken> convertCacheToken(const std::vector<uint8_t>& token) {
+    nn::CacheToken nnToken;
+    if (token.size() != nnToken.size()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid token";
+    }
+    std::copy(token.begin(), token.end(), nnToken.begin());
+    return nnToken;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> downcast(const IPreparedModelParcel& preparedModel) {
+    if (preparedModel.preparedModel == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "preparedModel is nullptr";
+    }
+    if (preparedModel.preparedModel->isRemote()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Cannot convert remote models";
+    }
+
+    // This static_cast is safe because adapter::PreparedModel is the only class that implements
+    // the IPreparedModel interface in the adapter service code.
+    const auto* casted = static_cast<const PreparedModel*>(preparedModel.preparedModel.get());
+    return casted->getUnderlyingPreparedModel();
+}
+
+nn::GeneralResult<std::vector<nn::SharedPreparedModel>> downcastAll(
+        const std::vector<IPreparedModelParcel>& preparedModels) {
+    std::vector<nn::SharedPreparedModel> canonical;
+    canonical.reserve(preparedModels.size());
+    for (const auto& preparedModel : preparedModels) {
+        canonical.push_back(NN_TRY(downcast(preparedModel)));
+    }
+    return canonical;
+}
+
+nn::GeneralResult<DeviceBuffer> allocate(const nn::IDevice& device, const BufferDesc& desc,
+                                         const std::vector<IPreparedModelParcel>& preparedModels,
+                                         const std::vector<BufferRole>& inputRoles,
+                                         const std::vector<BufferRole>& outputRoles) {
+    auto nnDesc = NN_TRY(convertInput(desc));
+    auto nnPreparedModels = NN_TRY(downcastAll(preparedModels));
+    auto nnInputRoles = NN_TRY(convertInput(inputRoles));
+    auto nnOutputRoles = NN_TRY(convertInput(outputRoles));
+
+    auto buffer = NN_TRY(device.allocate(nnDesc, nnPreparedModels, nnInputRoles, nnOutputRoles));
+    CHECK(buffer != nullptr);
+
+    const nn::Request::MemoryDomainToken token = buffer->getToken();
+    auto aidlBuffer = ndk::SharedRefBase::make<Buffer>(std::move(buffer));
+    return DeviceBuffer{.buffer = std::move(aidlBuffer), .token = static_cast<int32_t>(token)};
+}
+
+nn::GeneralResult<std::vector<bool>> getSupportedOperations(const nn::IDevice& device,
+                                                            const Model& model) {
+    const auto nnModel = NN_TRY(convertInput(model));
+    return device.getSupportedOperations(nnModel);
+}
+
+using PrepareModelResult = nn::GeneralResult<nn::SharedPreparedModel>;
+
+std::shared_ptr<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel) {
+    if (preparedModel == nullptr) {
+        return nullptr;
+    }
+    return ndk::SharedRefBase::make<PreparedModel>(std::move(preparedModel));
+}
+
+void notify(IPreparedModelCallback* callback, PrepareModelResult result) {
+    if (!result.has_value()) {
+        const auto& [message, status] = result.error();
+        LOG(ERROR) << message;
+        const auto aidlCode = utils::convert(status).value_or(ErrorStatus::GENERAL_FAILURE);
+        callback->notify(aidlCode, nullptr);
+    } else {
+        auto preparedModel = std::move(result).value();
+        auto aidlPreparedModel = adaptPreparedModel(std::move(preparedModel));
+        callback->notify(ErrorStatus::NONE, std::move(aidlPreparedModel));
+    }
+}
+
+nn::GeneralResult<void> prepareModel(
+        const nn::SharedDevice& device, const Executor& executor, const Model& model,
+        ExecutionPreference preference, Priority priority, int64_t deadlineNs,
+        const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+        const std::vector<ndk::ScopedFileDescriptor>& dataCache, const std::vector<uint8_t>& token,
+        const std::vector<TokenValuePair>& hints,
+        const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix,
+        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnModel = NN_TRY(convertInput(model));
+    const auto nnPreference = NN_TRY(convertInput(preference));
+    const auto nnPriority = NN_TRY(convertInput(priority));
+    const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+    auto nnModelCache = NN_TRY(convertInput(modelCache));
+    auto nnDataCache = NN_TRY(convertInput(dataCache));
+    const auto nnToken = NN_TRY(convertCacheToken(token));
+    auto nnHints = NN_TRY(convertInput(hints));
+    auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
+
+    Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
+                 nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
+                 nnToken, nnHints = std::move(nnHints),
+                 nnExtensionNameToPrefix = std::move(nnExtensionNameToPrefix), callback] {
+        auto result =
+                device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline, nnModelCache,
+                                     nnDataCache, nnToken, nnHints, nnExtensionNameToPrefix);
+        notify(callback.get(), std::move(result));
+    };
+    executor(std::move(task), nnDeadline);
+
+    return {};
+}
+
+nn::GeneralResult<void> prepareModelFromCache(
+        const nn::SharedDevice& device, const Executor& executor, int64_t deadlineNs,
+        const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+        const std::vector<ndk::ScopedFileDescriptor>& dataCache, const std::vector<uint8_t>& token,
+        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+    auto nnModelCache = NN_TRY(convertInput(modelCache));
+    auto nnDataCache = NN_TRY(convertInput(dataCache));
+    const auto nnToken = NN_TRY(convertCacheToken(token));
+
+    auto task = [device, nnDeadline, nnModelCache = std::move(nnModelCache),
+                 nnDataCache = std::move(nnDataCache), nnToken, callback] {
+        auto result = device->prepareModelFromCache(nnDeadline, nnModelCache, nnDataCache, nnToken);
+        notify(callback.get(), std::move(result));
+    };
+    executor(std::move(task), nnDeadline);
+
+    return {};
+}
+
+}  // namespace
+
+Device::Device(::android::nn::SharedDevice device, Executor executor)
+    : kDevice(std::move(device)), kExecutor(std::move(executor)) {
+    CHECK(kDevice != nullptr);
+    CHECK(kExecutor != nullptr);
+}
+
+ndk::ScopedAStatus Device::allocate(const BufferDesc& desc,
+                                    const std::vector<IPreparedModelParcel>& preparedModels,
+                                    const std::vector<BufferRole>& inputRoles,
+                                    const std::vector<BufferRole>& outputRoles,
+                                    DeviceBuffer* buffer) {
+    auto result = adapter::allocate(*kDevice, desc, preparedModels, inputRoles, outputRoles);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *buffer = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::getCapabilities(Capabilities* capabilities) {
+    *capabilities = utils::convert(kDevice->getCapabilities()).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::getNumberOfCacheFilesNeeded(NumberOfCacheFiles* numberOfCacheFiles) {
+    const auto [numModelCache, numDataCache] = kDevice->getNumberOfCacheFilesNeeded();
+    *numberOfCacheFiles = NumberOfCacheFiles{.numModelCache = static_cast<int32_t>(numModelCache),
+                                             .numDataCache = static_cast<int32_t>(numDataCache)};
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::getSupportedExtensions(std::vector<Extension>* extensions) {
+    *extensions = utils::convert(kDevice->getSupportedExtensions()).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::getSupportedOperations(const Model& model,
+                                                  std::vector<bool>* supported) {
+    auto result = adapter::getSupportedOperations(*kDevice, model);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *supported = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::getType(DeviceType* deviceType) {
+    *deviceType = utils::convert(kDevice->getType()).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::getVersionString(std::string* version) {
+    *version = kDevice->getVersionString();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::prepareModel(const Model& model, ExecutionPreference preference,
+                                        Priority priority, int64_t deadlineNs,
+                                        const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+                                        const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+                                        const std::vector<uint8_t>& token,
+                                        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    const auto result =
+            adapter::prepareModel(kDevice, kExecutor, model, preference, priority, deadlineNs,
+                                  modelCache, dataCache, token, {}, {}, callback);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        callback->notify(aidlCode, nullptr);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::prepareModelFromCache(
+        int64_t deadlineNs, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+        const std::vector<ndk::ScopedFileDescriptor>& dataCache, const std::vector<uint8_t>& token,
+        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    const auto result = adapter::prepareModelFromCache(kDevice, kExecutor, deadlineNs, modelCache,
+                                                       dataCache, token, callback);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        callback->notify(aidlCode, nullptr);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Device::prepareModelWithConfig(
+        const Model& model, const PrepareModelConfig& config,
+        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    const auto result = adapter::prepareModel(
+            kDevice, kExecutor, model, config.preference, config.priority, config.deadlineNs,
+            config.modelCache, config.dataCache, config.cacheToken, config.compilationHints,
+            config.extensionNameToPrefix, callback);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        callback->notify(aidlCode, nullptr);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/aidl/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/aidl/src/PreparedModel.cpp
new file mode 100644
index 0000000..790558f
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/src/PreparedModel.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PreparedModel.h"
+
+#include "Burst.h"
+#include "Execution.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnFencedExecutionCallback.h>
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/FencedExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/IBurst.h>
+#include <aidl/android/hardware/neuralnetworks/Request.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IExecution.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/aidl/Conversions.h>
+#include <nnapi/hal/aidl/Utils.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+namespace {
+
+class FencedExecutionCallback : public BnFencedExecutionCallback {
+  public:
+    FencedExecutionCallback(nn::ExecuteFencedInfoCallback callback)
+        : kCallback(std::move(callback)) {}
+
+    ndk::ScopedAStatus getExecutionInfo(Timing* timingLaunched, Timing* timingFenced,
+                                        ErrorStatus* errorStatus) override {
+        const auto result = kCallback();
+        if (result.ok()) {
+            const auto& [nnTimingLaunched, nnTimingFenced] = result.value();
+            *timingLaunched = utils::convert(nnTimingLaunched).value();
+            *timingFenced = utils::convert(nnTimingFenced).value();
+            *errorStatus = ErrorStatus::NONE;
+        } else {
+            constexpr auto kNoTiming = Timing{.timeOnDeviceNs = -1, .timeInDriverNs = -1};
+            const auto& [message, code] = result.error();
+            LOG(ERROR) << "getExecutionInfo failed with " << code << ": " << message;
+            const auto aidlStatus = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+            *timingLaunched = kNoTiming;
+            *timingFenced = kNoTiming;
+            *errorStatus = aidlStatus;
+        }
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    const nn::ExecuteFencedInfoCallback kCallback;
+};
+
+template <typename Type>
+auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
+    auto result = nn::convert(object);
+    if (!result.has_value()) {
+        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return result;
+}
+
+nn::GeneralResult<std::vector<nn::SyncFence>> convertSyncFences(
+        const std::vector<ndk::ScopedFileDescriptor>& waitFor) {
+    auto handles = NN_TRY(convertInput(waitFor));
+
+    constexpr auto valid = [](const nn::SharedHandle& handle) {
+        return handle != nullptr && handle->ok();
+    };
+    if (!std::all_of(handles.begin(), handles.end(), valid)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid sync fence";
+    }
+
+    std::vector<nn::SyncFence> syncFences;
+    syncFences.reserve(waitFor.size());
+    for (auto& handle : handles) {
+        syncFences.push_back(nn::SyncFence::create(std::move(handle)).value());
+    }
+    return syncFences;
+}
+
+nn::Duration makeDuration(int64_t durationNs) {
+    return nn::Duration(std::chrono::nanoseconds(durationNs));
+}
+
+nn::GeneralResult<nn::OptionalDuration> makeOptionalDuration(int64_t durationNs) {
+    if (durationNs < -1) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid duration " << durationNs;
+    }
+    return durationNs < 0 ? nn::OptionalDuration{} : makeDuration(durationNs);
+}
+
+nn::GeneralResult<nn::OptionalTimePoint> makeOptionalTimePoint(int64_t durationNs) {
+    if (durationNs < -1) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid time point " << durationNs;
+    }
+    return durationNs < 0 ? nn::OptionalTimePoint{} : nn::TimePoint(makeDuration(durationNs));
+}
+
+nn::ExecutionResult<ExecutionResult> executeSynchronously(
+        const nn::IPreparedModel& preparedModel, const Request& request, bool measureTiming,
+        int64_t deadlineNs, int64_t loopTimeoutDurationNs, const std::vector<TokenValuePair>& hints,
+        const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
+    const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+    const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
+    auto nnHints = NN_TRY(convertInput(hints));
+    auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
+
+    const auto result =
+            preparedModel.execute(nnRequest, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration,
+                                  nnHints, nnExtensionNameToPrefix);
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+        const auto& [message, code, outputShapes] = result.error();
+        LOG(ERROR) << "executeSynchronously failed with " << code << ": " << message;
+        return ExecutionResult{.outputSufficientSize = false,
+                               .outputShapes = utils::convert(outputShapes).value(),
+                               .timing = {.timeInDriverNs = -1, .timeOnDeviceNs = -1}};
+    }
+
+    const auto& [outputShapes, timing] = NN_TRY(result);
+    return ExecutionResult{.outputSufficientSize = true,
+                           .outputShapes = utils::convert(outputShapes).value(),
+                           .timing = utils::convert(timing).value()};
+}
+
+nn::GeneralResult<FencedExecutionResult> executeFenced(
+        const nn::IPreparedModel& preparedModel, const Request& request,
+        const std::vector<ndk::ScopedFileDescriptor>& waitFor, bool measureTiming,
+        int64_t deadlineNs, int64_t loopTimeoutDurationNs, int64_t durationNs,
+        const std::vector<TokenValuePair>& hints,
+        const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnWaitFor = NN_TRY(convertSyncFences(waitFor));
+    const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
+    const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+    const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
+    const auto nnDuration = NN_TRY(makeOptionalDuration(durationNs));
+    auto nnHints = NN_TRY(convertInput(hints));
+    auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
+
+    auto [syncFence, executeFencedInfoCallback] = NN_TRY(preparedModel.executeFenced(
+            nnRequest, nnWaitFor, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration, nnDuration,
+            nnHints, nnExtensionNameToPrefix));
+
+    ndk::ScopedFileDescriptor fileDescriptor;
+    if (syncFence.hasFd()) {
+        auto uniqueFd = NN_TRY(nn::dupFd(syncFence.getFd()));
+        fileDescriptor = ndk::ScopedFileDescriptor(uniqueFd.release());
+    }
+
+    return FencedExecutionResult{.callback = ndk::SharedRefBase::make<FencedExecutionCallback>(
+                                         std::move(executeFencedInfoCallback)),
+                                 .syncFence = std::move(fileDescriptor)};
+}
+
+nn::GeneralResult<nn::SharedExecution> createReusableExecution(
+        const nn::IPreparedModel& preparedModel, const Request& request, bool measureTiming,
+        int64_t loopTimeoutDurationNs, const std::vector<TokenValuePair>& hints,
+        const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
+    const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
+    auto nnHints = NN_TRY(convertInput(hints));
+    auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
+
+    return preparedModel.createReusableExecution(nnRequest, nnMeasureTiming, nnLoopTimeoutDuration,
+                                                 nnHints, nnExtensionNameToPrefix);
+}
+
+nn::ExecutionResult<ExecutionResult> executeSynchronously(const nn::IExecution& execution,
+                                                          int64_t deadlineNs) {
+    const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+
+    const auto result = execution.compute(nnDeadline);
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+        const auto& [message, code, outputShapes] = result.error();
+        LOG(ERROR) << "executeSynchronously failed with " << code << ": " << message;
+        return ExecutionResult{.outputSufficientSize = false,
+                               .outputShapes = utils::convert(outputShapes).value(),
+                               .timing = {.timeInDriverNs = -1, .timeOnDeviceNs = -1}};
+    }
+
+    const auto& [outputShapes, timing] = NN_TRY(result);
+    return ExecutionResult{.outputSufficientSize = true,
+                           .outputShapes = utils::convert(outputShapes).value(),
+                           .timing = utils::convert(timing).value()};
+}
+
+nn::GeneralResult<FencedExecutionResult> executeFenced(
+        const nn::IExecution& execution, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+        int64_t deadlineNs, int64_t durationNs) {
+    const auto nnWaitFor = NN_TRY(convertSyncFences(waitFor));
+    const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+    const auto nnDuration = NN_TRY(makeOptionalDuration(durationNs));
+
+    auto [syncFence, executeFencedInfoCallback] =
+            NN_TRY(execution.computeFenced(nnWaitFor, nnDeadline, nnDuration));
+
+    ndk::ScopedFileDescriptor fileDescriptor;
+    if (syncFence.hasFd()) {
+        auto uniqueFd = NN_TRY(nn::dupFd(syncFence.getFd()));
+        fileDescriptor = ndk::ScopedFileDescriptor(uniqueFd.release());
+    }
+
+    return FencedExecutionResult{.callback = ndk::SharedRefBase::make<FencedExecutionCallback>(
+                                         std::move(executeFencedInfoCallback)),
+                                 .syncFence = std::move(fileDescriptor)};
+}
+
+}  // namespace
+
+PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel)
+    : kPreparedModel(std::move(preparedModel)) {
+    CHECK(kPreparedModel != nullptr);
+}
+
+ndk::ScopedAStatus PreparedModel::executeSynchronously(const Request& request, bool measureTiming,
+                                                       int64_t deadlineNs,
+                                                       int64_t loopTimeoutDurationNs,
+                                                       ExecutionResult* executionResult) {
+    auto result = adapter::executeSynchronously(*kPreparedModel, request, measureTiming, deadlineNs,
+                                                loopTimeoutDurationNs, {}, {});
+    if (!result.has_value()) {
+        const auto& [message, code, _] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PreparedModel::executeFenced(
+        const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+        bool measureTiming, int64_t deadlineNs, int64_t loopTimeoutDurationNs, int64_t durationNs,
+        FencedExecutionResult* executionResult) {
+    auto result = adapter::executeFenced(*kPreparedModel, request, waitFor, measureTiming,
+                                         deadlineNs, loopTimeoutDurationNs, durationNs, {}, {});
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PreparedModel::executeSynchronouslyWithConfig(const Request& request,
+                                                                 const ExecutionConfig& config,
+                                                                 int64_t deadlineNs,
+                                                                 ExecutionResult* executionResult) {
+    auto result = adapter::executeSynchronously(
+            *kPreparedModel, request, config.measureTiming, deadlineNs,
+            config.loopTimeoutDurationNs, config.executionHints, config.extensionNameToPrefix);
+    if (!result.has_value()) {
+        const auto& [message, code, _] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PreparedModel::executeFencedWithConfig(
+        const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+        const ExecutionConfig& config, int64_t deadlineNs, int64_t durationNs,
+        FencedExecutionResult* executionResult) {
+    auto result = adapter::executeFenced(*kPreparedModel, request, waitFor, config.measureTiming,
+                                         deadlineNs, config.loopTimeoutDurationNs, durationNs,
+                                         config.executionHints, config.extensionNameToPrefix);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PreparedModel::configureExecutionBurst(std::shared_ptr<IBurst>* burst) {
+    auto result = kPreparedModel->configureExecutionBurst();
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *burst = ndk::SharedRefBase::make<Burst>(std::move(result).value());
+    return ndk::ScopedAStatus::ok();
+}
+
+nn::SharedPreparedModel PreparedModel::getUnderlyingPreparedModel() const {
+    return kPreparedModel;
+}
+
+ndk::ScopedAStatus PreparedModel::createReusableExecution(const Request& request,
+                                                          const ExecutionConfig& config,
+                                                          std::shared_ptr<IExecution>* execution) {
+    auto result = adapter::createReusableExecution(
+            *kPreparedModel, request, config.measureTiming, config.loopTimeoutDurationNs,
+            config.executionHints, config.extensionNameToPrefix);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *execution = ndk::SharedRefBase::make<Execution>(std::move(result).value());
+    return ndk::ScopedAStatus::ok();
+}
+
+Execution::Execution(nn::SharedExecution execution) : kExecution(std::move(execution)) {
+    CHECK(kExecution != nullptr);
+}
+
+ndk::ScopedAStatus Execution::executeSynchronously(int64_t deadlineNs,
+                                                   ExecutionResult* executionResult) {
+    auto result = adapter::executeSynchronously(*kExecution, deadlineNs);
+    if (!result.has_value()) {
+        const auto& [message, code, _] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Execution::executeFenced(const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+                                            int64_t deadlineNs, int64_t durationNs,
+                                            FencedExecutionResult* executionResult) {
+    auto result = adapter::executeFenced(*kExecution, waitFor, deadlineNs, durationNs);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                static_cast<int32_t>(aidlCode), message.c_str());
+    }
+    *executionResult = std::move(result).value();
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/hidl/Android.bp b/neuralnetworks/utils/adapter/hidl/Android.bp
new file mode 100644
index 0000000..6875daa
--- /dev/null
+++ b/neuralnetworks/utils/adapter/hidl/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_adapter",
+    defaults: ["neuralnetworks_utils_defaults"],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal"],
+    export_include_dirs: ["include"],
+    static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hardware.neuralnetworks@1.3",
+        "libfmq",
+        "neuralnetworks_types",
+        "neuralnetworks_utils_hal_1_0",
+        "neuralnetworks_utils_hal_1_1",
+        "neuralnetworks_utils_hal_1_2",
+        "neuralnetworks_utils_hal_1_3",
+        "neuralnetworks_utils_hal_common",
+    ],
+}
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
new file mode 100644
index 0000000..6fba4ab
--- /dev/null
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_ADAPTER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_ADAPTER_H
+
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/Types.h>
+#include <functional>
+#include <memory>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
+// lifetimes across processes and for protecting asynchronous calls across HIDL.
+
+namespace android::hardware::neuralnetworks::adapter {
+
+/**
+ * A self-contained unit of work to be executed.
+ */
+using Task = std::function<void()>;
+
+/**
+ * A type-erased executor which executes a task asynchronously.
+ *
+ * This executor is also provided an optional deadline for when the caller expects is the upper
+ * bound for the amount of time to complete the task. If needed, the Executor can retrieve the
+ * Application ID (Android User ID) by calling IPCThreadState::self()->getCallingUid() in
+ * hwbinder/IPCThreadState.h.
+ */
+using Executor = std::function<void(Task, nn::OptionalTimePoint)>;
+
+/**
+ * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
+ *
+ * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
+ * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
+ *
+ * @param device NNAPI canonical IDevice interface object to be adapted.
+ * @param executor Type-erased executor to handle executing tasks asynchronously.
+ * @return HIDL NN HAL IDevice interface object.
+ */
+sp<V1_3::IDevice> adapt(nn::SharedDevice device, Executor executor);
+
+/**
+ * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
+ *
+ * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
+ * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
+ *
+ * This function uses a default executor, which will execute tasks from a detached thread.
+ *
+ * @param device NNAPI canonical IDevice interface object to be adapted.
+ * @return HIDL NN HAL IDevice interface object.
+ */
+sp<V1_3::IDevice> adapt(nn::SharedDevice device);
+
+}  // namespace android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_ADAPTER_H
diff --git a/neuralnetworks/utils/adapter/include/nnapi/hal/Buffer.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Buffer.h
similarity index 100%
rename from neuralnetworks/utils/adapter/include/nnapi/hal/Buffer.h
rename to neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Buffer.h
diff --git a/neuralnetworks/utils/adapter/include/nnapi/hal/Burst.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Burst.h
similarity index 100%
rename from neuralnetworks/utils/adapter/include/nnapi/hal/Burst.h
rename to neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Burst.h
diff --git a/neuralnetworks/utils/adapter/include/nnapi/hal/Device.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Device.h
similarity index 100%
rename from neuralnetworks/utils/adapter/include/nnapi/hal/Device.h
rename to neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Device.h
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
new file mode 100644
index 0000000..9482b0d
--- /dev/null
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_PREPARED_MODEL_H
+
+#include "nnapi/hal/Adapter.h"
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IBurstCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Types.h>
+#include <memory>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
+// lifetimes across processes and for protecting asynchronous calls across HIDL.
+
+namespace android::hardware::neuralnetworks::adapter {
+
+// Class that adapts nn::IPreparedModel to V1_3::IPreparedModel.
+class PreparedModel final : public V1_3::IPreparedModel {
+  public:
+    PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor);
+
+    Return<V1_0::ErrorStatus> execute(const V1_0::Request& request,
+                                      const sp<V1_0::IExecutionCallback>& callback) override;
+    Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request& request, V1_2::MeasureTiming measure,
+                                          const sp<V1_2::IExecutionCallback>& callback) override;
+    Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request& request, V1_2::MeasureTiming measure,
+                                          const V1_3::OptionalTimePoint& deadline,
+                                          const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
+                                          const sp<V1_3::IExecutionCallback>& callback) override;
+    Return<void> executeSynchronously(const V1_0::Request& request, V1_2::MeasureTiming measure,
+                                      executeSynchronously_cb cb) override;
+    Return<void> executeSynchronously_1_3(const V1_3::Request& request, V1_2::MeasureTiming measure,
+                                          const V1_3::OptionalTimePoint& deadline,
+                                          const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
+                                          executeSynchronously_1_3_cb cb) override;
+    Return<void> configureExecutionBurst(
+            const sp<V1_2::IBurstCallback>& callback,
+            const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
+            const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
+            configureExecutionBurst_cb cb) override;
+    Return<void> executeFenced(const V1_3::Request& request, const hidl_vec<hidl_handle>& waitFor,
+                               V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& deadline,
+                               const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
+                               const V1_3::OptionalTimeoutDuration& duration,
+                               executeFenced_cb callback) override;
+
+    nn::SharedPreparedModel getUnderlyingPreparedModel() const;
+
+  private:
+    const nn::SharedPreparedModel kPreparedModel;
+    const Executor kExecutor;
+};
+
+}  // namespace android::hardware::neuralnetworks::adapter
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_PREPARED_MODEL_H
diff --git a/neuralnetworks/utils/adapter/hidl/src/Adapter.cpp b/neuralnetworks/utils/adapter/hidl/src/Adapter.cpp
new file mode 100644
index 0000000..782e815
--- /dev/null
+++ b/neuralnetworks/utils/adapter/hidl/src/Adapter.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Adapter.h"
+
+#include "Device.h"
+
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <thread>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
+// lifetimes across processes and for protecting asynchronous calls across HIDL.
+
+namespace android::hardware::neuralnetworks::adapter {
+
+sp<V1_3::IDevice> adapt(nn::SharedDevice device, Executor executor) {
+    return sp<Device>::make(std::move(device), std::move(executor));
+}
+
+sp<V1_3::IDevice> adapt(nn::SharedDevice device) {
+    Executor defaultExecutor = [](Task task, nn::OptionalTimePoint /*deadline*/) {
+        std::thread(std::move(task)).detach();
+    };
+    return adapt(std::move(device), std::move(defaultExecutor));
+}
+
+}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/src/Buffer.cpp b/neuralnetworks/utils/adapter/hidl/src/Buffer.cpp
similarity index 100%
rename from neuralnetworks/utils/adapter/src/Buffer.cpp
rename to neuralnetworks/utils/adapter/hidl/src/Buffer.cpp
diff --git a/neuralnetworks/utils/adapter/hidl/src/Burst.cpp b/neuralnetworks/utils/adapter/hidl/src/Burst.cpp
new file mode 100644
index 0000000..e3b165b
--- /dev/null
+++ b/neuralnetworks/utils/adapter/hidl/src/Burst.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Burst.h"
+
+#include <android-base/logging.h>
+#include <nnapi/IBurst.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.0/HandleError.h>
+#include <nnapi/hal/1.0/ProtectCallback.h>
+#include <nnapi/hal/1.2/BurstUtils.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/TransferValue.h>
+
+#include <algorithm>
+#include <cstring>
+#include <limits>
+#include <map>
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "Tracing.h"
+
+namespace android::hardware::neuralnetworks::adapter {
+namespace {
+
+constexpr V1_2::Timing kTiming = {std::numeric_limits<uint64_t>::max(),
+                                  std::numeric_limits<uint64_t>::max()};
+
+nn::GeneralResult<std::vector<nn::SharedMemory>> getMemoriesCallback(
+        V1_0::ErrorStatus status, const hidl_vec<hidl_memory>& memories) {
+    HANDLE_STATUS_HIDL(status) << "getting burst memories failed with " << toString(status);
+    std::vector<nn::SharedMemory> canonicalMemories;
+    canonicalMemories.reserve(memories.size());
+    for (const auto& memory : memories) {
+        canonicalMemories.push_back(NN_TRY(nn::convert(memory)));
+    }
+    return canonicalMemories;
+}
+
+}  // anonymous namespace
+
+Burst::MemoryCache::MemoryCache(nn::SharedBurst burstExecutor,
+                                sp<V1_2::IBurstCallback> burstCallback)
+    : kBurstExecutor(std::move(burstExecutor)), kBurstCallback(std::move(burstCallback)) {
+    CHECK(kBurstExecutor != nullptr);
+    CHECK(kBurstCallback != nullptr);
+}
+
+nn::GeneralResult<std::vector<std::pair<nn::SharedMemory, nn::IBurst::OptionalCacheHold>>>
+Burst::MemoryCache::getCacheEntries(const std::vector<int32_t>& slots) {
+    std::lock_guard guard(mMutex);
+    NN_TRY(ensureCacheEntriesArePresentLocked(slots));
+
+    std::vector<std::pair<nn::SharedMemory, nn::IBurst::OptionalCacheHold>> results;
+    results.reserve(slots.size());
+    for (int32_t slot : slots) {
+        results.push_back(NN_TRY(getCacheEntryLocked(slot)));
+    }
+
+    return results;
+}
+
+nn::GeneralResult<void> Burst::MemoryCache::ensureCacheEntriesArePresentLocked(
+        const std::vector<int32_t>& slots) {
+    const auto slotIsKnown = [this](int32_t slot)
+                                     REQUIRES(mMutex) { return mCache.count(slot) > 0; };
+
+    // find unique unknown slots
+    std::vector<int32_t> unknownSlots = slots;
+    std::sort(unknownSlots.begin(), unknownSlots.end());
+    auto unknownSlotsEnd = std::unique(unknownSlots.begin(), unknownSlots.end());
+    unknownSlotsEnd = std::remove_if(unknownSlots.begin(), unknownSlotsEnd, slotIsKnown);
+    unknownSlots.erase(unknownSlotsEnd, unknownSlots.end());
+
+    // quick-exit if all slots are known
+    if (unknownSlots.empty()) {
+        return {};
+    }
+
+    auto cb = neuralnetworks::utils::CallbackValue(getMemoriesCallback);
+
+    const auto ret = kBurstCallback->getMemories(unknownSlots, cb);
+    HANDLE_TRANSPORT_FAILURE(ret);
+
+    auto returnedMemories = NN_TRY(cb.take());
+
+    if (returnedMemories.size() != unknownSlots.size()) {
+        return NN_ERROR() << "Burst::MemoryCache::ensureCacheEntriesArePresentLocked: Error "
+                             "retrieving memories -- count mismatch between requested memories ("
+                          << unknownSlots.size() << ") and returned memories ("
+                          << returnedMemories.size() << ")";
+    }
+
+    // add memories to unknown slots
+    for (size_t i = 0; i < unknownSlots.size(); ++i) {
+        addCacheEntryLocked(unknownSlots[i], std::move(returnedMemories[i]));
+    }
+
+    return {};
+}
+
+nn::GeneralResult<std::pair<nn::SharedMemory, nn::IBurst::OptionalCacheHold>>
+Burst::MemoryCache::getCacheEntryLocked(int32_t slot) {
+    if (const auto iter = mCache.find(slot); iter != mCache.end()) {
+        return iter->second;
+    }
+    return NN_ERROR() << "Burst::MemoryCache::getCacheEntryLocked failed because slot " << slot
+                      << " is not present in the cache";
+}
+
+void Burst::MemoryCache::addCacheEntryLocked(int32_t slot, nn::SharedMemory memory) {
+    auto hold = kBurstExecutor->cacheMemory(memory);
+    mCache.emplace(slot, std::make_pair(std::move(memory), std::move(hold)));
+}
+
+void Burst::MemoryCache::removeCacheEntry(int32_t slot) {
+    std::lock_guard guard(mMutex);
+    mCache.erase(slot);
+}
+
+// Burst methods
+
+nn::GeneralResult<sp<Burst>> Burst::create(
+        const sp<V1_2::IBurstCallback>& callback,
+        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
+        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, nn::SharedBurst burstExecutor,
+        std::chrono::microseconds pollingTimeWindow) {
+    // check inputs
+    if (callback == nullptr || burstExecutor == nullptr) {
+        return NN_ERROR() << "Burst::create passed a nullptr";
+    }
+
+    // create FMQ objects
+    auto requestChannelReceiver =
+            NN_TRY(V1_2::utils::RequestChannelReceiver::create(requestChannel, pollingTimeWindow));
+    auto resultChannelSender = NN_TRY(V1_2::utils::ResultChannelSender::create(resultChannel));
+
+    // check FMQ objects
+    CHECK(requestChannelReceiver != nullptr);
+    CHECK(resultChannelSender != nullptr);
+
+    // make and return context
+    return sp<Burst>::make(PrivateConstructorTag{}, callback, std::move(requestChannelReceiver),
+                           std::move(resultChannelSender), std::move(burstExecutor));
+}
+
+Burst::Burst(PrivateConstructorTag /*tag*/, const sp<V1_2::IBurstCallback>& callback,
+             std::unique_ptr<V1_2::utils::RequestChannelReceiver> requestChannel,
+             std::unique_ptr<V1_2::utils::ResultChannelSender> resultChannel,
+             nn::SharedBurst burstExecutor)
+    : mCallback(callback),
+      mRequestChannelReceiver(std::move(requestChannel)),
+      mResultChannelSender(std::move(resultChannel)),
+      mBurstExecutor(std::move(burstExecutor)),
+      mMemoryCache(mBurstExecutor, mCallback) {
+    // TODO: highly document the threading behavior of this class
+    mWorker = std::thread([this] { task(); });
+}
+
+Burst::~Burst() {
+    // set teardown flag
+    mTeardown = true;
+    mRequestChannelReceiver->invalidate();
+
+    // wait for task thread to end
+    mWorker.join();
+}
+
+Return<void> Burst::freeMemory(int32_t slot) {
+    mMemoryCache.removeCacheEntry(slot);
+    return Void();
+}
+
+void Burst::task() {
+    // loop until the burst object is being destroyed
+    while (!mTeardown) {
+        // receive request
+        auto arguments = mRequestChannelReceiver->getBlocking();
+
+        // if the request packet was not properly received, return a generic error and skip the
+        // execution
+        //
+        // if the burst is being torn down, skip the execution so the "task" function can end
+        if (!arguments.has_value()) {
+            if (!mTeardown) {
+                mResultChannelSender->send(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kTiming);
+            }
+            continue;
+        }
+
+        // unpack the arguments; types are Request, std::vector<int32_t>, and V1_2::MeasureTiming,
+        // respectively
+        const auto [requestWithoutPools, slotsOfPools, measure] = std::move(arguments).value();
+
+        auto result = execute(requestWithoutPools, slotsOfPools, measure);
+
+        // return result
+        if (result.has_value()) {
+            const auto& [outputShapes, timing] = result.value();
+            mResultChannelSender->send(V1_0::ErrorStatus::NONE, outputShapes, timing);
+        } else {
+            const auto& [message, code, outputShapes] = result.error();
+            LOG(ERROR) << "IBurst::execute failed with " << code << ": " << message;
+            mResultChannelSender->send(V1_2::utils::convert(code).value(),
+                                       V1_2::utils::convert(outputShapes).value(), kTiming);
+        }
+    }
+}
+
+nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> Burst::execute(
+        const V1_0::Request& requestWithoutPools, const std::vector<int32_t>& slotsOfPools,
+        V1_2::MeasureTiming measure) {
+    NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_EXECUTION,
+                 "Burst getting memory, executing, and returning results");
+
+    // ensure executor with cache has required memory
+    const auto cacheEntries = NN_TRY(mMemoryCache.getCacheEntries(slotsOfPools));
+
+    // convert request, populating its pools
+    // This code performs an unvalidated convert because the request object without its pools is
+    // invalid because it is incomplete. Instead, the validation is performed after the memory pools
+    // have been added to the request.
+    auto canonicalRequest = NN_TRY(nn::unvalidatedConvert(requestWithoutPools));
+    CHECK(canonicalRequest.pools.empty());
+    std::transform(cacheEntries.begin(), cacheEntries.end(),
+                   std::back_inserter(canonicalRequest.pools),
+                   [](const auto& cacheEntry) { return cacheEntry.first; });
+    NN_TRY(validate(canonicalRequest));
+
+    nn::MeasureTiming canonicalMeasure = NN_TRY(nn::convert(measure));
+
+    const auto [outputShapes, timing] =
+            NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure, {}, {}, {}, {}));
+
+    return std::make_pair(NN_TRY(V1_2::utils::convert(outputShapes)),
+                          NN_TRY(V1_2::utils::convert(timing)));
+}
+
+}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/hidl/src/Device.cpp b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
new file mode 100644
index 0000000..0f44638
--- /dev/null
+++ b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Device.h"
+
+#include "Buffer.h"
+#include "PreparedModel.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.0/Utils.h>
+#include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/1.1/Utils.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/1.2/Utils.h>
+#include <nnapi/hal/1.3/Conversions.h>
+#include <nnapi/hal/1.3/Utils.h>
+
+#include <memory>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
+// lifetimes across processes and for protecting asynchronous calls across HIDL.
+
+namespace android::hardware::neuralnetworks::adapter {
+namespace {
+
+template <typename Type>
+auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
+    auto result = nn::convert(object);
+    if (!result.has_value()) {
+        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return result;
+}
+
+using PrepareModelResult = nn::GeneralResult<nn::SharedPreparedModel>;
+
+sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel, Executor executor) {
+    if (preparedModel == nullptr) {
+        return nullptr;
+    }
+    return sp<PreparedModel>::make(std::move(preparedModel), std::move(executor));
+}
+
+void notify(V1_0::IPreparedModelCallback* callback, nn::ErrorStatus status,
+            const sp<PreparedModel>& hidlPreparedModel) {
+    if (callback != nullptr) {
+        const auto hidlStatus = V1_0::utils::convert(status).value();
+        const auto ret = callback->notify(hidlStatus, hidlPreparedModel);
+        if (!ret.isOk()) {
+            LOG(ERROR) << "V1_0::IPreparedModelCallback::notify failed with " << ret.description();
+        }
+    }
+}
+
+void notify(V1_2::IPreparedModelCallback* callback, nn::ErrorStatus status,
+            const sp<PreparedModel>& hidlPreparedModel) {
+    if (callback != nullptr) {
+        const auto hidlStatus = V1_2::utils::convert(status).value();
+        const auto ret = callback->notify_1_2(hidlStatus, hidlPreparedModel);
+        if (!ret.isOk()) {
+            LOG(ERROR) << "V1_2::IPreparedModelCallback::notify_1_2 failed with "
+                       << ret.description();
+        }
+    }
+}
+
+void notify(V1_3::IPreparedModelCallback* callback, nn::ErrorStatus status,
+            const sp<PreparedModel>& hidlPreparedModel) {
+    if (callback != nullptr) {
+        const auto hidlStatus = V1_3::utils::convert(status).value();
+        const auto ret = callback->notify_1_3(hidlStatus, hidlPreparedModel);
+        if (!ret.isOk()) {
+            LOG(ERROR) << "V1_3::IPreparedModelCallback::notify_1_3 failed with "
+                       << ret.description();
+        }
+    }
+}
+
+template <typename CallbackType>
+void notify(CallbackType* callback, PrepareModelResult result, Executor executor) {
+    if (!result.has_value()) {
+        const auto [message, status] = std::move(result).error();
+        LOG(ERROR) << message;
+        notify(callback, status, nullptr);
+    } else {
+        auto preparedModel = std::move(result).value();
+        auto hidlPreparedModel = adaptPreparedModel(std::move(preparedModel), std::move(executor));
+        notify(callback, nn::ErrorStatus::NONE, std::move(hidlPreparedModel));
+    }
+}
+
+template <typename ModelType>
+nn::GeneralResult<hidl_vec<bool>> getSupportedOperations(const nn::SharedDevice& device,
+                                                         const ModelType& model) {
+    const auto nnModel = NN_TRY(convertInput(model));
+    return NN_TRY(device->getSupportedOperations(nnModel));
+}
+
+nn::GeneralResult<void> prepareModel(const nn::SharedDevice& device, const Executor& executor,
+                                     const V1_0::Model& model,
+                                     const sp<V1_0::IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnModel = NN_TRY(convertInput(model));
+
+    Task task = [device, nnModel = std::move(nnModel), executor, callback] {
+        auto result = device->prepareModel(nnModel, nn::ExecutionPreference::DEFAULT,
+                                           nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
+        notify(callback.get(), std::move(result), executor);
+    };
+    executor(std::move(task), {});
+
+    return {};
+}
+
+nn::GeneralResult<void> prepareModel_1_1(const nn::SharedDevice& device, const Executor& executor,
+                                         const V1_1::Model& model,
+                                         V1_1::ExecutionPreference preference,
+                                         const sp<V1_0::IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnModel = NN_TRY(convertInput(model));
+    const auto nnPreference = NN_TRY(convertInput(preference));
+
+    Task task = [device, nnModel = std::move(nnModel), nnPreference, executor, callback] {
+        auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {},
+                                           {}, {}, {});
+        notify(callback.get(), std::move(result), executor);
+    };
+    executor(std::move(task), {});
+
+    return {};
+}
+
+nn::GeneralResult<void> prepareModel_1_2(const nn::SharedDevice& device, const Executor& executor,
+                                         const V1_2::Model& model,
+                                         V1_1::ExecutionPreference preference,
+                                         const hidl_vec<hidl_handle>& modelCache,
+                                         const hidl_vec<hidl_handle>& dataCache,
+                                         const CacheToken& token,
+                                         const sp<V1_2::IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnModel = NN_TRY(convertInput(model));
+    const auto nnPreference = NN_TRY(convertInput(preference));
+    auto nnModelCache = NN_TRY(convertInput(modelCache));
+    auto nnDataCache = NN_TRY(convertInput(dataCache));
+    const auto nnToken = nn::CacheToken(token);
+
+    Task task = [device, nnModel = std::move(nnModel), nnPreference,
+                 nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
+                 nnToken, executor, callback] {
+        auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {},
+                                           nnModelCache, nnDataCache, nnToken, {}, {});
+        notify(callback.get(), std::move(result), executor);
+    };
+    executor(std::move(task), {});
+
+    return {};
+}
+
+nn::GeneralResult<void> prepareModel_1_3(
+        const nn::SharedDevice& device, const Executor& executor, const V1_3::Model& model,
+        V1_1::ExecutionPreference preference, V1_3::Priority priority,
+        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
+        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
+        const sp<V1_3::IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnModel = NN_TRY(convertInput(model));
+    const auto nnPreference = NN_TRY(convertInput(preference));
+    const auto nnPriority = NN_TRY(convertInput(priority));
+    const auto nnDeadline = NN_TRY(convertInput(deadline));
+    auto nnModelCache = NN_TRY(convertInput(modelCache));
+    auto nnDataCache = NN_TRY(convertInput(dataCache));
+    const auto nnToken = nn::CacheToken(token);
+
+    Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
+                 nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
+                 nnToken, executor, callback] {
+        auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
+                                           nnModelCache, nnDataCache, nnToken, {}, {});
+        notify(callback.get(), std::move(result), executor);
+    };
+    executor(std::move(task), nnDeadline);
+
+    return {};
+}
+
+nn::GeneralResult<void> prepareModelFromCache(const nn::SharedDevice& device,
+                                              const Executor& executor,
+                                              const hidl_vec<hidl_handle>& modelCache,
+                                              const hidl_vec<hidl_handle>& dataCache,
+                                              const CacheToken& token,
+                                              const sp<V1_2::IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnModelCache = NN_TRY(convertInput(modelCache));
+    auto nnDataCache = NN_TRY(convertInput(dataCache));
+    const auto nnToken = nn::CacheToken(token);
+
+    Task task = [device, nnModelCache = std::move(nnModelCache),
+                 nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+        auto result = device->prepareModelFromCache({}, nnModelCache, nnDataCache, nnToken);
+        notify(callback.get(), std::move(result), executor);
+    };
+    executor(std::move(task), {});
+
+    return {};
+}
+
+nn::GeneralResult<void> prepareModelFromCache_1_3(
+        const nn::SharedDevice& device, const Executor& executor,
+        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
+        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
+        const sp<V1_3::IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    const auto nnDeadline = NN_TRY(convertInput(deadline));
+    auto nnModelCache = NN_TRY(convertInput(modelCache));
+    auto nnDataCache = NN_TRY(convertInput(dataCache));
+    const auto nnToken = nn::CacheToken(token);
+
+    auto task = [device, nnDeadline, nnModelCache = std::move(nnModelCache),
+                 nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+        auto result = device->prepareModelFromCache(nnDeadline, nnModelCache, nnDataCache, nnToken);
+        notify(callback.get(), std::move(result), executor);
+    };
+    executor(std::move(task), nnDeadline);
+
+    return {};
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> downcast(const sp<V1_3::IPreparedModel>& preparedModel) {
+    if (preparedModel == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "preparedModel is nullptr";
+    }
+    if (preparedModel->isRemote()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Cannot convert remote models";
+    }
+
+    // This static_cast is safe because adapter::PreparedModel is the only class that implements
+    // the IPreparedModel interface in the adapter service code.
+    const auto* casted = static_cast<const PreparedModel*>(preparedModel.get());
+    return casted->getUnderlyingPreparedModel();
+}
+
+nn::GeneralResult<std::vector<nn::SharedPreparedModel>> downcastAll(
+        const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels) {
+    std::vector<nn::SharedPreparedModel> canonical;
+    canonical.reserve(preparedModels.size());
+    for (const auto& preparedModel : preparedModels) {
+        canonical.push_back(NN_TRY(downcast(preparedModel)));
+    }
+    return canonical;
+}
+
+nn::GeneralResult<std::pair<sp<V1_3::IBuffer>, uint32_t>> allocate(
+        const nn::SharedDevice& device, const V1_3::BufferDesc& desc,
+        const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels,
+        const hidl_vec<V1_3::BufferRole>& inputRoles,
+        const hidl_vec<V1_3::BufferRole>& outputRoles) {
+    auto nnDesc = NN_TRY(convertInput(desc));
+    auto nnPreparedModels = NN_TRY(downcastAll(preparedModels));
+    auto nnInputRoles = NN_TRY(convertInput(inputRoles));
+    auto nnOutputRoles = NN_TRY(convertInput(outputRoles));
+
+    auto buffer = NN_TRY(device->allocate(nnDesc, nnPreparedModels, nnInputRoles, nnOutputRoles));
+
+    const nn::Request::MemoryDomainToken token = buffer->getToken();
+    auto hidlBuffer = sp<Buffer>::make(std::move(buffer));
+    return std::make_pair(std::move(hidlBuffer), static_cast<uint32_t>(token));
+}
+
+}  // namespace
+
+Device::Device(nn::SharedDevice device, Executor executor)
+    : kDevice(std::move(device)), kExecutor(std::move(executor)) {
+    CHECK(kDevice != nullptr);
+    CHECK(kExecutor != nullptr);
+}
+
+Return<void> Device::getCapabilities(getCapabilities_cb cb) {
+    const auto capabilities = V1_0::utils::convert(kDevice->getCapabilities()).value();
+    cb(V1_0::ErrorStatus::NONE, capabilities);
+    return Void();
+}
+
+Return<void> Device::getCapabilities_1_1(getCapabilities_1_1_cb cb) {
+    const auto capabilities = V1_1::utils::convert(kDevice->getCapabilities()).value();
+    cb(V1_0::ErrorStatus::NONE, capabilities);
+    return Void();
+}
+
+Return<void> Device::getCapabilities_1_2(getCapabilities_1_2_cb cb) {
+    const auto capabilities = V1_2::utils::convert(kDevice->getCapabilities()).value();
+    cb(V1_0::ErrorStatus::NONE, capabilities);
+    return Void();
+}
+
+Return<void> Device::getCapabilities_1_3(getCapabilities_1_3_cb cb) {
+    const auto capabilities = V1_3::utils::convert(kDevice->getCapabilities()).value();
+    cb(V1_3::ErrorStatus::NONE, capabilities);
+    return Void();
+}
+
+Return<void> Device::getVersionString(getVersionString_cb cb) {
+    cb(V1_0::ErrorStatus::NONE, kDevice->getVersionString());
+    return Void();
+}
+
+Return<void> Device::getType(getType_cb cb) {
+    const auto maybeDeviceType = V1_2::utils::convert(kDevice->getType());
+    if (!maybeDeviceType.has_value()) {
+        const auto& [message, code] = maybeDeviceType.error();
+        LOG(ERROR) << "adapter::Device::getType failed with " << code << ": " << message;
+        cb(V1_2::utils::convert(code).value(), {});
+    } else {
+        cb(V1_0::ErrorStatus::NONE, maybeDeviceType.value());
+    }
+    return Void();
+}
+
+Return<void> Device::getSupportedExtensions(getSupportedExtensions_cb cb) {
+    const auto maybeSupportedExtensions = V1_2::utils::convert(kDevice->getSupportedExtensions());
+    if (!maybeSupportedExtensions.has_value()) {
+        const auto& [message, code] = maybeSupportedExtensions.error();
+        LOG(ERROR) << "adapter::Device::getSupportedExtensions failed with " << code << ": "
+                   << message;
+        cb(V1_2::utils::convert(code).value(), {});
+    } else {
+        cb(V1_0::ErrorStatus::NONE, maybeSupportedExtensions.value());
+    }
+    return Void();
+}
+
+Return<void> Device::getSupportedOperations(const V1_0::Model& model,
+                                            getSupportedOperations_cb cb) {
+    const auto result = adapter::getSupportedOperations(kDevice, model);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_0 failed with " << code << ": "
+                   << message;
+        cb(V1_0::utils::convert(code).value(), {});
+    } else {
+        cb(V1_0::ErrorStatus::NONE, result.value());
+    }
+    return Void();
+}
+
+Return<void> Device::getSupportedOperations_1_1(const V1_1::Model& model,
+                                                getSupportedOperations_1_1_cb cb) {
+    const auto result = adapter::getSupportedOperations(kDevice, model);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_1 failed with " << code << ": "
+                   << message;
+        cb(V1_1::utils::convert(code).value(), {});
+    } else {
+        cb(V1_0::ErrorStatus::NONE, result.value());
+    }
+    return Void();
+}
+
+Return<void> Device::getSupportedOperations_1_2(const V1_2::Model& model,
+                                                getSupportedOperations_1_2_cb cb) {
+    const auto result = adapter::getSupportedOperations(kDevice, model);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_2 failed with " << code << ": "
+                   << message;
+        cb(V1_2::utils::convert(code).value(), {});
+    } else {
+        cb(V1_0::ErrorStatus::NONE, result.value());
+    }
+    return Void();
+}
+
+Return<void> Device::getSupportedOperations_1_3(const V1_3::Model& model,
+                                                getSupportedOperations_1_3_cb cb) {
+    const auto result = adapter::getSupportedOperations(kDevice, model);
+    if (!result.has_value()) {
+        const auto& [message, code] = result.error();
+        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_3 failed with " << code << ": "
+                   << message;
+        cb(V1_3::utils::convert(code).value(), {});
+    } else {
+        cb(V1_3::ErrorStatus::NONE, result.value());
+    }
+    return Void();
+}
+
+Return<void> Device::getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) {
+    const auto [numModelCache, numDataCache] = kDevice->getNumberOfCacheFilesNeeded();
+    cb(V1_0::ErrorStatus::NONE, numModelCache, numDataCache);
+    return Void();
+}
+
+Return<V1_0::ErrorStatus> Device::prepareModel(const V1_0::Model& model,
+                                               const sp<V1_0::IPreparedModelCallback>& callback) {
+    auto result = adapter::prepareModel(kDevice, kExecutor, model, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::Device::prepareModel failed with " << code << ": " << message;
+        notify(callback.get(), code, nullptr);
+        return V1_0::utils::convert(code).value();
+    }
+    return V1_0::ErrorStatus::NONE;
+}
+
+Return<V1_0::ErrorStatus> Device::prepareModel_1_1(
+        const V1_1::Model& model, V1_1::ExecutionPreference preference,
+        const sp<V1_0::IPreparedModelCallback>& callback) {
+    auto result = adapter::prepareModel_1_1(kDevice, kExecutor, model, preference, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::Device::prepareModel_1_1 failed with " << code << ": " << message;
+        notify(callback.get(), code, nullptr);
+        return V1_1::utils::convert(code).value();
+    }
+    return V1_0::ErrorStatus::NONE;
+}
+
+Return<V1_0::ErrorStatus> Device::prepareModel_1_2(
+        const V1_2::Model& model, V1_1::ExecutionPreference preference,
+        const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
+        const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) {
+    auto result = adapter::prepareModel_1_2(kDevice, kExecutor, model, preference, modelCache,
+                                            dataCache, token, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::Device::prepareModel_1_2 failed with " << code << ": " << message;
+        notify(callback.get(), code, nullptr);
+        return V1_2::utils::convert(code).value();
+    }
+    return V1_0::ErrorStatus::NONE;
+}
+
+Return<V1_3::ErrorStatus> Device::prepareModel_1_3(
+        const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority,
+        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
+        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
+        const sp<V1_3::IPreparedModelCallback>& callback) {
+    auto result = adapter::prepareModel_1_3(kDevice, kExecutor, model, preference, priority,
+                                            deadline, modelCache, dataCache, token, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::Device::prepareModel_1_3 failed with " << code << ": " << message;
+        notify(callback.get(), code, nullptr);
+        return V1_3::utils::convert(code).value();
+    }
+    return V1_3::ErrorStatus::NONE;
+}
+
+Return<V1_0::ErrorStatus> Device::prepareModelFromCache(
+        const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
+        const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) {
+    auto result = adapter::prepareModelFromCache(kDevice, kExecutor, modelCache, dataCache, token,
+                                                 callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::Device::prepareModelFromCache failed with " << code << ": "
+                   << message;
+        notify(callback.get(), code, nullptr);
+        return V1_2::utils::convert(code).value();
+    }
+    return V1_0::ErrorStatus::NONE;
+}
+
+Return<V1_3::ErrorStatus> Device::prepareModelFromCache_1_3(
+        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
+        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
+        const sp<V1_3::IPreparedModelCallback>& callback) {
+    auto result = adapter::prepareModelFromCache_1_3(kDevice, kExecutor, deadline, modelCache,
+                                                     dataCache, token, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::Device::prepareModelFromCache_1_3 failed with " << code << ": "
+                   << message;
+        notify(callback.get(), code, nullptr);
+        return V1_3::utils::convert(code).value();
+    }
+    return V1_3::ErrorStatus::NONE;
+}
+
+Return<V1_0::DeviceStatus> Device::getStatus() {
+    return V1_0::DeviceStatus::AVAILABLE;
+}
+
+Return<void> Device::allocate(const V1_3::BufferDesc& desc,
+                              const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels,
+                              const hidl_vec<V1_3::BufferRole>& inputRoles,
+                              const hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) {
+    auto result = adapter::allocate(kDevice, desc, preparedModels, inputRoles, outputRoles);
+    if (!result.has_value()) {
+        const auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::Device::allocate failed with " << code << ": " << message;
+        cb(V1_3::utils::convert(code).value(), nullptr, /*token=*/0);
+        return Void();
+    }
+    auto [buffer, token] = std::move(result).value();
+    cb(V1_3::ErrorStatus::NONE, buffer, token);
+    return Void();
+}
+
+}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
new file mode 100644
index 0000000..c6055a6
--- /dev/null
+++ b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PreparedModel.h"
+
+#include "Burst.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IBurstCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/1.0/Utils.h>
+#include <nnapi/hal/1.2/Utils.h>
+#include <nnapi/hal/1.3/Conversions.h>
+#include <nnapi/hal/1.3/Utils.h>
+
+#include <memory>
+#include <thread>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
+// lifetimes across processes and for protecting asynchronous calls across HIDL.
+
+namespace android::hardware::neuralnetworks::adapter {
+namespace {
+
+template <typename Type>
+auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
+    auto result = nn::convert(object);
+    if (!result.has_value()) {
+        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return result;
+}
+
+nn::GeneralResult<nn::Version> validateRequestForModel(const nn::Request& request,
+                                                       const nn::Model& model) {
+    nn::GeneralResult<nn::Version> version = nn::validateRequestForModel(request, model);
+    if (!version.ok()) {
+        version.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return version;
+}
+
+class FencedExecutionCallback final : public V1_3::IFencedExecutionCallback {
+  public:
+    explicit FencedExecutionCallback(const nn::ExecuteFencedInfoCallback& callback)
+        : kCallback(callback) {
+        CHECK(callback != nullptr);
+    }
+
+    Return<void> getExecutionInfo(getExecutionInfo_cb cb) override {
+        const auto result = kCallback();
+        if (!result.has_value()) {
+            const auto& [message, code] = result.error();
+            const auto status =
+                    V1_3::utils::convert(code).value_or(V1_3::ErrorStatus::GENERAL_FAILURE);
+            LOG(ERROR) << message;
+            cb(status, V1_2::utils::kNoTiming, V1_2::utils::kNoTiming);
+            return Void();
+        }
+        const auto [timingLaunched, timingFenced] = result.value();
+        const auto hidlTimingLaunched = V1_3::utils::convert(timingLaunched).value();
+        const auto hidlTimingFenced = V1_3::utils::convert(timingFenced).value();
+        cb(V1_3::ErrorStatus::NONE, hidlTimingLaunched, hidlTimingFenced);
+        return Void();
+    }
+
+  private:
+    const nn::ExecuteFencedInfoCallback kCallback;
+};
+
+using ExecutionResult = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
+
+void notify(V1_0::IExecutionCallback* callback, nn::ErrorStatus status,
+            const std::vector<nn::OutputShape>& /*outputShapes*/, const nn::Timing& /*timing*/) {
+    if (callback != nullptr) {
+        const auto hidlStatus = V1_0::utils::convert(status).value();
+        const auto ret = callback->notify(hidlStatus);
+        if (!ret.isOk()) {
+            LOG(ERROR) << "V1_0::IExecutionCallback::notify failed with " << ret.description();
+        }
+    }
+}
+
+void notify(V1_2::IExecutionCallback* callback, nn::ErrorStatus status,
+            const std::vector<nn::OutputShape>& outputShapes, const nn::Timing& timing) {
+    if (callback != nullptr) {
+        const auto hidlStatus = V1_2::utils::convert(status).value();
+        const auto hidlOutputShapes = V1_2::utils::convert(outputShapes).value();
+        const auto hidlTiming = V1_2::utils::convert(timing).value();
+        const auto ret = callback->notify_1_2(hidlStatus, hidlOutputShapes, hidlTiming);
+        if (!ret.isOk()) {
+            LOG(ERROR) << "V1_2::IExecutionCallback::notify_1_2 failed with " << ret.description();
+        }
+    }
+}
+
+void notify(V1_3::IExecutionCallback* callback, nn::ErrorStatus status,
+            const std::vector<nn::OutputShape>& outputShapes, const nn::Timing& timing) {
+    if (callback != nullptr) {
+        const auto hidlStatus = V1_3::utils::convert(status).value();
+        const auto hidlOutputShapes = V1_3::utils::convert(outputShapes).value();
+        const auto hidlTiming = V1_3::utils::convert(timing).value();
+        const auto ret = callback->notify_1_3(hidlStatus, hidlOutputShapes, hidlTiming);
+        if (!ret.isOk()) {
+            LOG(ERROR) << "V1_3::IExecutionCallback::notify_1_3 failed with " << ret.description();
+        }
+    }
+}
+
+template <typename CallbackType>
+void notify(CallbackType* callback, ExecutionResult result) {
+    if (!result.has_value()) {
+        const auto [message, status, outputShapes] = std::move(result).error();
+        LOG(ERROR) << message;
+        notify(callback, status, outputShapes, {});
+    } else {
+        const auto [outputShapes, timing] = std::move(result).value();
+        notify(callback, nn::ErrorStatus::NONE, outputShapes, timing);
+    }
+}
+
+nn::GeneralResult<void> execute(const nn::SharedPreparedModel& preparedModel,
+                                const Executor& executor, const V1_0::Request& request,
+                                const sp<V1_0::IExecutionCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnRequest = NN_TRY(convertInput(request));
+
+    const std::any resource = preparedModel->getUnderlyingResource();
+    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
+        CHECK(*model != nullptr);
+        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    }
+
+    Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
+        auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
+        notify(callback.get(), std::move(result));
+    };
+    executor(std::move(task), {});
+
+    return {};
+}
+
+nn::GeneralResult<void> execute_1_2(const nn::SharedPreparedModel& preparedModel,
+                                    const Executor& executor, const V1_0::Request& request,
+                                    V1_2::MeasureTiming measure,
+                                    const sp<V1_2::IExecutionCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasure = NN_TRY(convertInput(measure));
+
+    const std::any resource = preparedModel->getUnderlyingResource();
+    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
+        CHECK(*model != nullptr);
+        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    }
+
+    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
+        auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
+        notify(callback.get(), std::move(result));
+    };
+    executor(std::move(task), {});
+
+    return {};
+}
+
+nn::GeneralResult<void> execute_1_3(const nn::SharedPreparedModel& preparedModel,
+                                    const Executor& executor, const V1_3::Request& request,
+                                    V1_2::MeasureTiming measure,
+                                    const V1_3::OptionalTimePoint& deadline,
+                                    const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
+                                    const sp<V1_3::IExecutionCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
+    }
+
+    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasure = NN_TRY(convertInput(measure));
+    const auto nnDeadline = NN_TRY(convertInput(deadline));
+    const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
+
+    const std::any resource = preparedModel->getUnderlyingResource();
+    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
+        CHECK(*model != nullptr);
+        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    }
+
+    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
+                 nnLoopTimeoutDuration, callback] {
+        auto result = preparedModel->execute(nnRequest, nnMeasure, nnDeadline,
+                                             nnLoopTimeoutDuration, {}, {});
+        notify(callback.get(), std::move(result));
+    };
+    executor(std::move(task), nnDeadline);
+
+    return {};
+}
+
+nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> executeSynchronously(
+        const nn::SharedPreparedModel& preparedModel, const V1_0::Request& request,
+        V1_2::MeasureTiming measure) {
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasure = NN_TRY(convertInput(measure));
+
+    const auto [outputShapes, timing] =
+            NN_TRY(preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {}));
+
+    auto hidlOutputShapes = NN_TRY(V1_2::utils::convert(outputShapes));
+    const auto hidlTiming = NN_TRY(V1_2::utils::convert(timing));
+    return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
+}
+
+nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> executeSynchronously_1_3(
+        const nn::SharedPreparedModel& preparedModel, const V1_3::Request& request,
+        V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& deadline,
+        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration) {
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasure = NN_TRY(convertInput(measure));
+    const auto nnDeadline = NN_TRY(convertInput(deadline));
+    const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
+
+    const auto [outputShapes, timing] = NN_TRY(preparedModel->execute(
+            nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration, {}, {}));
+
+    auto hidlOutputShapes = NN_TRY(V1_3::utils::convert(outputShapes));
+    const auto hidlTiming = NN_TRY(V1_3::utils::convert(timing));
+    return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
+}
+
+nn::GeneralResult<std::vector<nn::SyncFence>> convertSyncFences(
+        const hidl_vec<hidl_handle>& handles) {
+    auto nnHandles = NN_TRY(convertInput(handles));
+    std::vector<nn::SyncFence> syncFences;
+    syncFences.reserve(handles.size());
+    for (auto&& handle : nnHandles) {
+        if (auto syncFence = nn::SyncFence::create(std::move(handle)); !syncFence.ok()) {
+            return nn::error(nn::ErrorStatus::INVALID_ARGUMENT) << std::move(syncFence).error();
+        } else {
+            syncFences.push_back(std::move(syncFence).value());
+        }
+    }
+    return syncFences;
+}
+
+nn::GeneralResult<sp<V1_2::IBurstContext>> configureExecutionBurst(
+        const nn::SharedPreparedModel& preparedModel, const sp<V1_2::IBurstCallback>& callback,
+        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
+        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel) {
+    auto burstExecutor = NN_TRY(preparedModel->configureExecutionBurst());
+    return Burst::create(callback, requestChannel, resultChannel, std::move(burstExecutor),
+                         V1_2::utils::getBurstServerPollingTimeWindow());
+}
+
+nn::GeneralResult<std::pair<hidl_handle, sp<V1_3::IFencedExecutionCallback>>> executeFenced(
+        const nn::SharedPreparedModel& preparedModel, const V1_3::Request& request,
+        const hidl_vec<hidl_handle>& waitFor, V1_2::MeasureTiming measure,
+        const V1_3::OptionalTimePoint& deadline,
+        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
+        const V1_3::OptionalTimeoutDuration& duration) {
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnWaitFor = NN_TRY(convertSyncFences(waitFor));
+    const auto nnMeasure = NN_TRY(convertInput(measure));
+    const auto nnDeadline = NN_TRY(convertInput(deadline));
+    const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
+    const auto nnDuration = NN_TRY(convertInput(duration));
+
+    auto [syncFence, executeFencedCallback] =
+            NN_TRY(preparedModel->executeFenced(nnRequest, nnWaitFor, nnMeasure, nnDeadline,
+                                                nnLoopTimeoutDuration, nnDuration, {}, {}));
+
+    auto hidlSyncFence = NN_TRY(V1_3::utils::convert(syncFence.getSharedHandle()));
+    auto hidlExecuteFencedCallback = sp<FencedExecutionCallback>::make(executeFencedCallback);
+    return std::make_pair(std::move(hidlSyncFence), std::move(hidlExecuteFencedCallback));
+}
+
+}  // namespace
+
+PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor)
+    : kPreparedModel(std::move(preparedModel)), kExecutor(std::move(executor)) {
+    CHECK(kPreparedModel != nullptr);
+    CHECK(kExecutor != nullptr);
+}
+
+nn::SharedPreparedModel PreparedModel::getUnderlyingPreparedModel() const {
+    return kPreparedModel;
+}
+
+Return<V1_0::ErrorStatus> PreparedModel::execute(const V1_0::Request& request,
+                                                 const sp<V1_0::IExecutionCallback>& callback) {
+    auto result = adapter::execute(kPreparedModel, kExecutor, request, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::PreparedModel::execute failed with " << code << ": " << message;
+        notify(callback.get(), code, {}, {});
+        return V1_0::utils::convert(code).value();
+    }
+    return V1_0::ErrorStatus::NONE;
+}
+
+Return<V1_0::ErrorStatus> PreparedModel::execute_1_2(const V1_0::Request& request,
+                                                     V1_2::MeasureTiming measure,
+                                                     const sp<V1_2::IExecutionCallback>& callback) {
+    auto result = adapter::execute_1_2(kPreparedModel, kExecutor, request, measure, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::PreparedModel::execute_1_2 failed with " << code << ": " << message;
+        notify(callback.get(), code, {}, {});
+        return V1_2::utils::convert(code).value();
+    }
+    return V1_0::ErrorStatus::NONE;
+}
+
+Return<V1_3::ErrorStatus> PreparedModel::execute_1_3(
+        const V1_3::Request& request, V1_2::MeasureTiming measure,
+        const V1_3::OptionalTimePoint& deadline,
+        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
+        const sp<V1_3::IExecutionCallback>& callback) {
+    auto result = adapter::execute_1_3(kPreparedModel, kExecutor, request, measure, deadline,
+                                       loopTimeoutDuration, callback);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::PreparedModel::execute_1_3 failed with " << code << ": " << message;
+        notify(callback.get(), code, {}, {});
+        return V1_3::utils::convert(code).value();
+    }
+    return V1_3::ErrorStatus::NONE;
+}
+
+Return<void> PreparedModel::executeSynchronously(const V1_0::Request& request,
+                                                 V1_2::MeasureTiming measure,
+                                                 executeSynchronously_cb cb) {
+    auto result = adapter::executeSynchronously(kPreparedModel, request, measure);
+    if (!result.has_value()) {
+        auto [message, code, outputShapes] = std::move(result).error();
+        LOG(ERROR) << "adapter::PreparedModel::executeSynchronously failed with " << code << ": "
+                   << message;
+        cb(V1_2::utils::convert(code).value(), V1_2::utils::convert(outputShapes).value(),
+           V1_2::utils::kNoTiming);
+        return Void();
+    }
+    auto [outputShapes, timing] = std::move(result).value();
+    cb(V1_0::ErrorStatus::NONE, outputShapes, timing);
+    return Void();
+}
+
+Return<void> PreparedModel::executeSynchronously_1_3(
+        const V1_3::Request& request, V1_2::MeasureTiming measure,
+        const V1_3::OptionalTimePoint& deadline,
+        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb) {
+    auto result = adapter::executeSynchronously_1_3(kPreparedModel, request, measure, deadline,
+                                                    loopTimeoutDuration);
+    if (!result.has_value()) {
+        auto [message, code, outputShapes] = std::move(result).error();
+        LOG(ERROR) << "adapter::PreparedModel::executeSynchronously_1_3 failed with " << code
+                   << ": " << message;
+        cb(V1_3::utils::convert(code).value(), V1_3::utils::convert(outputShapes).value(),
+           V1_2::utils::kNoTiming);
+        return Void();
+    }
+    auto [outputShapes, timing] = std::move(result).value();
+    cb(V1_3::ErrorStatus::NONE, outputShapes, timing);
+    return Void();
+}
+
+Return<void> PreparedModel::configureExecutionBurst(
+        const sp<V1_2::IBurstCallback>& callback,
+        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
+        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
+        configureExecutionBurst_cb cb) {
+    auto result = adapter::configureExecutionBurst(kPreparedModel, callback, requestChannel,
+                                                   resultChannel);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::PreparedModel::configureExecutionBurst failed with " << code << ": "
+                   << message;
+        cb(V1_2::utils::convert(code).value(), nullptr);
+        return Void();
+    }
+    auto burstContext = std::move(result).value();
+    cb(V1_0::ErrorStatus::NONE, std::move(burstContext));
+    return Void();
+}
+
+Return<void> PreparedModel::executeFenced(const V1_3::Request& request,
+                                          const hidl_vec<hidl_handle>& waitFor,
+                                          V1_2::MeasureTiming measure,
+                                          const V1_3::OptionalTimePoint& deadline,
+                                          const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
+                                          const V1_3::OptionalTimeoutDuration& duration,
+                                          executeFenced_cb callback) {
+    auto result = adapter::executeFenced(kPreparedModel, request, waitFor, measure, deadline,
+                                         loopTimeoutDuration, duration);
+    if (!result.has_value()) {
+        auto [message, code] = std::move(result).error();
+        LOG(ERROR) << "adapter::PreparedModel::executeFenced failed with " << code << ": "
+                   << message;
+        callback(V1_3::utils::convert(code).value(), {}, nullptr);
+        return Void();
+    }
+    auto [syncFence, executeFencedCallback] = std::move(result).value();
+    callback(V1_3::ErrorStatus::NONE, syncFence, executeFencedCallback);
+    return Void();
+}
+
+}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/include/nnapi/hal/Adapter.h b/neuralnetworks/utils/adapter/include/nnapi/hal/Adapter.h
deleted file mode 100644
index da00a09..0000000
--- a/neuralnetworks/utils/adapter/include/nnapi/hal/Adapter.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_ADAPTER_H
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_ADAPTER_H
-
-#include <android/hardware/neuralnetworks/1.3/IDevice.h>
-#include <nnapi/IDevice.h>
-#include <nnapi/Types.h>
-#include <sys/types.h>
-#include <functional>
-#include <memory>
-
-// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
-// lifetimes across processes and for protecting asynchronous calls across HIDL.
-
-namespace android::hardware::neuralnetworks::adapter {
-
-/**
- * A self-contained unit of work to be executed.
- */
-using Task = std::function<void()>;
-
-/**
- * A type-erased executor which executes a task asynchronously.
- *
- * This executor is also provided with an Application ID (Android User ID) and an optional deadline
- * for when the caller expects is the upper bound for the amount of time to complete the task.
- */
-using Executor = std::function<void(Task, uid_t, nn::OptionalTimePoint)>;
-
-/**
- * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
- *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
- * @param device NNAPI canonical IDevice interface object to be adapted.
- * @param executor Type-erased executor to handle executing tasks asynchronously.
- * @return HIDL NN HAL IDevice interface object.
- */
-sp<V1_3::IDevice> adapt(nn::SharedDevice device, Executor executor);
-
-/**
- * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
- *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
- * This function uses a default executor, which will execute tasks from a detached thread.
- *
- * @param device NNAPI canonical IDevice interface object to be adapted.
- * @return HIDL NN HAL IDevice interface object.
- */
-sp<V1_3::IDevice> adapt(nn::SharedDevice device);
-
-}  // namespace android::hardware::neuralnetworks::adapter
-
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_ADAPTER_H
diff --git a/neuralnetworks/utils/adapter/include/nnapi/hal/PreparedModel.h b/neuralnetworks/utils/adapter/include/nnapi/hal/PreparedModel.h
deleted file mode 100644
index 65763b8..0000000
--- a/neuralnetworks/utils/adapter/include/nnapi/hal/PreparedModel.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_PREPARED_MODEL_H
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_PREPARED_MODEL_H
-
-#include "nnapi/hal/Adapter.h"
-
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.2/IBurstCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.2/types.h>
-#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.3/types.h>
-#include <nnapi/IPreparedModel.h>
-#include <nnapi/Types.h>
-#include <memory>
-
-// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
-// lifetimes across processes and for protecting asynchronous calls across HIDL.
-
-namespace android::hardware::neuralnetworks::adapter {
-
-// Class that adapts nn::IPreparedModel to V1_3::IPreparedModel.
-class PreparedModel final : public V1_3::IPreparedModel {
-  public:
-    PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor, uid_t userId);
-
-    Return<V1_0::ErrorStatus> execute(const V1_0::Request& request,
-                                      const sp<V1_0::IExecutionCallback>& callback) override;
-    Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request& request, V1_2::MeasureTiming measure,
-                                          const sp<V1_2::IExecutionCallback>& callback) override;
-    Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request& request, V1_2::MeasureTiming measure,
-                                          const V1_3::OptionalTimePoint& deadline,
-                                          const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
-                                          const sp<V1_3::IExecutionCallback>& callback) override;
-    Return<void> executeSynchronously(const V1_0::Request& request, V1_2::MeasureTiming measure,
-                                      executeSynchronously_cb cb) override;
-    Return<void> executeSynchronously_1_3(const V1_3::Request& request, V1_2::MeasureTiming measure,
-                                          const V1_3::OptionalTimePoint& deadline,
-                                          const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
-                                          executeSynchronously_1_3_cb cb) override;
-    Return<void> configureExecutionBurst(
-            const sp<V1_2::IBurstCallback>& callback,
-            const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
-            const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
-            configureExecutionBurst_cb cb) override;
-    Return<void> executeFenced(const V1_3::Request& request, const hidl_vec<hidl_handle>& waitFor,
-                               V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& deadline,
-                               const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
-                               const V1_3::OptionalTimeoutDuration& duration,
-                               executeFenced_cb callback) override;
-
-    nn::SharedPreparedModel getUnderlyingPreparedModel() const;
-
-  private:
-    const nn::SharedPreparedModel kPreparedModel;
-    const Executor kExecutor;
-    const uid_t kUserId;
-};
-
-}  // namespace android::hardware::neuralnetworks::adapter
-
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_PREPARED_MODEL_H
diff --git a/neuralnetworks/utils/adapter/src/Adapter.cpp b/neuralnetworks/utils/adapter/src/Adapter.cpp
deleted file mode 100644
index d6f53f0..0000000
--- a/neuralnetworks/utils/adapter/src/Adapter.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Adapter.h"
-
-#include "Device.h"
-
-#include <android/hardware/neuralnetworks/1.3/IDevice.h>
-#include <nnapi/IDevice.h>
-#include <nnapi/Types.h>
-#include <sys/types.h>
-
-#include <functional>
-#include <memory>
-#include <thread>
-
-// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
-// lifetimes across processes and for protecting asynchronous calls across HIDL.
-
-namespace android::hardware::neuralnetworks::adapter {
-
-sp<V1_3::IDevice> adapt(nn::SharedDevice device, Executor executor) {
-    return sp<Device>::make(std::move(device), std::move(executor));
-}
-
-sp<V1_3::IDevice> adapt(nn::SharedDevice device) {
-    Executor defaultExecutor = [](Task task, uid_t /*uid*/, nn::OptionalTimePoint /*deadline*/) {
-        std::thread(std::move(task)).detach();
-    };
-    return adapt(std::move(device), std::move(defaultExecutor));
-}
-
-}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/src/Burst.cpp b/neuralnetworks/utils/adapter/src/Burst.cpp
deleted file mode 100644
index 8b2e1dd..0000000
--- a/neuralnetworks/utils/adapter/src/Burst.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Burst.h"
-
-#include <android-base/logging.h>
-#include <nnapi/IBurst.h>
-#include <nnapi/Result.h>
-#include <nnapi/TypeUtils.h>
-#include <nnapi/Types.h>
-#include <nnapi/Validation.h>
-#include <nnapi/hal/1.0/Conversions.h>
-#include <nnapi/hal/1.0/HandleError.h>
-#include <nnapi/hal/1.0/ProtectCallback.h>
-#include <nnapi/hal/1.2/BurstUtils.h>
-#include <nnapi/hal/1.2/Conversions.h>
-#include <nnapi/hal/TransferValue.h>
-
-#include <algorithm>
-#include <cstring>
-#include <limits>
-#include <map>
-#include <memory>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "Tracing.h"
-
-namespace android::hardware::neuralnetworks::adapter {
-namespace {
-
-constexpr V1_2::Timing kTiming = {std::numeric_limits<uint64_t>::max(),
-                                  std::numeric_limits<uint64_t>::max()};
-
-nn::GeneralResult<std::vector<nn::SharedMemory>> getMemoriesCallback(
-        V1_0::ErrorStatus status, const hidl_vec<hidl_memory>& memories) {
-    HANDLE_STATUS_HIDL(status) << "getting burst memories failed with " << toString(status);
-    std::vector<nn::SharedMemory> canonicalMemories;
-    canonicalMemories.reserve(memories.size());
-    for (const auto& memory : memories) {
-        canonicalMemories.push_back(NN_TRY(nn::convert(memory)));
-    }
-    return canonicalMemories;
-}
-
-}  // anonymous namespace
-
-Burst::MemoryCache::MemoryCache(nn::SharedBurst burstExecutor,
-                                sp<V1_2::IBurstCallback> burstCallback)
-    : kBurstExecutor(std::move(burstExecutor)), kBurstCallback(std::move(burstCallback)) {
-    CHECK(kBurstExecutor != nullptr);
-    CHECK(kBurstCallback != nullptr);
-}
-
-nn::GeneralResult<std::vector<std::pair<nn::SharedMemory, nn::IBurst::OptionalCacheHold>>>
-Burst::MemoryCache::getCacheEntries(const std::vector<int32_t>& slots) {
-    std::lock_guard guard(mMutex);
-    NN_TRY(ensureCacheEntriesArePresentLocked(slots));
-
-    std::vector<std::pair<nn::SharedMemory, nn::IBurst::OptionalCacheHold>> results;
-    results.reserve(slots.size());
-    for (int32_t slot : slots) {
-        results.push_back(NN_TRY(getCacheEntryLocked(slot)));
-    }
-
-    return results;
-}
-
-nn::GeneralResult<void> Burst::MemoryCache::ensureCacheEntriesArePresentLocked(
-        const std::vector<int32_t>& slots) {
-    const auto slotIsKnown = [this](int32_t slot)
-                                     REQUIRES(mMutex) { return mCache.count(slot) > 0; };
-
-    // find unique unknown slots
-    std::vector<int32_t> unknownSlots = slots;
-    std::sort(unknownSlots.begin(), unknownSlots.end());
-    auto unknownSlotsEnd = std::unique(unknownSlots.begin(), unknownSlots.end());
-    unknownSlotsEnd = std::remove_if(unknownSlots.begin(), unknownSlotsEnd, slotIsKnown);
-    unknownSlots.erase(unknownSlotsEnd, unknownSlots.end());
-
-    // quick-exit if all slots are known
-    if (unknownSlots.empty()) {
-        return {};
-    }
-
-    auto cb = neuralnetworks::utils::CallbackValue(getMemoriesCallback);
-
-    const auto ret = kBurstCallback->getMemories(unknownSlots, cb);
-    HANDLE_TRANSPORT_FAILURE(ret);
-
-    auto returnedMemories = NN_TRY(cb.take());
-
-    if (returnedMemories.size() != unknownSlots.size()) {
-        return NN_ERROR() << "Burst::MemoryCache::ensureCacheEntriesArePresentLocked: Error "
-                             "retrieving memories -- count mismatch between requested memories ("
-                          << unknownSlots.size() << ") and returned memories ("
-                          << returnedMemories.size() << ")";
-    }
-
-    // add memories to unknown slots
-    for (size_t i = 0; i < unknownSlots.size(); ++i) {
-        addCacheEntryLocked(unknownSlots[i], std::move(returnedMemories[i]));
-    }
-
-    return {};
-}
-
-nn::GeneralResult<std::pair<nn::SharedMemory, nn::IBurst::OptionalCacheHold>>
-Burst::MemoryCache::getCacheEntryLocked(int32_t slot) {
-    if (const auto iter = mCache.find(slot); iter != mCache.end()) {
-        return iter->second;
-    }
-    return NN_ERROR() << "Burst::MemoryCache::getCacheEntryLocked failed because slot " << slot
-                      << " is not present in the cache";
-}
-
-void Burst::MemoryCache::addCacheEntryLocked(int32_t slot, nn::SharedMemory memory) {
-    auto hold = kBurstExecutor->cacheMemory(memory);
-    mCache.emplace(slot, std::make_pair(std::move(memory), std::move(hold)));
-}
-
-void Burst::MemoryCache::removeCacheEntry(int32_t slot) {
-    std::lock_guard guard(mMutex);
-    mCache.erase(slot);
-}
-
-// Burst methods
-
-nn::GeneralResult<sp<Burst>> Burst::create(
-        const sp<V1_2::IBurstCallback>& callback,
-        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
-        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel, nn::SharedBurst burstExecutor,
-        std::chrono::microseconds pollingTimeWindow) {
-    // check inputs
-    if (callback == nullptr || burstExecutor == nullptr) {
-        return NN_ERROR() << "Burst::create passed a nullptr";
-    }
-
-    // create FMQ objects
-    auto requestChannelReceiver =
-            NN_TRY(V1_2::utils::RequestChannelReceiver::create(requestChannel, pollingTimeWindow));
-    auto resultChannelSender = NN_TRY(V1_2::utils::ResultChannelSender::create(resultChannel));
-
-    // check FMQ objects
-    CHECK(requestChannelReceiver != nullptr);
-    CHECK(resultChannelSender != nullptr);
-
-    // make and return context
-    return sp<Burst>::make(PrivateConstructorTag{}, callback, std::move(requestChannelReceiver),
-                           std::move(resultChannelSender), std::move(burstExecutor));
-}
-
-Burst::Burst(PrivateConstructorTag /*tag*/, const sp<V1_2::IBurstCallback>& callback,
-             std::unique_ptr<V1_2::utils::RequestChannelReceiver> requestChannel,
-             std::unique_ptr<V1_2::utils::ResultChannelSender> resultChannel,
-             nn::SharedBurst burstExecutor)
-    : mCallback(callback),
-      mRequestChannelReceiver(std::move(requestChannel)),
-      mResultChannelSender(std::move(resultChannel)),
-      mBurstExecutor(std::move(burstExecutor)),
-      mMemoryCache(mBurstExecutor, mCallback) {
-    // TODO: highly document the threading behavior of this class
-    mWorker = std::thread([this] { task(); });
-}
-
-Burst::~Burst() {
-    // set teardown flag
-    mTeardown = true;
-    mRequestChannelReceiver->invalidate();
-
-    // wait for task thread to end
-    mWorker.join();
-}
-
-Return<void> Burst::freeMemory(int32_t slot) {
-    mMemoryCache.removeCacheEntry(slot);
-    return Void();
-}
-
-void Burst::task() {
-    // loop until the burst object is being destroyed
-    while (!mTeardown) {
-        // receive request
-        auto arguments = mRequestChannelReceiver->getBlocking();
-
-        // if the request packet was not properly received, return a generic error and skip the
-        // execution
-        //
-        // if the burst is being torn down, skip the execution so the "task" function can end
-        if (!arguments.has_value()) {
-            if (!mTeardown) {
-                mResultChannelSender->send(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kTiming);
-            }
-            continue;
-        }
-
-        // unpack the arguments; types are Request, std::vector<int32_t>, and V1_2::MeasureTiming,
-        // respectively
-        const auto [requestWithoutPools, slotsOfPools, measure] = std::move(arguments).value();
-
-        auto result = execute(requestWithoutPools, slotsOfPools, measure);
-
-        // return result
-        if (result.has_value()) {
-            const auto& [outputShapes, timing] = result.value();
-            mResultChannelSender->send(V1_0::ErrorStatus::NONE, outputShapes, timing);
-        } else {
-            const auto& [message, code, outputShapes] = result.error();
-            LOG(ERROR) << "IBurst::execute failed with " << code << ": " << message;
-            mResultChannelSender->send(V1_2::utils::convert(code).value(),
-                                       V1_2::utils::convert(outputShapes).value(), kTiming);
-        }
-    }
-}
-
-nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> Burst::execute(
-        const V1_0::Request& requestWithoutPools, const std::vector<int32_t>& slotsOfPools,
-        V1_2::MeasureTiming measure) {
-    NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_EXECUTION,
-                 "Burst getting memory, executing, and returning results");
-
-    // ensure executor with cache has required memory
-    const auto cacheEntries = NN_TRY(mMemoryCache.getCacheEntries(slotsOfPools));
-
-    // convert request, populating its pools
-    // This code performs an unvalidated convert because the request object without its pools is
-    // invalid because it is incomplete. Instead, the validation is performed after the memory pools
-    // have been added to the request.
-    auto canonicalRequest = NN_TRY(nn::unvalidatedConvert(requestWithoutPools));
-    CHECK(canonicalRequest.pools.empty());
-    std::transform(cacheEntries.begin(), cacheEntries.end(),
-                   std::back_inserter(canonicalRequest.pools),
-                   [](const auto& cacheEntry) { return cacheEntry.first; });
-    NN_TRY(validate(canonicalRequest));
-
-    nn::MeasureTiming canonicalMeasure = NN_TRY(nn::convert(measure));
-
-    const auto [outputShapes, timing] =
-            NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure, {}, {}));
-
-    return std::make_pair(NN_TRY(V1_2::utils::convert(outputShapes)),
-                          NN_TRY(V1_2::utils::convert(timing)));
-}
-
-}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/src/Device.cpp b/neuralnetworks/utils/adapter/src/Device.cpp
deleted file mode 100644
index 96142c3..0000000
--- a/neuralnetworks/utils/adapter/src/Device.cpp
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Device.h"
-
-#include "Buffer.h"
-#include "PreparedModel.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
-#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
-#include <android/hardware/neuralnetworks/1.2/types.h>
-#include <android/hardware/neuralnetworks/1.3/IDevice.h>
-#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
-#include <android/hardware/neuralnetworks/1.3/types.h>
-#include <hwbinder/IPCThreadState.h>
-#include <nnapi/IBuffer.h>
-#include <nnapi/IDevice.h>
-#include <nnapi/IPreparedModel.h>
-#include <nnapi/Result.h>
-#include <nnapi/TypeUtils.h>
-#include <nnapi/Types.h>
-#include <nnapi/hal/1.0/Conversions.h>
-#include <nnapi/hal/1.0/Utils.h>
-#include <nnapi/hal/1.1/Conversions.h>
-#include <nnapi/hal/1.1/Utils.h>
-#include <nnapi/hal/1.2/Conversions.h>
-#include <nnapi/hal/1.2/Utils.h>
-#include <nnapi/hal/1.3/Conversions.h>
-#include <nnapi/hal/1.3/Utils.h>
-#include <sys/types.h>
-
-#include <memory>
-
-// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
-// lifetimes across processes and for protecting asynchronous calls across HIDL.
-
-namespace android::hardware::neuralnetworks::adapter {
-namespace {
-
-template <typename Type>
-auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
-    auto result = nn::convert(object);
-    if (!result.has_value()) {
-        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
-    }
-    return result;
-}
-
-using PrepareModelResult = nn::GeneralResult<nn::SharedPreparedModel>;
-
-sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel, Executor executor,
-                                     uid_t userId) {
-    if (preparedModel == nullptr) {
-        return nullptr;
-    }
-    return sp<PreparedModel>::make(std::move(preparedModel), std::move(executor), userId);
-}
-
-void notify(V1_0::IPreparedModelCallback* callback, nn::ErrorStatus status,
-            const sp<PreparedModel>& hidlPreparedModel) {
-    if (callback != nullptr) {
-        const auto hidlStatus = V1_0::utils::convert(status).value();
-        const auto ret = callback->notify(hidlStatus, hidlPreparedModel);
-        if (!ret.isOk()) {
-            LOG(ERROR) << "V1_0::IPreparedModelCallback::notify failed with " << ret.description();
-        }
-    }
-}
-
-void notify(V1_2::IPreparedModelCallback* callback, nn::ErrorStatus status,
-            const sp<PreparedModel>& hidlPreparedModel) {
-    if (callback != nullptr) {
-        const auto hidlStatus = V1_2::utils::convert(status).value();
-        const auto ret = callback->notify_1_2(hidlStatus, hidlPreparedModel);
-        if (!ret.isOk()) {
-            LOG(ERROR) << "V1_2::IPreparedModelCallback::notify_1_2 failed with "
-                       << ret.description();
-        }
-    }
-}
-
-void notify(V1_3::IPreparedModelCallback* callback, nn::ErrorStatus status,
-            const sp<PreparedModel>& hidlPreparedModel) {
-    if (callback != nullptr) {
-        const auto hidlStatus = V1_3::utils::convert(status).value();
-        const auto ret = callback->notify_1_3(hidlStatus, hidlPreparedModel);
-        if (!ret.isOk()) {
-            LOG(ERROR) << "V1_3::IPreparedModelCallback::notify_1_3 failed with "
-                       << ret.description();
-        }
-    }
-}
-
-template <typename CallbackType>
-void notify(CallbackType* callback, PrepareModelResult result, Executor executor, uid_t userId) {
-    if (!result.has_value()) {
-        const auto [message, status] = std::move(result).error();
-        LOG(ERROR) << message;
-        notify(callback, status, nullptr);
-    } else {
-        auto preparedModel = std::move(result).value();
-        auto hidlPreparedModel =
-                adaptPreparedModel(std::move(preparedModel), std::move(executor), userId);
-        notify(callback, nn::ErrorStatus::NONE, std::move(hidlPreparedModel));
-    }
-}
-
-template <typename ModelType>
-nn::GeneralResult<hidl_vec<bool>> getSupportedOperations(const nn::SharedDevice& device,
-                                                         const ModelType& model) {
-    const auto nnModel = NN_TRY(convertInput(model));
-    return NN_TRY(device->getSupportedOperations(nnModel));
-}
-
-nn::GeneralResult<void> prepareModel(const nn::SharedDevice& device, const Executor& executor,
-                                     const V1_0::Model& model,
-                                     const sp<V1_0::IPreparedModelCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnModel = NN_TRY(convertInput(model));
-
-    const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
-    Task task = [device, nnModel = std::move(nnModel), userId, executor, callback] {
-        auto result = device->prepareModel(nnModel, nn::ExecutionPreference::DEFAULT,
-                                           nn::Priority::DEFAULT, {}, {}, {}, {});
-        notify(callback.get(), std::move(result), executor, userId);
-    };
-    executor(std::move(task), userId, {});
-
-    return {};
-}
-
-nn::GeneralResult<void> prepareModel_1_1(const nn::SharedDevice& device, const Executor& executor,
-                                         const V1_1::Model& model,
-                                         V1_1::ExecutionPreference preference,
-                                         const sp<V1_0::IPreparedModelCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnModel = NN_TRY(convertInput(model));
-    const auto nnPreference = NN_TRY(convertInput(preference));
-
-    const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
-    Task task = [device, nnModel = std::move(nnModel), nnPreference, userId, executor, callback] {
-        auto result =
-                device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {}, {});
-        notify(callback.get(), std::move(result), executor, userId);
-    };
-    executor(std::move(task), userId, {});
-
-    return {};
-}
-
-nn::GeneralResult<void> prepareModel_1_2(const nn::SharedDevice& device, const Executor& executor,
-                                         const V1_2::Model& model,
-                                         V1_1::ExecutionPreference preference,
-                                         const hidl_vec<hidl_handle>& modelCache,
-                                         const hidl_vec<hidl_handle>& dataCache,
-                                         const CacheToken& token,
-                                         const sp<V1_2::IPreparedModelCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnModel = NN_TRY(convertInput(model));
-    const auto nnPreference = NN_TRY(convertInput(preference));
-    auto nnModelCache = NN_TRY(convertInput(modelCache));
-    auto nnDataCache = NN_TRY(convertInput(dataCache));
-    const auto nnToken = nn::CacheToken(token);
-
-    const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
-    Task task = [device, nnModel = std::move(nnModel), nnPreference,
-                 nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
-                 nnToken, userId, executor, callback] {
-        auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {},
-                                           nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor, userId);
-    };
-    executor(std::move(task), userId, {});
-
-    return {};
-}
-
-nn::GeneralResult<void> prepareModel_1_3(
-        const nn::SharedDevice& device, const Executor& executor, const V1_3::Model& model,
-        V1_1::ExecutionPreference preference, V1_3::Priority priority,
-        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
-        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
-        const sp<V1_3::IPreparedModelCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnModel = NN_TRY(convertInput(model));
-    const auto nnPreference = NN_TRY(convertInput(preference));
-    const auto nnPriority = NN_TRY(convertInput(priority));
-    const auto nnDeadline = NN_TRY(convertInput(deadline));
-    auto nnModelCache = NN_TRY(convertInput(modelCache));
-    auto nnDataCache = NN_TRY(convertInput(dataCache));
-    const auto nnToken = nn::CacheToken(token);
-
-    const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
-    Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
-                 nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
-                 nnToken, userId, executor, callback] {
-        auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
-                                           nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor, userId);
-    };
-    executor(std::move(task), userId, nnDeadline);
-
-    return {};
-}
-
-nn::GeneralResult<void> prepareModelFromCache(const nn::SharedDevice& device,
-                                              const Executor& executor,
-                                              const hidl_vec<hidl_handle>& modelCache,
-                                              const hidl_vec<hidl_handle>& dataCache,
-                                              const CacheToken& token,
-                                              const sp<V1_2::IPreparedModelCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnModelCache = NN_TRY(convertInput(modelCache));
-    auto nnDataCache = NN_TRY(convertInput(dataCache));
-    const auto nnToken = nn::CacheToken(token);
-
-    const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
-    Task task = [device, nnModelCache = std::move(nnModelCache),
-                 nnDataCache = std::move(nnDataCache), nnToken, userId, executor, callback] {
-        auto result = device->prepareModelFromCache({}, nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor, userId);
-    };
-    executor(std::move(task), userId, {});
-
-    return {};
-}
-
-nn::GeneralResult<void> prepareModelFromCache_1_3(
-        const nn::SharedDevice& device, const Executor& executor,
-        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
-        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
-        const sp<V1_3::IPreparedModelCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    const auto nnDeadline = NN_TRY(convertInput(deadline));
-    auto nnModelCache = NN_TRY(convertInput(modelCache));
-    auto nnDataCache = NN_TRY(convertInput(dataCache));
-    const auto nnToken = nn::CacheToken(token);
-
-    const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
-    auto task = [device, nnDeadline, nnModelCache = std::move(nnModelCache),
-                 nnDataCache = std::move(nnDataCache), nnToken, userId, executor, callback] {
-        auto result = device->prepareModelFromCache(nnDeadline, nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor, userId);
-    };
-    executor(std::move(task), userId, nnDeadline);
-
-    return {};
-}
-
-nn::GeneralResult<nn::SharedPreparedModel> downcast(const sp<V1_3::IPreparedModel>& preparedModel) {
-    if (preparedModel == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "preparedModel is nullptr";
-    }
-    if (preparedModel->isRemote()) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Cannot convert remote models";
-    }
-
-    // This static_cast is safe because adapter::PreparedModel is the only class that implements
-    // the IPreparedModel interface in the adapter service code.
-    const auto* casted = static_cast<const PreparedModel*>(preparedModel.get());
-    return casted->getUnderlyingPreparedModel();
-}
-
-nn::GeneralResult<std::vector<nn::SharedPreparedModel>> downcastAll(
-        const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels) {
-    std::vector<nn::SharedPreparedModel> canonical;
-    canonical.reserve(preparedModels.size());
-    for (const auto& preparedModel : preparedModels) {
-        canonical.push_back(NN_TRY(downcast(preparedModel)));
-    }
-    return canonical;
-}
-
-nn::GeneralResult<std::pair<sp<V1_3::IBuffer>, uint32_t>> allocate(
-        const nn::SharedDevice& device, const V1_3::BufferDesc& desc,
-        const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels,
-        const hidl_vec<V1_3::BufferRole>& inputRoles,
-        const hidl_vec<V1_3::BufferRole>& outputRoles) {
-    auto nnDesc = NN_TRY(convertInput(desc));
-    auto nnPreparedModels = NN_TRY(downcastAll(preparedModels));
-    auto nnInputRoles = NN_TRY(convertInput(inputRoles));
-    auto nnOutputRoles = NN_TRY(convertInput(outputRoles));
-
-    auto buffer = NN_TRY(device->allocate(nnDesc, nnPreparedModels, nnInputRoles, nnOutputRoles));
-
-    const nn::Request::MemoryDomainToken token = buffer->getToken();
-    auto hidlBuffer = sp<Buffer>::make(std::move(buffer));
-    return std::make_pair(std::move(hidlBuffer), static_cast<uint32_t>(token));
-}
-
-}  // namespace
-
-Device::Device(nn::SharedDevice device, Executor executor)
-    : kDevice(std::move(device)), kExecutor(std::move(executor)) {
-    CHECK(kDevice != nullptr);
-    CHECK(kExecutor != nullptr);
-}
-
-Return<void> Device::getCapabilities(getCapabilities_cb cb) {
-    const auto capabilities = V1_0::utils::convert(kDevice->getCapabilities()).value();
-    cb(V1_0::ErrorStatus::NONE, capabilities);
-    return Void();
-}
-
-Return<void> Device::getCapabilities_1_1(getCapabilities_1_1_cb cb) {
-    const auto capabilities = V1_1::utils::convert(kDevice->getCapabilities()).value();
-    cb(V1_0::ErrorStatus::NONE, capabilities);
-    return Void();
-}
-
-Return<void> Device::getCapabilities_1_2(getCapabilities_1_2_cb cb) {
-    const auto capabilities = V1_2::utils::convert(kDevice->getCapabilities()).value();
-    cb(V1_0::ErrorStatus::NONE, capabilities);
-    return Void();
-}
-
-Return<void> Device::getCapabilities_1_3(getCapabilities_1_3_cb cb) {
-    const auto capabilities = V1_3::utils::convert(kDevice->getCapabilities()).value();
-    cb(V1_3::ErrorStatus::NONE, capabilities);
-    return Void();
-}
-
-Return<void> Device::getVersionString(getVersionString_cb cb) {
-    cb(V1_0::ErrorStatus::NONE, kDevice->getVersionString());
-    return Void();
-}
-
-Return<void> Device::getType(getType_cb cb) {
-    const auto maybeDeviceType = V1_2::utils::convert(kDevice->getType());
-    if (!maybeDeviceType.has_value()) {
-        const auto& [message, code] = maybeDeviceType.error();
-        LOG(ERROR) << "adapter::Device::getType failed with " << code << ": " << message;
-        cb(V1_2::utils::convert(code).value(), {});
-    } else {
-        cb(V1_0::ErrorStatus::NONE, maybeDeviceType.value());
-    }
-    return Void();
-}
-
-Return<void> Device::getSupportedExtensions(getSupportedExtensions_cb cb) {
-    const auto maybeSupportedExtensions = V1_2::utils::convert(kDevice->getSupportedExtensions());
-    if (!maybeSupportedExtensions.has_value()) {
-        const auto& [message, code] = maybeSupportedExtensions.error();
-        LOG(ERROR) << "adapter::Device::getSupportedExtensions failed with " << code << ": "
-                   << message;
-        cb(V1_2::utils::convert(code).value(), {});
-    } else {
-        cb(V1_0::ErrorStatus::NONE, maybeSupportedExtensions.value());
-    }
-    return Void();
-}
-
-Return<void> Device::getSupportedOperations(const V1_0::Model& model,
-                                            getSupportedOperations_cb cb) {
-    const auto result = adapter::getSupportedOperations(kDevice, model);
-    if (!result.has_value()) {
-        const auto& [message, code] = result.error();
-        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_0 failed with " << code << ": "
-                   << message;
-        cb(V1_0::utils::convert(code).value(), {});
-    } else {
-        cb(V1_0::ErrorStatus::NONE, result.value());
-    }
-    return Void();
-}
-
-Return<void> Device::getSupportedOperations_1_1(const V1_1::Model& model,
-                                                getSupportedOperations_1_1_cb cb) {
-    const auto result = adapter::getSupportedOperations(kDevice, model);
-    if (!result.has_value()) {
-        const auto& [message, code] = result.error();
-        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_1 failed with " << code << ": "
-                   << message;
-        cb(V1_1::utils::convert(code).value(), {});
-    } else {
-        cb(V1_0::ErrorStatus::NONE, result.value());
-    }
-    return Void();
-}
-
-Return<void> Device::getSupportedOperations_1_2(const V1_2::Model& model,
-                                                getSupportedOperations_1_2_cb cb) {
-    const auto result = adapter::getSupportedOperations(kDevice, model);
-    if (!result.has_value()) {
-        const auto& [message, code] = result.error();
-        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_2 failed with " << code << ": "
-                   << message;
-        cb(V1_2::utils::convert(code).value(), {});
-    } else {
-        cb(V1_0::ErrorStatus::NONE, result.value());
-    }
-    return Void();
-}
-
-Return<void> Device::getSupportedOperations_1_3(const V1_3::Model& model,
-                                                getSupportedOperations_1_3_cb cb) {
-    const auto result = adapter::getSupportedOperations(kDevice, model);
-    if (!result.has_value()) {
-        const auto& [message, code] = result.error();
-        LOG(ERROR) << "adapter::Device::getSupportedOperations_1_3 failed with " << code << ": "
-                   << message;
-        cb(V1_3::utils::convert(code).value(), {});
-    } else {
-        cb(V1_3::ErrorStatus::NONE, result.value());
-    }
-    return Void();
-}
-
-Return<void> Device::getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) {
-    const auto [numModelCache, numDataCache] = kDevice->getNumberOfCacheFilesNeeded();
-    cb(V1_0::ErrorStatus::NONE, numModelCache, numDataCache);
-    return Void();
-}
-
-Return<V1_0::ErrorStatus> Device::prepareModel(const V1_0::Model& model,
-                                               const sp<V1_0::IPreparedModelCallback>& callback) {
-    auto result = adapter::prepareModel(kDevice, kExecutor, model, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::Device::prepareModel failed with " << code << ": " << message;
-        notify(callback.get(), code, nullptr);
-        return V1_0::utils::convert(code).value();
-    }
-    return V1_0::ErrorStatus::NONE;
-}
-
-Return<V1_0::ErrorStatus> Device::prepareModel_1_1(
-        const V1_1::Model& model, V1_1::ExecutionPreference preference,
-        const sp<V1_0::IPreparedModelCallback>& callback) {
-    auto result = adapter::prepareModel_1_1(kDevice, kExecutor, model, preference, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::Device::prepareModel_1_1 failed with " << code << ": " << message;
-        notify(callback.get(), code, nullptr);
-        return V1_1::utils::convert(code).value();
-    }
-    return V1_0::ErrorStatus::NONE;
-}
-
-Return<V1_0::ErrorStatus> Device::prepareModel_1_2(
-        const V1_2::Model& model, V1_1::ExecutionPreference preference,
-        const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
-        const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) {
-    auto result = adapter::prepareModel_1_2(kDevice, kExecutor, model, preference, modelCache,
-                                            dataCache, token, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::Device::prepareModel_1_2 failed with " << code << ": " << message;
-        notify(callback.get(), code, nullptr);
-        return V1_2::utils::convert(code).value();
-    }
-    return V1_0::ErrorStatus::NONE;
-}
-
-Return<V1_3::ErrorStatus> Device::prepareModel_1_3(
-        const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority,
-        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
-        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
-        const sp<V1_3::IPreparedModelCallback>& callback) {
-    auto result = adapter::prepareModel_1_3(kDevice, kExecutor, model, preference, priority,
-                                            deadline, modelCache, dataCache, token, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::Device::prepareModel_1_3 failed with " << code << ": " << message;
-        notify(callback.get(), code, nullptr);
-        return V1_3::utils::convert(code).value();
-    }
-    return V1_3::ErrorStatus::NONE;
-}
-
-Return<V1_0::ErrorStatus> Device::prepareModelFromCache(
-        const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
-        const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) {
-    auto result = adapter::prepareModelFromCache(kDevice, kExecutor, modelCache, dataCache, token,
-                                                 callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::Device::prepareModelFromCache failed with " << code << ": "
-                   << message;
-        notify(callback.get(), code, nullptr);
-        return V1_2::utils::convert(code).value();
-    }
-    return V1_0::ErrorStatus::NONE;
-}
-
-Return<V1_3::ErrorStatus> Device::prepareModelFromCache_1_3(
-        const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
-        const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
-        const sp<V1_3::IPreparedModelCallback>& callback) {
-    auto result = adapter::prepareModelFromCache_1_3(kDevice, kExecutor, deadline, modelCache,
-                                                     dataCache, token, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::Device::prepareModelFromCache_1_3 failed with " << code << ": "
-                   << message;
-        notify(callback.get(), code, nullptr);
-        return V1_3::utils::convert(code).value();
-    }
-    return V1_3::ErrorStatus::NONE;
-}
-
-Return<V1_0::DeviceStatus> Device::getStatus() {
-    return V1_0::DeviceStatus::AVAILABLE;
-}
-
-Return<void> Device::allocate(const V1_3::BufferDesc& desc,
-                              const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels,
-                              const hidl_vec<V1_3::BufferRole>& inputRoles,
-                              const hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) {
-    auto result = adapter::allocate(kDevice, desc, preparedModels, inputRoles, outputRoles);
-    if (!result.has_value()) {
-        const auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::Device::allocate failed with " << code << ": " << message;
-        cb(V1_3::utils::convert(code).value(), nullptr, /*token=*/0);
-        return Void();
-    }
-    auto [buffer, token] = std::move(result).value();
-    cb(V1_3::ErrorStatus::NONE, buffer, token);
-    return Void();
-}
-
-}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/src/PreparedModel.cpp
deleted file mode 100644
index a14e782..0000000
--- a/neuralnetworks/utils/adapter/src/PreparedModel.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "PreparedModel.h"
-
-#include "Burst.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.2/IBurstCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.2/types.h>
-#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.3/types.h>
-#include <hwbinder/IPCThreadState.h>
-#include <nnapi/IPreparedModel.h>
-#include <nnapi/TypeUtils.h>
-#include <nnapi/Types.h>
-#include <nnapi/Validation.h>
-#include <nnapi/hal/1.0/Utils.h>
-#include <nnapi/hal/1.2/Utils.h>
-#include <nnapi/hal/1.3/Conversions.h>
-#include <nnapi/hal/1.3/Utils.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <thread>
-
-// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
-// lifetimes across processes and for protecting asynchronous calls across HIDL.
-
-namespace android::hardware::neuralnetworks::adapter {
-namespace {
-
-template <typename Type>
-auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
-    auto result = nn::convert(object);
-    if (!result.has_value()) {
-        result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
-    }
-    return result;
-}
-
-nn::GeneralResult<nn::Version> validateRequestForModel(const nn::Request& request,
-                                                       const nn::Model& model) {
-    nn::GeneralResult<nn::Version> version = nn::validateRequestForModel(request, model);
-    if (!version.ok()) {
-        version.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
-    }
-    return version;
-}
-
-class FencedExecutionCallback final : public V1_3::IFencedExecutionCallback {
-  public:
-    explicit FencedExecutionCallback(const nn::ExecuteFencedInfoCallback& callback)
-        : kCallback(callback) {
-        CHECK(callback != nullptr);
-    }
-
-    Return<void> getExecutionInfo(getExecutionInfo_cb cb) override {
-        const auto result = kCallback();
-        if (!result.has_value()) {
-            const auto& [message, code] = result.error();
-            const auto status =
-                    V1_3::utils::convert(code).value_or(V1_3::ErrorStatus::GENERAL_FAILURE);
-            LOG(ERROR) << message;
-            cb(status, V1_2::utils::kNoTiming, V1_2::utils::kNoTiming);
-            return Void();
-        }
-        const auto [timingLaunched, timingFenced] = result.value();
-        const auto hidlTimingLaunched = V1_3::utils::convert(timingLaunched).value();
-        const auto hidlTimingFenced = V1_3::utils::convert(timingFenced).value();
-        cb(V1_3::ErrorStatus::NONE, hidlTimingLaunched, hidlTimingFenced);
-        return Void();
-    }
-
-  private:
-    const nn::ExecuteFencedInfoCallback kCallback;
-};
-
-using ExecutionResult = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
-
-void notify(V1_0::IExecutionCallback* callback, nn::ErrorStatus status,
-            const std::vector<nn::OutputShape>& /*outputShapes*/, const nn::Timing& /*timing*/) {
-    if (callback != nullptr) {
-        const auto hidlStatus = V1_0::utils::convert(status).value();
-        const auto ret = callback->notify(hidlStatus);
-        if (!ret.isOk()) {
-            LOG(ERROR) << "V1_0::IExecutionCallback::notify failed with " << ret.description();
-        }
-    }
-}
-
-void notify(V1_2::IExecutionCallback* callback, nn::ErrorStatus status,
-            const std::vector<nn::OutputShape>& outputShapes, const nn::Timing& timing) {
-    if (callback != nullptr) {
-        const auto hidlStatus = V1_2::utils::convert(status).value();
-        const auto hidlOutputShapes = V1_2::utils::convert(outputShapes).value();
-        const auto hidlTiming = V1_2::utils::convert(timing).value();
-        const auto ret = callback->notify_1_2(hidlStatus, hidlOutputShapes, hidlTiming);
-        if (!ret.isOk()) {
-            LOG(ERROR) << "V1_2::IExecutionCallback::notify_1_2 failed with " << ret.description();
-        }
-    }
-}
-
-void notify(V1_3::IExecutionCallback* callback, nn::ErrorStatus status,
-            const std::vector<nn::OutputShape>& outputShapes, const nn::Timing& timing) {
-    if (callback != nullptr) {
-        const auto hidlStatus = V1_3::utils::convert(status).value();
-        const auto hidlOutputShapes = V1_3::utils::convert(outputShapes).value();
-        const auto hidlTiming = V1_3::utils::convert(timing).value();
-        const auto ret = callback->notify_1_3(hidlStatus, hidlOutputShapes, hidlTiming);
-        if (!ret.isOk()) {
-            LOG(ERROR) << "V1_3::IExecutionCallback::notify_1_3 failed with " << ret.description();
-        }
-    }
-}
-
-template <typename CallbackType>
-void notify(CallbackType* callback, ExecutionResult result) {
-    if (!result.has_value()) {
-        const auto [message, status, outputShapes] = std::move(result).error();
-        LOG(ERROR) << message;
-        notify(callback, status, outputShapes, {});
-    } else {
-        const auto [outputShapes, timing] = std::move(result).value();
-        notify(callback, nn::ErrorStatus::NONE, outputShapes, timing);
-    }
-}
-
-nn::GeneralResult<void> execute(const nn::SharedPreparedModel& preparedModel, uid_t userId,
-                                const Executor& executor, const V1_0::Request& request,
-                                const sp<V1_0::IExecutionCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnRequest = NN_TRY(convertInput(request));
-
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
-    }
-
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
-        auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), userId, {});
-
-    return {};
-}
-
-nn::GeneralResult<void> execute_1_2(const nn::SharedPreparedModel& preparedModel, uid_t userId,
-                                    const Executor& executor, const V1_0::Request& request,
-                                    V1_2::MeasureTiming measure,
-                                    const sp<V1_2::IExecutionCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnRequest = NN_TRY(convertInput(request));
-    const auto nnMeasure = NN_TRY(convertInput(measure));
-
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
-    }
-
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
-        auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), userId, {});
-
-    return {};
-}
-
-nn::GeneralResult<void> execute_1_3(const nn::SharedPreparedModel& preparedModel, uid_t userId,
-                                    const Executor& executor, const V1_3::Request& request,
-                                    V1_2::MeasureTiming measure,
-                                    const V1_3::OptionalTimePoint& deadline,
-                                    const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
-                                    const sp<V1_3::IExecutionCallback>& callback) {
-    if (callback.get() == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
-    }
-
-    auto nnRequest = NN_TRY(convertInput(request));
-    const auto nnMeasure = NN_TRY(convertInput(measure));
-    const auto nnDeadline = NN_TRY(convertInput(deadline));
-    const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
-
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
-    }
-
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
-                 nnLoopTimeoutDuration, callback] {
-        auto result =
-                preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration);
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), userId, nnDeadline);
-
-    return {};
-}
-
-nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> executeSynchronously(
-        const nn::SharedPreparedModel& preparedModel, const V1_0::Request& request,
-        V1_2::MeasureTiming measure) {
-    const auto nnRequest = NN_TRY(convertInput(request));
-    const auto nnMeasure = NN_TRY(convertInput(measure));
-
-    const auto [outputShapes, timing] =
-            NN_TRY(preparedModel->execute(nnRequest, nnMeasure, {}, {}));
-
-    auto hidlOutputShapes = NN_TRY(V1_2::utils::convert(outputShapes));
-    const auto hidlTiming = NN_TRY(V1_2::utils::convert(timing));
-    return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
-}
-
-nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> executeSynchronously_1_3(
-        const nn::SharedPreparedModel& preparedModel, const V1_3::Request& request,
-        V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& deadline,
-        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration) {
-    const auto nnRequest = NN_TRY(convertInput(request));
-    const auto nnMeasure = NN_TRY(convertInput(measure));
-    const auto nnDeadline = NN_TRY(convertInput(deadline));
-    const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
-
-    const auto [outputShapes, timing] =
-            NN_TRY(preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration));
-
-    auto hidlOutputShapes = NN_TRY(V1_3::utils::convert(outputShapes));
-    const auto hidlTiming = NN_TRY(V1_3::utils::convert(timing));
-    return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
-}
-
-nn::GeneralResult<std::vector<nn::SyncFence>> convertSyncFences(
-        const hidl_vec<hidl_handle>& handles) {
-    auto nnHandles = NN_TRY(convertInput(handles));
-    std::vector<nn::SyncFence> syncFences;
-    syncFences.reserve(handles.size());
-    for (auto&& handle : nnHandles) {
-        if (auto syncFence = nn::SyncFence::create(std::move(handle)); !syncFence.ok()) {
-            return nn::error(nn::ErrorStatus::INVALID_ARGUMENT) << std::move(syncFence).error();
-        } else {
-            syncFences.push_back(std::move(syncFence).value());
-        }
-    }
-    return syncFences;
-}
-
-nn::GeneralResult<sp<V1_2::IBurstContext>> configureExecutionBurst(
-        const nn::SharedPreparedModel& preparedModel, const sp<V1_2::IBurstCallback>& callback,
-        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
-        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel) {
-    auto burstExecutor = NN_TRY(preparedModel->configureExecutionBurst());
-    return Burst::create(callback, requestChannel, resultChannel, std::move(burstExecutor),
-                         V1_2::utils::getBurstServerPollingTimeWindow());
-}
-
-nn::GeneralResult<std::pair<hidl_handle, sp<V1_3::IFencedExecutionCallback>>> executeFenced(
-        const nn::SharedPreparedModel& preparedModel, const V1_3::Request& request,
-        const hidl_vec<hidl_handle>& waitFor, V1_2::MeasureTiming measure,
-        const V1_3::OptionalTimePoint& deadline,
-        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
-        const V1_3::OptionalTimeoutDuration& duration) {
-    const auto nnRequest = NN_TRY(convertInput(request));
-    const auto nnWaitFor = NN_TRY(convertSyncFences(waitFor));
-    const auto nnMeasure = NN_TRY(convertInput(measure));
-    const auto nnDeadline = NN_TRY(convertInput(deadline));
-    const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
-    const auto nnDuration = NN_TRY(convertInput(duration));
-
-    auto [syncFence, executeFencedCallback] = NN_TRY(preparedModel->executeFenced(
-            nnRequest, nnWaitFor, nnMeasure, nnDeadline, nnLoopTimeoutDuration, nnDuration));
-
-    auto hidlSyncFence = NN_TRY(V1_3::utils::convert(syncFence.getSharedHandle()));
-    auto hidlExecuteFencedCallback = sp<FencedExecutionCallback>::make(executeFencedCallback);
-    return std::make_pair(std::move(hidlSyncFence), std::move(hidlExecuteFencedCallback));
-}
-
-}  // namespace
-
-PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor, uid_t userId)
-    : kPreparedModel(std::move(preparedModel)), kExecutor(std::move(executor)), kUserId(userId) {
-    CHECK(kPreparedModel != nullptr);
-    CHECK(kExecutor != nullptr);
-}
-
-nn::SharedPreparedModel PreparedModel::getUnderlyingPreparedModel() const {
-    return kPreparedModel;
-}
-
-Return<V1_0::ErrorStatus> PreparedModel::execute(const V1_0::Request& request,
-                                                 const sp<V1_0::IExecutionCallback>& callback) {
-    auto result = adapter::execute(kPreparedModel, kUserId, kExecutor, request, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::PreparedModel::execute failed with " << code << ": " << message;
-        notify(callback.get(), code, {}, {});
-        return V1_0::utils::convert(code).value();
-    }
-    return V1_0::ErrorStatus::NONE;
-}
-
-Return<V1_0::ErrorStatus> PreparedModel::execute_1_2(const V1_0::Request& request,
-                                                     V1_2::MeasureTiming measure,
-                                                     const sp<V1_2::IExecutionCallback>& callback) {
-    auto result =
-            adapter::execute_1_2(kPreparedModel, kUserId, kExecutor, request, measure, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::PreparedModel::execute_1_2 failed with " << code << ": " << message;
-        notify(callback.get(), code, {}, {});
-        return V1_2::utils::convert(code).value();
-    }
-    return V1_0::ErrorStatus::NONE;
-}
-
-Return<V1_3::ErrorStatus> PreparedModel::execute_1_3(
-        const V1_3::Request& request, V1_2::MeasureTiming measure,
-        const V1_3::OptionalTimePoint& deadline,
-        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
-        const sp<V1_3::IExecutionCallback>& callback) {
-    auto result = adapter::execute_1_3(kPreparedModel, kUserId, kExecutor, request, measure,
-                                       deadline, loopTimeoutDuration, callback);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::PreparedModel::execute_1_3 failed with " << code << ": " << message;
-        notify(callback.get(), code, {}, {});
-        return V1_3::utils::convert(code).value();
-    }
-    return V1_3::ErrorStatus::NONE;
-}
-
-Return<void> PreparedModel::executeSynchronously(const V1_0::Request& request,
-                                                 V1_2::MeasureTiming measure,
-                                                 executeSynchronously_cb cb) {
-    auto result = adapter::executeSynchronously(kPreparedModel, request, measure);
-    if (!result.has_value()) {
-        auto [message, code, outputShapes] = std::move(result).error();
-        LOG(ERROR) << "adapter::PreparedModel::executeSynchronously failed with " << code << ": "
-                   << message;
-        cb(V1_2::utils::convert(code).value(), V1_2::utils::convert(outputShapes).value(),
-           V1_2::utils::kNoTiming);
-        return Void();
-    }
-    auto [outputShapes, timing] = std::move(result).value();
-    cb(V1_0::ErrorStatus::NONE, outputShapes, timing);
-    return Void();
-}
-
-Return<void> PreparedModel::executeSynchronously_1_3(
-        const V1_3::Request& request, V1_2::MeasureTiming measure,
-        const V1_3::OptionalTimePoint& deadline,
-        const V1_3::OptionalTimeoutDuration& loopTimeoutDuration, executeSynchronously_1_3_cb cb) {
-    auto result = adapter::executeSynchronously_1_3(kPreparedModel, request, measure, deadline,
-                                                    loopTimeoutDuration);
-    if (!result.has_value()) {
-        auto [message, code, outputShapes] = std::move(result).error();
-        LOG(ERROR) << "adapter::PreparedModel::executeSynchronously_1_3 failed with " << code
-                   << ": " << message;
-        cb(V1_3::utils::convert(code).value(), V1_3::utils::convert(outputShapes).value(),
-           V1_2::utils::kNoTiming);
-        return Void();
-    }
-    auto [outputShapes, timing] = std::move(result).value();
-    cb(V1_3::ErrorStatus::NONE, outputShapes, timing);
-    return Void();
-}
-
-Return<void> PreparedModel::configureExecutionBurst(
-        const sp<V1_2::IBurstCallback>& callback,
-        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
-        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
-        configureExecutionBurst_cb cb) {
-    auto result = adapter::configureExecutionBurst(kPreparedModel, callback, requestChannel,
-                                                   resultChannel);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::PreparedModel::configureExecutionBurst failed with " << code << ": "
-                   << message;
-        cb(V1_2::utils::convert(code).value(), nullptr);
-        return Void();
-    }
-    auto burstContext = std::move(result).value();
-    cb(V1_0::ErrorStatus::NONE, std::move(burstContext));
-    return Void();
-}
-
-Return<void> PreparedModel::executeFenced(const V1_3::Request& request,
-                                          const hidl_vec<hidl_handle>& waitFor,
-                                          V1_2::MeasureTiming measure,
-                                          const V1_3::OptionalTimePoint& deadline,
-                                          const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
-                                          const V1_3::OptionalTimeoutDuration& duration,
-                                          executeFenced_cb callback) {
-    auto result = adapter::executeFenced(kPreparedModel, request, waitFor, measure, deadline,
-                                         loopTimeoutDuration, duration);
-    if (!result.has_value()) {
-        auto [message, code] = std::move(result).error();
-        LOG(ERROR) << "adapter::PreparedModel::executeFenced failed with " << code << ": "
-                   << message;
-        callback(V1_3::utils::convert(code).value(), {}, nullptr);
-        return Void();
-    }
-    auto [syncFence, executeFencedCallback] = std::move(result).value();
-    callback(V1_3::ErrorStatus::NONE, syncFence, executeFencedCallback);
-    return Void();
-}
-
-}  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
index 39927a3..bfba24f 100644
--- a/neuralnetworks/utils/common/Android.bp
+++ b/neuralnetworks/utils/common/Android.bp
@@ -39,20 +39,12 @@
     srcs: ["test/*.cpp"],
     static_libs: [
         "libgmock",
-        "libneuralnetworks_common",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
     ],
     shared_libs: [
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
         "libbase",
         "libcutils",
-        "libfmq",
-        "libhidlbase",
-        "libhidlmemory",
-        "liblog",
-        "libutils",
     ],
     target: {
         android: {
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
index e86edda..1f1245f 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
@@ -33,12 +33,15 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 };
 
 }  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
index 5e62b9a..9582873 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
@@ -52,8 +52,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache,
-            const nn::CacheToken& token) const override;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
index de30aae..3f1f290 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
@@ -31,18 +31,23 @@
   public:
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
             const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
             const nn::OptionalDuration& loopTimeoutDuration,
-            const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+            const nn::OptionalDuration& timeoutDurationAfterFence,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
 
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
index fde2486..129431f 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
@@ -48,18 +48,23 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
   private:
     bool isValidInternal() const EXCLUDES(mMutex);
     nn::GeneralResult<nn::SharedExecution> createReusableExecutionInternal(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const;
 
     const Factory kMakeBurst;
     mutable std::mutex mMutex;
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
index 84ae799..267d634 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
@@ -65,8 +65,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache,
-            const nn::CacheToken& token) const override;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
@@ -83,7 +84,9 @@
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelInternal(
             const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const;
     nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCacheInternal(
             nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
             const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
index 86533ed..bbfc220 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
@@ -49,18 +49,23 @@
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalTimePoint& deadline,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
             const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
             const nn::OptionalDuration& loopTimeoutDuration,
-            const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+            const nn::OptionalDuration& timeoutDurationAfterFence,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedExecution> createReusableExecution(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const override;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& hints,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
 
     nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
 
@@ -70,7 +75,9 @@
     bool isValidInternal() const EXCLUDES(mMutex);
     nn::GeneralResult<nn::SharedExecution> createReusableExecutionInternal(
             const nn::Request& request, nn::MeasureTiming measure,
-            const nn::OptionalDuration& loopTimeoutDuration) const;
+            const nn::OptionalDuration& loopTimeoutDuration,
+            const std::vector<nn::TokenValuePair>& metaData,
+            const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const;
     nn::GeneralResult<nn::SharedBurst> configureExecutionBurstInternal() const;
 
     const Factory kMakePreparedModel;
diff --git a/neuralnetworks/utils/common/src/InvalidBurst.cpp b/neuralnetworks/utils/common/src/InvalidBurst.cpp
index 0191533..3fdfb5c 100644
--- a/neuralnetworks/utils/common/src/InvalidBurst.cpp
+++ b/neuralnetworks/utils/common/src/InvalidBurst.cpp
@@ -34,13 +34,17 @@
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> InvalidBurst::execute(
         const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
         const nn::OptionalTimePoint& /*deadline*/,
-        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR() << "InvalidBurst";
 }
 
 nn::GeneralResult<nn::SharedExecution> InvalidBurst::createReusableExecution(
         const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
-        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR() << "InvalidBurst";
 }
 
diff --git a/neuralnetworks/utils/common/src/InvalidDevice.cpp b/neuralnetworks/utils/common/src/InvalidDevice.cpp
index 535ccb4..c8cc287 100644
--- a/neuralnetworks/utils/common/src/InvalidDevice.cpp
+++ b/neuralnetworks/utils/common/src/InvalidDevice.cpp
@@ -84,7 +84,9 @@
         const nn::Model& /*model*/, nn::ExecutionPreference /*preference*/,
         nn::Priority /*priority*/, nn::OptionalTimePoint /*deadline*/,
         const std::vector<nn::SharedHandle>& /*modelCache*/,
-        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR() << "InvalidDevice";
 }
 
diff --git a/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp b/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
index 8195462..f6f978d 100644
--- a/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
+++ b/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
@@ -27,9 +27,12 @@
 namespace android::hardware::neuralnetworks::utils {
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
-InvalidPreparedModel::execute(const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
-                              const nn::OptionalTimePoint& /*deadline*/,
-                              const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+InvalidPreparedModel::execute(
+        const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
+        const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR() << "InvalidPreparedModel";
 }
 
@@ -38,13 +41,17 @@
         const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
         nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
         const nn::OptionalDuration& /*loopTimeoutDuration*/,
-        const nn::OptionalDuration& /*timeoutDurationAfterFence*/) const {
+        const nn::OptionalDuration& /*timeoutDurationAfterFence*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR() << "InvalidPreparedModel";
 }
 
 nn::GeneralResult<nn::SharedExecution> InvalidPreparedModel::createReusableExecution(
         const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
-        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+        const nn::OptionalDuration& /*loopTimeoutDuration*/,
+        const std::vector<nn::TokenValuePair>& /*hints*/,
+        const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
     return NN_ERROR() << "InvalidPreparedModel";
 }
 
diff --git a/neuralnetworks/utils/common/src/ResilientBurst.cpp b/neuralnetworks/utils/common/src/ResilientBurst.cpp
index 79cbe39..bf7a8ea 100644
--- a/neuralnetworks/utils/common/src/ResilientBurst.cpp
+++ b/neuralnetworks/utils/common/src/ResilientBurst.cpp
@@ -105,37 +105,49 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> ResilientBurst::execute(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalTimePoint& deadline,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
-    const auto fn = [&request, measure, deadline, loopTimeoutDuration](const nn::IBurst& burst) {
-        return burst.execute(request, measure, deadline, loopTimeoutDuration);
+        const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+    const auto fn = [&request, measure, deadline, loopTimeoutDuration, &hints,
+                     &extensionNameToPrefix](const nn::IBurst& burst) {
+        return burst.execute(request, measure, deadline, loopTimeoutDuration, hints,
+                             extensionNameToPrefix);
     };
     return protect(*this, fn);
 }
 
 nn::GeneralResult<nn::SharedExecution> ResilientBurst::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
 #if 0
     auto self = shared_from_this();
-    ResilientExecution::Factory makeExecution =
-            [burst = std::move(self), request, measure, loopTimeoutDuration] {
-        return burst->createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+    ResilientExecution::Factory makeExecution = [burst = std::move(self), request, measure,
+                                                 loopTimeoutDuration, &hints,
+                                                 &extensionNameToPrefix] {
+        return burst->createReusableExecutionInternal(request, measure, loopTimeoutDuration, hints,
+                                                      extensionNameToPrefix);
     };
     return ResilientExecution::create(std::move(makeExecution));
 #else
-    return createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+    return createReusableExecutionInternal(request, measure, loopTimeoutDuration, hints,
+                                           extensionNameToPrefix);
 #endif
 }
 
 nn::GeneralResult<nn::SharedExecution> ResilientBurst::createReusableExecutionInternal(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     if (!isValidInternal()) {
         return std::make_shared<const InvalidExecution>();
     }
-    const auto fn = [&request, measure, &loopTimeoutDuration](const nn::IBurst& burst) {
-        return burst.createReusableExecution(request, measure, loopTimeoutDuration);
+    const auto fn = [&request, measure, &loopTimeoutDuration, &hints,
+                     &extensionNameToPrefix](const nn::IBurst& burst) {
+        return burst.createReusableExecution(request, measure, loopTimeoutDuration, hints,
+                                             extensionNameToPrefix);
     };
     return protect(*this, fn);
 }
diff --git a/neuralnetworks/utils/common/src/ResilientDevice.cpp b/neuralnetworks/utils/common/src/ResilientDevice.cpp
index 2023c9a..a5c2640 100644
--- a/neuralnetworks/utils/common/src/ResilientDevice.cpp
+++ b/neuralnetworks/utils/common/src/ResilientDevice.cpp
@@ -179,19 +179,21 @@
 nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModel(
         const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
         nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
 #if 0
     auto self = shared_from_this();
     ResilientPreparedModel::Factory makePreparedModel = [device = std::move(self), model,
                                                          preference, priority, deadline, modelCache,
-                                                         dataCache, token] {
+                                                         dataCache, token, hints, extensionNameToPrefix] {
         return device->prepareModelInternal(model, preference, priority, deadline, modelCache,
-                                            dataCache, token);
+                                            dataCache, token, hints, extensionNameToPrefix);
     };
     return ResilientPreparedModel::create(std::move(makePreparedModel));
 #else
-    return prepareModelInternal(model, preference, priority, deadline, modelCache, dataCache,
-                                token);
+    return prepareModelInternal(model, preference, priority, deadline, modelCache, dataCache, token,
+                                hints, extensionNameToPrefix);
 #endif
 }
 
@@ -234,14 +236,16 @@
 nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelInternal(
         const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
         nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
-        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     if (!isValidInternal()) {
         return std::make_shared<const InvalidPreparedModel>();
     }
-    const auto fn = [&model, preference, priority, &deadline, &modelCache, &dataCache,
-                     &token](const nn::IDevice& device) {
+    const auto fn = [&model, preference, priority, &deadline, &modelCache, &dataCache, &token,
+                     &hints, &extensionNameToPrefix](const nn::IDevice& device) {
         return device.prepareModel(model, preference, priority, deadline, modelCache, dataCache,
-                                   token);
+                                   token, hints, extensionNameToPrefix);
     };
     return protect(*this, fn, /*blocking=*/false);
 }
diff --git a/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
index 1ae19bc..b5843c0 100644
--- a/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
+++ b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
@@ -104,43 +104,53 @@
 }
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
-ResilientPreparedModel::execute(const nn::Request& request, nn::MeasureTiming measure,
-                                const nn::OptionalTimePoint& deadline,
-                                const nn::OptionalDuration& loopTimeoutDuration) const {
-    const auto fn = [&request, measure, &deadline,
-                     &loopTimeoutDuration](const nn::IPreparedModel& preparedModel) {
-        return preparedModel.execute(request, measure, deadline, loopTimeoutDuration);
+ResilientPreparedModel::execute(
+        const nn::Request& request, nn::MeasureTiming measure,
+        const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+    const auto fn = [&request, measure, &deadline, &loopTimeoutDuration, &hints,
+                     &extensionNameToPrefix](const nn::IPreparedModel& preparedModel) {
+        return preparedModel.execute(request, measure, deadline, loopTimeoutDuration, hints,
+                                     extensionNameToPrefix);
     };
     return protect(*this, fn);
 }
 
 nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-ResilientPreparedModel::executeFenced(const nn::Request& request,
-                                      const std::vector<nn::SyncFence>& waitFor,
-                                      nn::MeasureTiming measure,
-                                      const nn::OptionalTimePoint& deadline,
-                                      const nn::OptionalDuration& loopTimeoutDuration,
-                                      const nn::OptionalDuration& timeoutDurationAfterFence) const {
+ResilientPreparedModel::executeFenced(
+        const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+        nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const nn::OptionalDuration& timeoutDurationAfterFence,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     const auto fn = [&request, &waitFor, measure, &deadline, &loopTimeoutDuration,
-                     &timeoutDurationAfterFence](const nn::IPreparedModel& preparedModel) {
+                     &timeoutDurationAfterFence, &hints,
+                     &extensionNameToPrefix](const nn::IPreparedModel& preparedModel) {
         return preparedModel.executeFenced(request, waitFor, measure, deadline, loopTimeoutDuration,
-                                           timeoutDurationAfterFence);
+                                           timeoutDurationAfterFence, hints, extensionNameToPrefix);
     };
     return protect(*this, fn);
 }
 
 nn::GeneralResult<nn::SharedExecution> ResilientPreparedModel::createReusableExecution(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
 #if 0
     auto self = shared_from_this();
-    ResilientExecution::Factory makeExecution =
-            [preparedModel = std::move(self), request, measure, loopTimeoutDuration] {
-        return preparedModel->createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+    ResilientExecution::Factory makeExecution = [preparedModel = std::move(self), request, measure,
+                                                 loopTimeoutDuration, hints,
+                                                 extensionNameToPrefix] {
+        return preparedModel->createReusableExecutionInternal(request, measure, loopTimeoutDuration,
+                                                              hints, extensionNameToPrefix);
     };
     return ResilientExecution::create(std::move(makeExecution));
 #else
-    return createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+    return createReusableExecutionInternal(request, measure, loopTimeoutDuration, hints,
+                                           extensionNameToPrefix);
 #endif
 }
 
@@ -159,13 +169,16 @@
 
 nn::GeneralResult<nn::SharedExecution> ResilientPreparedModel::createReusableExecutionInternal(
         const nn::Request& request, nn::MeasureTiming measure,
-        const nn::OptionalDuration& loopTimeoutDuration) const {
+        const nn::OptionalDuration& loopTimeoutDuration,
+        const std::vector<nn::TokenValuePair>& hints,
+        const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
     if (!isValidInternal()) {
         return std::make_shared<const InvalidExecution>();
     }
-    const auto fn = [&request, measure,
-                     &loopTimeoutDuration](const nn::IPreparedModel& preparedModel) {
-        return preparedModel.createReusableExecution(request, measure, loopTimeoutDuration);
+    const auto fn = [&request, measure, &loopTimeoutDuration, &hints,
+                     &extensionNameToPrefix](const nn::IPreparedModel& preparedModel) {
+        return preparedModel.createReusableExecution(request, measure, loopTimeoutDuration, hints,
+                                                     extensionNameToPrefix);
     };
     return protect(*this, fn);
 }
diff --git a/neuralnetworks/utils/common/test/MockDevice.h b/neuralnetworks/utils/common/test/MockDevice.h
index a9428bc..a0fc5c3 100644
--- a/neuralnetworks/utils/common/test/MockDevice.h
+++ b/neuralnetworks/utils/common/test/MockDevice.h
@@ -39,7 +39,9 @@
     MOCK_METHOD(GeneralResult<SharedPreparedModel>, prepareModel,
                 (const Model& model, ExecutionPreference preference, Priority priority,
                  OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache,
-                 const std::vector<SharedHandle>& dataCache, const CacheToken& token),
+                 const std::vector<SharedHandle>& dataCache, const CacheToken& token,
+                 const std::vector<TokenValuePair>& hints,
+                 const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
                 (const, override));
     MOCK_METHOD(GeneralResult<SharedPreparedModel>, prepareModelFromCache,
                 (OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache,
diff --git a/neuralnetworks/utils/common/test/MockPreparedModel.h b/neuralnetworks/utils/common/test/MockPreparedModel.h
index c8ce006..b8613b2 100644
--- a/neuralnetworks/utils/common/test/MockPreparedModel.h
+++ b/neuralnetworks/utils/common/test/MockPreparedModel.h
@@ -27,17 +27,23 @@
   public:
     MOCK_METHOD((ExecutionResult<std::pair<std::vector<OutputShape>, Timing>>), execute,
                 (const Request& request, MeasureTiming measure, const OptionalTimePoint& deadline,
-                 const OptionalDuration& loopTimeoutDuration),
+                 const OptionalDuration& loopTimeoutDuration,
+                 const std::vector<TokenValuePair>& hints,
+                 const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
                 (const, override));
     MOCK_METHOD((GeneralResult<std::pair<SyncFence, ExecuteFencedInfoCallback>>), executeFenced,
                 (const Request& request, const std::vector<SyncFence>& waitFor,
                  MeasureTiming measure, const OptionalTimePoint& deadline,
                  const OptionalDuration& loopTimeoutDuration,
-                 const OptionalDuration& timeoutDurationAfterFence),
+                 const OptionalDuration& timeoutDurationAfterFence,
+                 const std::vector<TokenValuePair>& hints,
+                 const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
                 (const, override));
     MOCK_METHOD((GeneralResult<SharedExecution>), createReusableExecution,
-                (const nn::Request& request, nn::MeasureTiming measure,
-                 const nn::OptionalDuration& loopTimeoutDuration),
+                (const Request& request, MeasureTiming measure,
+                 const OptionalDuration& loopTimeoutDuration,
+                 const std::vector<TokenValuePair>& hints,
+                 const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
                 (const, override));
     MOCK_METHOD(GeneralResult<SharedBurst>, configureExecutionBurst, (), (const, override));
     MOCK_METHOD(std::any, getUnderlyingResource, (), (const, override));
diff --git a/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp b/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp
index 0488b63..d9b8505 100644
--- a/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp
+++ b/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp
@@ -309,12 +309,12 @@
     // setup call
     const auto [mockDevice, mockDeviceFactory, device] = setup();
     const auto mockPreparedModel = std::make_shared<const nn::MockPreparedModel>();
-    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(Return(mockPreparedModel));
 
     // run test
-    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -324,12 +324,12 @@
 TEST(ResilientDeviceTest, prepareModelError) {
     // setup call
     const auto [mockDevice, mockDeviceFactory, device] = setup();
-    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(kReturnGeneralFailure);
 
     // run test
-    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -339,13 +339,13 @@
 TEST(ResilientDeviceTest, prepareModelDeadObjectFailedRecovery) {
     // setup call
     const auto [mockDevice, mockDeviceFactory, device] = setup();
-    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(kReturnDeadObject);
     EXPECT_CALL(*mockDeviceFactory, Call(false)).Times(1).WillOnce(kReturnGeneralFailure);
 
     // run test
-    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -355,18 +355,18 @@
 TEST(ResilientDeviceTest, prepareModelDeadObjectSuccessfulRecovery) {
     // setup call
     const auto [mockDevice, mockDeviceFactory, device] = setup();
-    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+    EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(kReturnDeadObject);
     const auto recoveredMockDevice = createConfiguredMockDevice();
     const auto mockPreparedModel = std::make_shared<const nn::MockPreparedModel>();
-    EXPECT_CALL(*recoveredMockDevice, prepareModel(_, _, _, _, _, _, _))
+    EXPECT_CALL(*recoveredMockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(Return(mockPreparedModel));
     EXPECT_CALL(*mockDeviceFactory, Call(false)).Times(1).WillOnce(Return(recoveredMockDevice));
 
     // run test
-    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+    const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -679,7 +679,7 @@
     device->recover(mockDevice.get(), /*blocking=*/false);
 
     // run test
-    auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+    auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
diff --git a/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp b/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp
index d396ca8..276bfba 100644
--- a/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp
+++ b/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp
@@ -104,12 +104,12 @@
 TEST(ResilientPreparedModelTest, execute) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _))
+    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _))
             .Times(1)
             .WillOnce(Return(kNoExecutionError));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -119,10 +119,12 @@
 TEST(ResilientPreparedModelTest, executeError) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _)).Times(1).WillOnce(kReturnGeneralFailure);
+    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _))
+            .Times(1)
+            .WillOnce(kReturnGeneralFailure);
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -132,12 +134,12 @@
 TEST(ResilientPreparedModelTest, executeDeadObjectFailedRecovery) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
+    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
     constexpr auto ret = [] { return nn::error(nn::ErrorStatus::GENERAL_FAILURE); };
     EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(ret);
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -147,9 +149,9 @@
 TEST(ResilientPreparedModelTest, executeDeadObjectSuccessfulRecovery) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
+    EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
     const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
-    EXPECT_CALL(*recoveredMockPreparedModel, execute(_, _, _, _))
+    EXPECT_CALL(*recoveredMockPreparedModel, execute(_, _, _, _, _, _))
             .Times(1)
             .WillOnce(Return(kNoExecutionError));
     EXPECT_CALL(*mockPreparedModelFactory, Call())
@@ -157,7 +159,7 @@
             .WillOnce(Return(recoveredMockPreparedModel));
 
     // run test
-    const auto result = preparedModel->execute({}, {}, {}, {});
+    const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -167,12 +169,12 @@
 TEST(ResilientPreparedModelTest, executeFenced) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(Return(kNoFencedExecutionError));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -182,12 +184,12 @@
 TEST(ResilientPreparedModelTest, executeFencedError) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(kReturnGeneralFailure);
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -197,13 +199,13 @@
 TEST(ResilientPreparedModelTest, executeFencedDeadObjectFailedRecovery) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(kReturnDeadObject);
     EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure);
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
@@ -213,11 +215,11 @@
 TEST(ResilientPreparedModelTest, executeFencedDeadObjectSuccessfulRecovery) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+    EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(kReturnDeadObject);
     const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
-    EXPECT_CALL(*recoveredMockPreparedModel, executeFenced(_, _, _, _, _, _))
+    EXPECT_CALL(*recoveredMockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(Return(kNoFencedExecutionError));
     EXPECT_CALL(*mockPreparedModelFactory, Call())
@@ -225,7 +227,7 @@
             .WillOnce(Return(recoveredMockPreparedModel));
 
     // run test
-    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+    const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -235,12 +237,12 @@
 TEST(ResilientPreparedModelTest, createReusableExecution) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _, _, _))
             .Times(1)
             .WillOnce(Return(kNoCreateReusableExecutionError));
 
     // run test
-    const auto result = preparedModel->createReusableExecution({}, {}, {});
+    const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
 
     // verify result
     ASSERT_TRUE(result.has_value())
@@ -250,12 +252,12 @@
 TEST(ResilientPreparedModelTest, createReusableExecutionError) {
     // setup call
     const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
-    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+    EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _, _, _))
             .Times(1)
             .WillOnce(kReturnGeneralFailure);
 
     // run test
-    const auto result = preparedModel->createReusableExecution({}, {}, {});
+    const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
 
     // verify result
     ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/utils/service/Android.bp b/neuralnetworks/utils/service/Android.bp
index c3272ae..452078b 100644
--- a/neuralnetworks/utils/service/Android.bp
+++ b/neuralnetworks/utils/service/Android.bp
@@ -33,6 +33,10 @@
     local_include_dirs: ["include/nnapi/hal"],
     export_include_dirs: ["include"],
     static_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hardware.neuralnetworks@1.3",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_1_0",
         "neuralnetworks_utils_hal_1_1",
@@ -40,10 +44,4 @@
         "neuralnetworks_utils_hal_1_3",
         "neuralnetworks_utils_hal_common",
     ],
-    shared_libs: [
-        "android.hardware.neuralnetworks@1.0",
-        "android.hardware.neuralnetworks@1.1",
-        "android.hardware.neuralnetworks@1.2",
-        "android.hardware.neuralnetworks@1.3",
-    ],
 }
diff --git a/nfc/OWNERS b/nfc/OWNERS
new file mode 100644
index 0000000..7867204
--- /dev/null
+++ b/nfc/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 48448
+alisher@google.com
+georgekgchang@google.com
+jackcwyu@google.com
+
+
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
new file mode 100644
index 0000000..d390c7e
--- /dev/null
+++ b/nfc/aidl/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+aidl_interface {
+    name: "android.hardware.nfc",
+    vendor_available: true,
+    srcs: ["android/hardware/nfc/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+            enabled: false,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/nfc/aidl/TEST_MAPPING b/nfc/aidl/TEST_MAPPING
new file mode 100644
index 0000000..3a10084
--- /dev/null
+++ b/nfc/aidl/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsAidlHalNfcTargetTest"
+    }
+  ]
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
new file mode 100644
index 0000000..7a0ae54
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.nfc;
+@VintfStability
+interface INfc {
+  void open(in android.hardware.nfc.INfcClientCallback clientCallback);
+  void close(in android.hardware.nfc.NfcCloseType type);
+  void coreInitialized();
+  void factoryReset();
+  android.hardware.nfc.NfcConfig getConfig();
+  void powerCycle();
+  void preDiscover();
+  int write(in byte[] data);
+  void setEnableVerboseLogging(in boolean enable);
+  boolean isVerboseLoggingEnabled();
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfcClientCallback.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfcClientCallback.aidl
new file mode 100644
index 0000000..8150e81
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfcClientCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.nfc;
+@VintfStability
+interface INfcClientCallback {
+  void sendData(in byte[] data);
+  void sendEvent(in android.hardware.nfc.NfcEvent event, in android.hardware.nfc.NfcStatus status);
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcCloseType.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcCloseType.aidl
new file mode 100644
index 0000000..7d44d48
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcCloseType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.nfc;
+@Backing(type="int") @VintfStability
+enum NfcCloseType {
+  DISABLE = 0,
+  HOST_SWITCHED_OFF = 1,
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
new file mode 100644
index 0000000..92e0a9a
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.nfc;
+@VintfStability
+parcelable NfcConfig {
+  boolean nfaPollBailOutMode;
+  android.hardware.nfc.PresenceCheckAlgorithm presenceCheckAlgorithm;
+  android.hardware.nfc.ProtocolDiscoveryConfig nfaProprietaryCfg;
+  byte defaultOffHostRoute;
+  byte defaultOffHostRouteFelica;
+  byte defaultSystemCodeRoute;
+  byte defaultSystemCodePowerState;
+  byte defaultRoute;
+  byte offHostESEPipeId;
+  byte offHostSIMPipeId;
+  int maxIsoDepTransceiveLength;
+  byte[] hostAllowlist;
+  byte[] offHostRouteUicc;
+  byte[] offHostRouteEse;
+  byte defaultIsoDepRoute;
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
new file mode 100644
index 0000000..dda258e
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.nfc;
+@Backing(type="int") @VintfStability
+enum NfcEvent {
+  OPEN_CPLT = 0,
+  CLOSE_CPLT = 1,
+  POST_INIT_CPLT = 2,
+  PRE_DISCOVER_CPLT = 3,
+  HCI_NETWORK_RESET = 4,
+  ERROR = 5,
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcStatus.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcStatus.aidl
new file mode 100644
index 0000000..2632480
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcStatus.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.nfc;
+@Backing(type="int") @VintfStability
+enum NfcStatus {
+  OK = 0,
+  FAILED = 1,
+  ERR_TRANSPORT = 2,
+  ERR_CMD_TIMEOUT = 3,
+  REFUSED = 4,
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/PresenceCheckAlgorithm.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/PresenceCheckAlgorithm.aidl
new file mode 100644
index 0000000..9a9be21
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/PresenceCheckAlgorithm.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.nfc;
+@Backing(type="byte") @VintfStability
+enum PresenceCheckAlgorithm {
+  DEFAULT = 0,
+  I_BLOCK = 1,
+  ISO_DEP_NAK = 2,
+}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/ProtocolDiscoveryConfig.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
new file mode 100644
index 0000000..021dfe2
--- /dev/null
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.nfc;
+@VintfStability
+parcelable ProtocolDiscoveryConfig {
+  byte protocol18092Active;
+  byte protocolBPrime;
+  byte protocolDual;
+  byte protocol15693;
+  byte protocolKovio;
+  byte protocolMifare;
+  byte discoveryPollKovio;
+  byte discoveryPollBPrime;
+  byte discoveryListenBPrime;
+}
diff --git a/nfc/aidl/android/hardware/nfc/INfc.aidl b/nfc/aidl/android/hardware/nfc/INfc.aidl
new file mode 100644
index 0000000..662f8d4
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/INfc.aidl
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+import android.hardware.nfc.INfcClientCallback;
+import android.hardware.nfc.NfcCloseType;
+import android.hardware.nfc.NfcConfig;
+import android.hardware.nfc.NfcStatus;
+
+@VintfStability
+interface INfc {
+    /**
+     * Opens the NFC controller device and performs initialization.
+     * This may include patch download and other vendor-specific initialization.
+     *
+     * If open completes successfully, the controller must be ready to perform NCI
+     * initialization - ie accept CORE_RESET and subsequent commands through the write()
+     * call.
+     *
+     * Returns ok() if initialization starts successfully.
+     * If open() returns ok(), the NCI stack must wait for a NfcEvent.OPEN_CPLT
+     * callback before continuing.
+     * If a NfcEvent.OPEN_CPLT callback received with status NfcStatus::OK, the controller
+     * must be ready to perform  NCI initialization - ie accept CORE_RESET and subsequent
+     * commands through the write() call.
+     */
+    void open(in INfcClientCallback clientCallback);
+
+    /**
+     * Close the NFC HAL and setup NFC controller close type.
+     * Associated resources such as clientCallback must be released.
+     * The clientCallback reference from open() must be invalid after close().
+     * If close() returns ok(), the NCI stack must wait for a NfcEvent.CLOSE_CPLT
+     * callback before continuing.
+     * Returns an error if close may be called more than once.
+     * Calls to any other method which expect a callback after this must return
+     * a service-specific error NfcStatus::FAILED.
+     * HAL close automatically if the client drops the reference to the HAL or
+     * crashes.
+     */
+    void close(in NfcCloseType type);
+
+    /**
+     * coreInitialized() is called after the CORE_INIT_RSP is received from the
+     * NFCC. At this time, the HAL can do any chip-specific configuration.
+     *
+     * If coreInitialized() returns ok(), the NCI stack must wait for a
+     * NfcEvent.POST_INIT_CPLT before continuing.
+     * If coreInitialized() returns an error, the NCI stack must continue immediately.
+     *
+     * coreInitialized() must be called after open() registers the clientCallback
+     * or return a service-specific error NfcStatus::FAILED directly.
+     *
+     */
+    void coreInitialized();
+
+    /**
+     * Clears the NFC chip.
+     *
+     * Must be called during factory reset and/or before the first time the HAL is
+     * initialized after a factory reset.
+     */
+    void factoryReset();
+
+    /**
+     * Fetches vendor specific configurations.
+     * @return NfcConfig indicates support for certain features and
+     * populates the vendor specific configs.
+     */
+    NfcConfig getConfig();
+
+    /**
+     * Restart controller by power cyle;
+     * It's similar to open but just reset the controller without initialize all the
+     * resources.
+     *
+     * If powerCycle() returns ok(), the NCI stack must wait for a NfcEvent.OPEN_CPLT
+     * before continuing.
+     *
+     * powerCycle() must be called after open() registers the clientCallback
+     * or return a service-specific error NfcStatus::FAILED directly.
+     */
+    void powerCycle();
+
+    /**
+     * preDiscover is called every time before starting RF discovery.
+     * It is a good place to do vendor-specific configuration that must be
+     * performed every time RF discovery is about to be started.
+     *
+     * If preDiscover() returns ok(), the NCI stack must wait for a
+     * NfcEvent.PREDISCOVER_CPLT before continuing.
+     *
+     * preDiscover() must be called after open() registers the clientCallback
+     * or return a service-specific error NfcStatus::FAILED directly.
+     *
+     * If preDiscover() reports an error, the NCI stack must start RF discovery immediately.
+     */
+    void preDiscover();
+
+    /**
+     * Performs an NCI write.
+     *
+     * This method may queue writes and return immediately. The only
+     * requirement is that the writes are executed in order.
+     *
+     * @param data
+     * Data packet to transmit NCI Commands and Data Messages over write.
+     * Detailed format is defined in NFC Controller Interface (NCI) Technical Specification.
+     * https://nfc-forum.org/our-work/specification-releases/
+     *
+     * @return number of bytes written to the NFCC.
+     */
+    int write(in byte[] data);
+
+    /**
+     * Set the logging flag for NFC HAL to enable it's verbose logging.
+     * If verbose logging is not supported, the call must not have any effect on logging verbosity.
+     * However, isVerboseLoggingEnabled() must still return the value set by the last call to
+     * setEnableVerboseLogging().
+     * @param enable for setting the verbose logging flag to HAL
+     */
+    void setEnableVerboseLogging(in boolean enable);
+
+    /**
+     * Get the verbose logging flag value from NFC HAL.
+     * @return true if verbose logging flag value is enabled, false if disabled.
+     */
+    boolean isVerboseLoggingEnabled();
+}
diff --git a/nfc/aidl/android/hardware/nfc/INfcClientCallback.aidl b/nfc/aidl/android/hardware/nfc/INfcClientCallback.aidl
new file mode 100644
index 0000000..43d4f5c
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/INfcClientCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+import android.hardware.nfc.NfcEvent;
+import android.hardware.nfc.NfcStatus;
+
+@VintfStability
+interface INfcClientCallback {
+    /**
+     * The callback passed in from the NFC stack that the HAL
+     * can use to pass incomming response data to the stack.
+     *
+     * @param data
+     * Data packet to transmit NCI Responses, Notifications, and Data
+     * Messages over sendData.
+     * Detailed format is defined in NFC Controller Interface (NCI) Technical Specification.
+     * https://nfc-forum.org/our-work/specification-releases/
+     */
+    void sendData(in byte[] data);
+
+    /**
+     * The callback passed in from the NFC stack that the HAL
+     * can use to pass events back to the stack.
+     */
+    void sendEvent(in NfcEvent event, in NfcStatus status);
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcCloseType.aidl b/nfc/aidl/android/hardware/nfc/NfcCloseType.aidl
new file mode 100644
index 0000000..5160532
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcCloseType.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+/**
+ * Different closing types for NFC HAL.
+ */
+@VintfStability
+@Backing(type="int")
+enum NfcCloseType {
+    /**
+     * Close the NFC controller and free NFC HAL resources.
+     */
+    DISABLE = 0,
+
+    /**
+     * Switch the NFC controller operation mode and free NFC HAL resources.
+     * Enable NFC functionality for off host card emulation usecases in
+     * device(host) power off(switched off) state, if the device
+     * supports power off use cases. If the device doesn't support power
+     * off use cases, this call should be same as DISABLE.
+     */
+    HOST_SWITCHED_OFF = 1,
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcConfig.aidl b/nfc/aidl/android/hardware/nfc/NfcConfig.aidl
new file mode 100644
index 0000000..1b4fcfb
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcConfig.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+import android.hardware.nfc.PresenceCheckAlgorithm;
+import android.hardware.nfc.ProtocolDiscoveryConfig;
+
+/**
+ * Define Nfc related configurations based on:
+ * NFC Controller Interface (NCI) Technical Specification
+ * https://nfc-forum.org/our-work/specification-releases/
+ */
+@VintfStability
+parcelable NfcConfig {
+    /**
+     * If true, NFCC is using bail out mode for either Type A or Type B poll
+     * based on: Nfc-Forum Activity Technical Specification
+     * https://nfc-forum.org/our-work/specification-releases/
+     */
+    boolean nfaPollBailOutMode;
+    PresenceCheckAlgorithm presenceCheckAlgorithm;
+    ProtocolDiscoveryConfig nfaProprietaryCfg;
+    /**
+     * Default off-host route. 0x00 if there aren't any. Refer to NCI spec.
+     */
+    byte defaultOffHostRoute;
+    /**
+     * Default off-host route for Felica. 0x00 if there aren't any. Refer to
+     * NCI spec.
+     */
+    byte defaultOffHostRouteFelica;
+    /**
+     * Default system code route. 0x00 if there aren't any. Refer NCI spec.
+     */
+    byte defaultSystemCodeRoute;
+    /**
+     * Default power state for system code route. 0x00 if there aren't any.
+     * Refer to NCI spec.
+     */
+    byte defaultSystemCodePowerState;
+    /**
+     * Default route for all remaining protocols and technology which haven't
+     * been configured.
+     * Device Host(0x00) is the default. Refer to NCI spec.
+     *
+     */
+    byte defaultRoute;
+    /**
+     * Pipe ID for eSE. 0x00 if there aren't any.
+     */
+    byte offHostESEPipeId;
+    /**
+     * Pipe ID for UICC. 0x00 if there aren't any.
+     */
+    byte offHostSIMPipeId;
+    /**
+     * Extended APDU length for ISO_DEP. If not supported default length is 261
+     */
+    int maxIsoDepTransceiveLength;
+    /**
+     * list of allowed host ids, as per ETSI TS 102 622
+     * https://www.etsi.org/
+     */
+    byte[] hostAllowlist;
+    /**
+     * NFCEE ID for offhost UICC & eSE secure element.
+     * 0x00 if there aren't any. Refer to NCI spec.
+     */
+    byte[] offHostRouteUicc;
+    byte[] offHostRouteEse;
+    /**
+     * Default IsoDep route. 0x00 if there aren't any. Refer to NCI spec.
+     */
+    byte defaultIsoDepRoute;
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcEvent.aidl b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
new file mode 100644
index 0000000..a78b1cd
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+/**
+ * Nfc event to notify nfc status change.
+ */
+@VintfStability
+@Backing(type="int")
+enum NfcEvent {
+    /**
+     * Open complete event to notify upper layer when NFC HAL and NFCC
+     * initialization complete.
+     */
+    OPEN_CPLT = 0,
+    /**
+     * Close complete event to notify upper layer when HAL close is done.
+     */
+    CLOSE_CPLT = 1,
+    /**
+     * Post init complete event to notify upper layer when post init operations
+     * are done.
+     */
+    POST_INIT_CPLT = 2,
+    /**
+     * Pre-discover complete event to notify upper layer when pre-discover
+     * operations are done.
+     */
+    PRE_DISCOVER_CPLT = 3,
+    /**
+     * HCI network reset event to notify upplayer when HCI network needs to
+     * be re-initialized in case of an error.
+     */
+    HCI_NETWORK_RESET = 4,
+    /**
+     * Error event to notify upper layer when there's an unknown error.
+     */
+    ERROR = 5,
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcStatus.aidl b/nfc/aidl/android/hardware/nfc/NfcStatus.aidl
new file mode 100644
index 0000000..a38d370
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcStatus.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+/**
+ * Used to specify the status of the NfcEvent
+ */
+@VintfStability
+@Backing(type="int")
+enum NfcStatus {
+    /**
+     * Default status when NfcEvent with status OK.
+     */
+    OK = 0,
+    /**
+     * Generic error.
+     */
+    FAILED = 1,
+    /**
+     * Transport error.
+     */
+    ERR_TRANSPORT = 2,
+    /**
+     * Command timeout error.
+     */
+    ERR_CMD_TIMEOUT = 3,
+    /**
+     * Refused error when command is rejected.
+     */
+    REFUSED = 4,
+}
diff --git a/nfc/aidl/android/hardware/nfc/PresenceCheckAlgorithm.aidl b/nfc/aidl/android/hardware/nfc/PresenceCheckAlgorithm.aidl
new file mode 100644
index 0000000..20e7bff
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/PresenceCheckAlgorithm.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+/*
+ * Presence Check Algorithm as defined in ISO/IEC 14443-4:
+ * https://www.iso.org/standard/73599.html
+ */
+@VintfStability
+@Backing(type="byte")
+enum PresenceCheckAlgorithm {
+    /**
+     * Let the stack select an algorithm
+     */
+    DEFAULT = 0,
+    /**
+     * ISO-DEP protocol's empty I-block
+     */
+    I_BLOCK = 1,
+    /**
+     * Type - 4 tag protocol iso-dep nak presence check command is sent waiting for
+     * response and notification.
+     */
+    ISO_DEP_NAK = 2,
+}
diff --git a/nfc/aidl/android/hardware/nfc/ProtocolDiscoveryConfig.aidl b/nfc/aidl/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
new file mode 100644
index 0000000..f8e3228
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc;
+
+/**
+ * Vendor Specific Proprietary Protocol & Discovery Configuration.
+ * Set to 0xFF if not supported.
+ * discovery* fields map to "RF Technology and Mode" in NCI Spec
+ * protocol* fields map to "RF protocols" in NCI Spec
+ */
+@VintfStability
+parcelable ProtocolDiscoveryConfig {
+    byte protocol18092Active;
+    byte protocolBPrime;
+    byte protocolDual;
+    byte protocol15693;
+    byte protocolKovio;
+    byte protocolMifare;
+    byte discoveryPollKovio;
+    byte discoveryPollBPrime;
+    byte discoveryListenBPrime;
+}
diff --git a/nfc/aidl/default/Android.bp b/nfc/aidl/default/Android.bp
new file mode 100644
index 0000000..907d23d
--- /dev/null
+++ b/nfc/aidl/default/Android.bp
@@ -0,0 +1,23 @@
+cc_binary {
+    name: "android.hardware.nfc-service.example",
+    relative_install_path: "hw",
+    init_rc: ["nfc-service-example.rc"],
+    vintf_fragments: ["nfc-service-example.xml"],
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+        "libbinder_ndk",
+        "android.hardware.nfc-V1-ndk",
+    ],
+    srcs: [
+        "main.cpp",
+        "Nfc.cpp",
+        "Vendor_hal_api.cpp",
+    ],
+}
diff --git a/nfc/aidl/default/Nfc.cpp b/nfc/aidl/default/Nfc.cpp
new file mode 100644
index 0000000..4685b59
--- /dev/null
+++ b/nfc/aidl/default/Nfc.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Nfc.h"
+
+#include <android-base/logging.h>
+
+#include "Vendor_hal_api.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace nfc {
+
+std::shared_ptr<INfcClientCallback> Nfc::mCallback = nullptr;
+AIBinder_DeathRecipient* clientDeathRecipient = nullptr;
+
+void OnDeath(void* cookie) {
+    if (Nfc::mCallback != nullptr && !AIBinder_isAlive(Nfc::mCallback->asBinder().get())) {
+        LOG(INFO) << __func__ << " Nfc service has died";
+        Nfc* nfc = static_cast<Nfc*>(cookie);
+        nfc->close(NfcCloseType::DISABLE);
+    }
+}
+
+::ndk::ScopedAStatus Nfc::open(const std::shared_ptr<INfcClientCallback>& clientCallback) {
+    LOG(INFO) << "open";
+    if (clientCallback == nullptr) {
+        LOG(INFO) << "Nfc::open null callback";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(NfcStatus::FAILED));
+    }
+    Nfc::mCallback = clientCallback;
+
+    clientDeathRecipient = AIBinder_DeathRecipient_new(OnDeath);
+    auto linkRet = AIBinder_linkToDeath(clientCallback->asBinder().get(), clientDeathRecipient,
+                                        this /* cookie */);
+    if (linkRet != STATUS_OK) {
+        LOG(ERROR) << __func__ << ": linkToDeath failed: " << linkRet;
+        // Just ignore the error.
+    }
+
+    int ret = Vendor_hal_open(eventCallback, dataCallback);
+    return ret == 0 ? ndk::ScopedAStatus::ok()
+                    : ndk::ScopedAStatus::fromServiceSpecificError(
+                              static_cast<int32_t>(NfcStatus::FAILED));
+}
+
+::ndk::ScopedAStatus Nfc::close(NfcCloseType type) {
+    LOG(INFO) << "close";
+    if (Nfc::mCallback == nullptr) {
+        LOG(ERROR) << __func__ << "mCallback null";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(NfcStatus::FAILED));
+    }
+    int ret = 0;
+    if (type == NfcCloseType::HOST_SWITCHED_OFF) {
+        ret = Vendor_hal_close_off();
+    } else {
+        ret = Vendor_hal_close();
+    }
+    Nfc::mCallback = nullptr;
+    AIBinder_DeathRecipient_delete(clientDeathRecipient);
+    clientDeathRecipient = nullptr;
+    return ret == 0 ? ndk::ScopedAStatus::ok()
+                    : ndk::ScopedAStatus::fromServiceSpecificError(
+                              static_cast<int32_t>(NfcStatus::FAILED));
+}
+
+::ndk::ScopedAStatus Nfc::coreInitialized() {
+    LOG(INFO) << "coreInitialized";
+    if (Nfc::mCallback == nullptr) {
+        LOG(ERROR) << __func__ << "mCallback null";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(NfcStatus::FAILED));
+    }
+    int ret = Vendor_hal_core_initialized();
+
+    return ret == 0 ? ndk::ScopedAStatus::ok()
+                    : ndk::ScopedAStatus::fromServiceSpecificError(
+                              static_cast<int32_t>(NfcStatus::FAILED));
+}
+
+::ndk::ScopedAStatus Nfc::factoryReset() {
+    LOG(INFO) << "factoryReset";
+    Vendor_hal_factoryReset();
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::getConfig(NfcConfig* _aidl_return) {
+    LOG(INFO) << "getConfig";
+    NfcConfig nfcVendorConfig;
+    Vendor_hal_getConfig(nfcVendorConfig);
+
+    *_aidl_return = nfcVendorConfig;
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::powerCycle() {
+    LOG(INFO) << "powerCycle";
+    if (Nfc::mCallback == nullptr) {
+        LOG(ERROR) << __func__ << "mCallback null";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(NfcStatus::FAILED));
+    }
+    return Vendor_hal_power_cycle() ? ndk::ScopedAStatus::fromServiceSpecificError(
+                                              static_cast<int32_t>(NfcStatus::FAILED))
+                                    : ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::preDiscover() {
+    LOG(INFO) << "preDiscover";
+    if (Nfc::mCallback == nullptr) {
+        LOG(ERROR) << __func__ << "mCallback null";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(NfcStatus::FAILED));
+    }
+    return Vendor_hal_pre_discover() ? ndk::ScopedAStatus::fromServiceSpecificError(
+                                               static_cast<int32_t>(NfcStatus::FAILED))
+                                     : ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::write(const std::vector<uint8_t>& data, int32_t* _aidl_return) {
+    LOG(INFO) << "write";
+    if (Nfc::mCallback == nullptr) {
+        LOG(ERROR) << __func__ << "mCallback null";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(NfcStatus::FAILED));
+    }
+    *_aidl_return = Vendor_hal_write(data.size(), &data[0]);
+    return ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus Nfc::setEnableVerboseLogging(bool enable) {
+    LOG(INFO) << "setVerboseLogging";
+    Vendor_hal_setVerboseLogging(enable);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::isVerboseLoggingEnabled(bool* _aidl_return) {
+    *_aidl_return = Vendor_hal_getVerboseLogging();
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace nfc
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/nfc/aidl/default/Nfc.h b/nfc/aidl/default/Nfc.h
new file mode 100644
index 0000000..1b14534
--- /dev/null
+++ b/nfc/aidl/default/Nfc.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/nfc/BnNfc.h>
+#include <aidl/android/hardware/nfc/INfcClientCallback.h>
+#include <android-base/logging.h>
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace nfc {
+
+using ::aidl::android::hardware::nfc::NfcCloseType;
+using ::aidl::android::hardware::nfc::NfcConfig;
+using ::aidl::android::hardware::nfc::NfcStatus;
+
+// Default implementation that reports no support NFC.
+struct Nfc : public BnNfc {
+  public:
+    Nfc() = default;
+
+    ::ndk::ScopedAStatus open(const std::shared_ptr<INfcClientCallback>& clientCallback) override;
+    ::ndk::ScopedAStatus close(NfcCloseType type) override;
+    ::ndk::ScopedAStatus coreInitialized() override;
+    ::ndk::ScopedAStatus factoryReset() override;
+    ::ndk::ScopedAStatus getConfig(NfcConfig* _aidl_return) override;
+    ::ndk::ScopedAStatus powerCycle() override;
+    ::ndk::ScopedAStatus preDiscover() override;
+    ::ndk::ScopedAStatus write(const std::vector<uint8_t>& data, int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus setEnableVerboseLogging(bool enable) override;
+    ::ndk::ScopedAStatus isVerboseLoggingEnabled(bool* _aidl_return) override;
+
+    static void eventCallback(uint8_t event, uint8_t status) {
+        if (mCallback != nullptr) {
+            auto ret = mCallback->sendEvent((NfcEvent)event, (NfcStatus)status);
+            if (!ret.isOk()) {
+                LOG(ERROR) << "Failed to send event!";
+            }
+        }
+    }
+
+    static void dataCallback(uint16_t data_len, uint8_t* p_data) {
+        std::vector<uint8_t> data(p_data, p_data + data_len);
+        if (mCallback != nullptr) {
+            auto ret = mCallback->sendData(data);
+            if (!ret.isOk()) {
+                LOG(ERROR) << "Failed to send data!";
+            }
+        }
+    }
+
+    static std::shared_ptr<INfcClientCallback> mCallback;
+};
+
+}  // namespace nfc
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/nfc/aidl/default/Vendor_hal_api.cpp b/nfc/aidl/default/Vendor_hal_api.cpp
new file mode 100644
index 0000000..66a2ebc
--- /dev/null
+++ b/nfc/aidl/default/Vendor_hal_api.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/properties.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include "Vendor_hal_api.h"
+
+bool logging = false;
+
+int Vendor_hal_open(nfc_stack_callback_t* p_cback, nfc_stack_data_callback_t* p_data_cback) {
+    (void)p_cback;
+    (void)p_data_cback;
+    // nothing to open in this example
+    return -1;
+}
+
+int Vendor_hal_write(uint16_t data_len, const uint8_t* p_data) {
+    (void)data_len;
+    (void)p_data;
+    return -1;
+}
+
+int Vendor_hal_core_initialized() {
+    return -1;
+}
+
+int Vendor_hal_pre_discover() {
+    return -1;
+}
+
+int Vendor_hal_close() {
+    return -1;
+}
+
+int Vendor_hal_close_off() {
+    return -1;
+}
+
+int Vendor_hal_power_cycle() {
+    return -1;
+}
+
+void Vendor_hal_factoryReset() {}
+
+void Vendor_hal_getConfig(NfcConfig& config) {
+    (void)config;
+}
+
+void Vendor_hal_setVerboseLogging(bool enable) {
+    logging = enable;
+}
+
+bool Vendor_hal_getVerboseLogging() {
+    return logging;
+}
diff --git a/nfc/aidl/default/Vendor_hal_api.h b/nfc/aidl/default/Vendor_hal_api.h
new file mode 100644
index 0000000..595c2dd
--- /dev/null
+++ b/nfc/aidl/default/Vendor_hal_api.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/nfc/INfc.h>
+#include <aidl/android/hardware/nfc/NfcConfig.h>
+#include <aidl/android/hardware/nfc/NfcEvent.h>
+#include <aidl/android/hardware/nfc/NfcStatus.h>
+#include <aidl/android/hardware/nfc/PresenceCheckAlgorithm.h>
+#include <aidl/android/hardware/nfc/ProtocolDiscoveryConfig.h>
+#include "hardware_nfc.h"
+
+using aidl::android::hardware::nfc::NfcConfig;
+using aidl::android::hardware::nfc::NfcEvent;
+using aidl::android::hardware::nfc::NfcStatus;
+using aidl::android::hardware::nfc::PresenceCheckAlgorithm;
+using aidl::android::hardware::nfc::ProtocolDiscoveryConfig;
+
+int Vendor_hal_open(nfc_stack_callback_t* p_cback, nfc_stack_data_callback_t* p_data_cback);
+int Vendor_hal_write(uint16_t data_len, const uint8_t* p_data);
+
+int Vendor_hal_core_initialized();
+
+int Vendor_hal_pre_discover();
+
+int Vendor_hal_close();
+
+int Vendor_hal_close_off();
+
+int Vendor_hal_power_cycle();
+
+void Vendor_hal_factoryReset();
+
+void Vendor_hal_getConfig(NfcConfig& config);
+
+void Vendor_hal_setVerboseLogging(bool enable);
+
+bool Vendor_hal_getVerboseLogging();
diff --git a/nfc/aidl/default/hardware_nfc.h b/nfc/aidl/default/hardware_nfc.h
new file mode 100644
index 0000000..0f856c5
--- /dev/null
+++ b/nfc/aidl/default/hardware_nfc.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+#pragma once
+
+typedef uint8_t nfc_event_t;
+typedef uint8_t nfc_status_t;
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass events back to the stack.
+ */
+typedef void(nfc_stack_callback_t)(nfc_event_t event, nfc_status_t event_status);
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass incomming data to the stack.
+ */
+typedef void(nfc_stack_data_callback_t)(uint16_t data_len, uint8_t* p_data);
diff --git a/nfc/aidl/default/main.cpp b/nfc/aidl/default/main.cpp
new file mode 100644
index 0000000..0cc51e7
--- /dev/null
+++ b/nfc/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "Nfc.h"
+using ::aidl::android::hardware::nfc::Nfc;
+
+int main() {
+    LOG(INFO) << "NFC HAL starting up";
+    if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+        LOG(INFO) << "failed to set thread pool max thread count";
+        return 1;
+    }
+    std::shared_ptr<Nfc> nfc_service = ndk::SharedRefBase::make<Nfc>();
+
+    const std::string instance = std::string() + Nfc::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(nfc_service->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+    ABinderProcess_joinThreadPool();
+    return 0;
+}
diff --git a/nfc/aidl/default/nfc-service-example.rc b/nfc/aidl/default/nfc-service-example.rc
new file mode 100644
index 0000000..7d7052e
--- /dev/null
+++ b/nfc/aidl/default/nfc-service-example.rc
@@ -0,0 +1,4 @@
+service nfc_hal_service /vendor/bin/hw/android.hardware.nfc-service.st
+    class hal
+    user nfc
+    group nfc
diff --git a/nfc/aidl/default/nfc-service-example.xml b/nfc/aidl/default/nfc-service-example.xml
new file mode 100644
index 0000000..70fed20
--- /dev/null
+++ b/nfc/aidl/default/nfc-service-example.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.nfc</name>
+        <fqname>INfc/default</fqname>
+    </hal>
+</manifest>
diff --git a/nfc/aidl/vts/functional/Android.bp b/nfc/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..99eecd0
--- /dev/null
+++ b/nfc/aidl/vts/functional/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsAidlHalNfcTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsAidlHalNfcTargetTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.nfc-V1-ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
new file mode 100644
index 0000000..977b25c
--- /dev/null
+++ b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "nfc_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/nfc/BnNfc.h>
+#include <aidl/android/hardware/nfc/BnNfcClientCallback.h>
+#include <aidl/android/hardware/nfc/INfc.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_enums.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <chrono>
+#include <future>
+
+using aidl::android::hardware::nfc::INfc;
+using aidl::android::hardware::nfc::INfcClientCallback;
+using aidl::android::hardware::nfc::NfcCloseType;
+using aidl::android::hardware::nfc::NfcConfig;
+using aidl::android::hardware::nfc::NfcEvent;
+using aidl::android::hardware::nfc::NfcStatus;
+using aidl::android::hardware::nfc::PresenceCheckAlgorithm;
+
+using android::getAidlHalInstanceNames;
+using android::PrintInstanceNameToString;
+using android::base::StringPrintf;
+using ndk::enum_range;
+using ndk::ScopedAStatus;
+using ndk::SharedRefBase;
+using ndk::SpAIBinder;
+
+constexpr static int kCallbackTimeoutMs = 10000;
+
+// 261 bytes is the default and minimum transceive length
+constexpr unsigned int MIN_ISO_DEP_TRANSCEIVE_LENGTH = 261;
+
+// Range of valid off host route ids
+constexpr uint8_t MIN_OFFHOST_ROUTE_ID = 0x01;
+constexpr uint8_t MAX_OFFHOST_ROUTE_ID = 0xFE;
+
+class NfcClientCallback : public aidl::android::hardware::nfc::BnNfcClientCallback {
+  public:
+    NfcClientCallback(const std::function<void(NfcEvent, NfcStatus)>& on_hal_event_cb,
+                      const std::function<void(const std::vector<uint8_t>&)>& on_nci_data_cb)
+        : on_nci_data_cb_(on_nci_data_cb), on_hal_event_cb_(on_hal_event_cb) {}
+    virtual ~NfcClientCallback() = default;
+
+    ::ndk::ScopedAStatus sendEvent(NfcEvent event, NfcStatus event_status) override {
+        on_hal_event_cb_(event, event_status);
+        return ::ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus sendData(const std::vector<uint8_t>& data) override {
+        on_nci_data_cb_(data);
+        return ::ndk::ScopedAStatus::ok();
+    };
+
+  private:
+    std::function<void(const std::vector<uint8_t>&)> on_nci_data_cb_;
+    std::function<void(NfcEvent, NfcStatus)> on_hal_event_cb_;
+};
+
+class NfcAidl : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+        infc_ = INfc::fromBinder(binder);
+        ASSERT_NE(infc_, nullptr);
+    }
+    std::shared_ptr<INfc> infc_;
+};
+
+/*
+ * OpenAndCloseForDisable:
+ * Makes an open call, waits for NfcEvent::OPEN_CPLT
+ * Immediately calls close(NfcCloseType::DISABLE) and
+ * waits for NfcEvent::CLOSE_CPLT
+ *
+ */
+TEST_P(NfcAidl, OpenAndCloseForDisable) {
+    std::promise<void> open_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                LOG(INFO) << StringPrintf("%s,%d ", __func__, event);
+                if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close DISABLE";
+    EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+    LOG(INFO) << "wait for close";
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * OpenAndCloseForHostSwitchedOff:
+ * Makes an open call, waits for NfcEvent::OPEN_CPLT
+ * Immediately calls close(NfcCloseType::HOST_SWITCHED_OFF) and
+ * waits for NfcEvent::CLOSE_CPLT
+ *
+ */
+TEST_P(NfcAidl, OpenAndCloseForHostSwitchedOff) {
+    std::promise<void> open_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close HOST_SWITCHED_OFF";
+    EXPECT_TRUE(infc_->close(NfcCloseType::HOST_SWITCHED_OFF).isOk());
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * OpenAfterOpen:
+ * Calls open() multiple times
+ * Checks status
+ */
+TEST_P(NfcAidl, OpenAfterOpen) {
+    int open_count = 0;
+    std::promise<void> open_cb_promise;
+    std::promise<void> open2_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto open2_cb_future = open2_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &open2_cb_promise, &open_count](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) {
+                    open_count == 0 ? open_cb_promise.set_value() : open2_cb_promise.set_value();
+                    open_count++;
+                }
+            },
+            [](auto) {});
+
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Open again and wait for OPEN_CPLT
+    LOG(INFO) << "open again";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open2_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * CloseAfterClose:
+ * Calls close() multiple times
+ * Checks status
+ */
+TEST_P(NfcAidl, CloseAfterClose) {
+    std::promise<void> open_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close";
+    EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+    // Close again should fail.
+    LOG(INFO) << "close again";
+    EXPECT_TRUE(!(infc_->close(NfcCloseType::DISABLE).isOk()));
+}
+
+/*
+ * PowerCycleAfterOpen:
+ * Calls powerCycle() after open
+ * Waits for NfcEvent.OPEN_CPLT
+ * Checks status
+ */
+TEST_P(NfcAidl, PowerCycleAfterOpen) {
+    int open_cplt_count = 0;
+    std::promise<void> open_cb_promise;
+    std::promise<void> power_cycle_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto power_cycle_cb_future = power_cycle_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise, &power_cycle_cb_promise, &open_cplt_count](
+                    auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) {
+                    if (open_cplt_count == 0) {
+                        open_cplt_count++;
+                        open_cb_promise.set_value();
+                    } else {
+                        power_cycle_cb_promise.set_value();
+                    }
+                }
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // PowerCycle and wait for OPEN_CPLT
+    LOG(INFO) << "PowerCycle";
+    EXPECT_TRUE(infc_->powerCycle().isOk());
+    EXPECT_EQ(power_cycle_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close";
+    EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * PowerCycleAfterClose:
+ * Calls powerCycle() after close
+ * PowerCycle should fail immediately
+ */
+TEST_P(NfcAidl, PowerCycleAfterClose) {
+    std::promise<void> open_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close";
+    EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // PowerCycle should fail
+    LOG(INFO) << "PowerCycle";
+    EXPECT_TRUE(!(infc_->powerCycle().isOk()));
+}
+
+/*
+ * CoreInitializedAfterOpen:
+ * Calls coreInitialized() after open
+ * Waits for NfcEvent.POST_INIT_CPLT
+ */
+TEST_P(NfcAidl, CoreInitializedAfterOpen) {
+    std::promise<void> open_cb_promise;
+    std::promise<void> core_init_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto core_init_cb_future = core_init_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise, &core_init_cb_promise](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+                if (event == NfcEvent::POST_INIT_CPLT) core_init_cb_promise.set_value();
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // CoreInitialized and wait for POST_INIT_CPLT
+    LOG(INFO) << "coreInitialized";
+    EXPECT_TRUE(infc_->coreInitialized().isOk());
+    EXPECT_EQ(core_init_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close";
+    EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * CoreInitializedAfterClose:
+ * Calls coreInitialized() after close
+ * coreInitialized() should fail immediately
+ */
+TEST_P(NfcAidl, CoreInitializedAfterClose) {
+    std::promise<void> open_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close";
+    EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // coreInitialized should fail
+    LOG(INFO) << "CoreInitialized";
+    EXPECT_TRUE(!(infc_->coreInitialized().isOk()));
+}
+
+/*
+ * PreDiscoverAfterClose:
+ * Call preDiscover() after close
+ * preDiscover() should fail immediately
+ */
+TEST_P(NfcAidl, PreDiscoverAfterClose) {
+    std::promise<void> open_cb_promise;
+    std::promise<void> close_cb_promise;
+    auto open_cb_future = open_cb_promise.get_future();
+    auto close_cb_future = close_cb_promise.get_future();
+    std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+            [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+                EXPECT_EQ(status, NfcStatus::OK);
+                if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+                if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+            },
+            [](auto) {});
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+    // Open and wait for OPEN_CPLT
+    LOG(INFO) << "open";
+    EXPECT_TRUE(infc_->open(mCallback).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // Close and wait for CLOSE_CPLT
+    LOG(INFO) << "close";
+    EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+    EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+
+    // preDiscover should fail
+    LOG(INFO) << "preDiscover";
+    EXPECT_TRUE(!(infc_->preDiscover().isOk()));
+}
+
+/*
+ * checkGetConfigValues:
+ * Calls getConfig()
+ * checks if fields in NfcConfig are populated correctly
+ */
+TEST_P(NfcAidl, CheckGetConfigValues) {
+    NfcConfig configValue;
+    EXPECT_TRUE(infc_->getConfig(&configValue).isOk());
+    EXPECT_GE(configValue.maxIsoDepTransceiveLength, MIN_ISO_DEP_TRANSCEIVE_LENGTH);
+    LOG(INFO) << StringPrintf("configValue.maxIsoDepTransceiveLength = %x",
+                              configValue.maxIsoDepTransceiveLength);
+    for (auto uicc : configValue.offHostRouteUicc) {
+        LOG(INFO) << StringPrintf("offHostRouteUicc = %x", uicc);
+        EXPECT_GE(uicc, MIN_OFFHOST_ROUTE_ID);
+        EXPECT_LE(uicc, MAX_OFFHOST_ROUTE_ID);
+    }
+    for (auto ese : configValue.offHostRouteEse) {
+        LOG(INFO) << StringPrintf("offHostRouteEse = %x", ese);
+        EXPECT_GE(ese, MIN_OFFHOST_ROUTE_ID);
+        EXPECT_LE(ese, MAX_OFFHOST_ROUTE_ID);
+    }
+    if (configValue.defaultIsoDepRoute != 0) {
+        EXPECT_GE((uint8_t)configValue.defaultIsoDepRoute, MIN_OFFHOST_ROUTE_ID);
+        EXPECT_LE((uint8_t)configValue.defaultIsoDepRoute, MAX_OFFHOST_ROUTE_ID);
+    }
+}
+
+/*
+ * CheckisVerboseLoggingEnabledAfterSetEnableVerboseLogging:
+ * Calls setEnableVerboseLogging()
+ * checks the return value of isVerboseLoggingEnabled
+ */
+TEST_P(NfcAidl, CheckisVerboseLoggingEnabledAfterSetEnableVerboseLogging) {
+    bool enabled = false;
+    EXPECT_TRUE(infc_->setEnableVerboseLogging(true).isOk());
+    EXPECT_TRUE(infc_->isVerboseLoggingEnabled(&enabled).isOk());
+    EXPECT_TRUE(enabled);
+    EXPECT_TRUE(infc_->setEnableVerboseLogging(false).isOk());
+    EXPECT_TRUE(infc_->isVerboseLoggingEnabled(&enabled).isOk());
+    EXPECT_TRUE(!enabled);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NfcAidl);
+INSTANTIATE_TEST_SUITE_P(Nfc, NfcAidl,
+                         testing::ValuesIn(::android::getAidlHalInstanceNames(INfc::descriptor)),
+                         ::android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
+    std::system("/system/bin/svc nfc disable"); /* Turn off NFC */
+    sleep(5);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    std::system("/system/bin/svc nfc enable"); /* Turn on NFC */
+    sleep(5);
+    return status;
+}
diff --git a/oemlock/aidl/default/service.cpp b/oemlock/aidl/default/service.cpp
index af828a0..9fa7d63 100644
--- a/oemlock/aidl/default/service.cpp
+++ b/oemlock/aidl/default/service.cpp
@@ -28,7 +28,7 @@
 
     const std::string instance = std::string() + OemLock::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(oemlock->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return -1; // Should never be reached
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
index 8920c01..f38426b 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
@@ -49,4 +49,6 @@
   CAMERA_STREAMING_LOW = 12,
   CAMERA_STREAMING_MID = 13,
   CAMERA_STREAMING_HIGH = 14,
+  GAME = 15,
+  GAME_LOADING = 16,
 }
diff --git a/power/aidl/android/hardware/power/Mode.aidl b/power/aidl/android/hardware/power/Mode.aidl
index ae113e3..cc4b130 100644
--- a/power/aidl/android/hardware/power/Mode.aidl
+++ b/power/aidl/android/hardware/power/Mode.aidl
@@ -162,4 +162,14 @@
      * This hint indicates that camera high resolution stream is being started.
      */
     CAMERA_STREAMING_HIGH,
+
+    /**
+     * This mode indicates that user is playing a game.
+     */
+    GAME,
+
+    /**
+     * This mode indicates that the user is waiting for loading in a game.
+     */
+    GAME_LOADING,
 }
diff --git a/power/aidl/default/Android.bp b/power/aidl/default/Android.bp
index 9acb9e0..223b9d5 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -30,7 +30,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.power-V2-ndk",
+        "android.hardware.power-V3-ndk",
     ],
     srcs: [
         "main.cpp",
diff --git a/power/aidl/default/main.cpp b/power/aidl/default/main.cpp
index 964bd96..306b91b 100644
--- a/power/aidl/default/main.cpp
+++ b/power/aidl/default/main.cpp
@@ -28,7 +28,7 @@
 
     const std::string instance = std::string() + Power::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(vib->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/power/aidl/default/power-default.xml b/power/aidl/default/power-default.xml
index 9f56deb..927ba22 100644
--- a/power/aidl/default/power-default.xml
+++ b/power/aidl/default/power-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.power</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IPower/default</fqname>
     </hal>
 </manifest>
diff --git a/power/stats/aidl/default/main.cpp b/power/stats/aidl/default/main.cpp
index 2fe3d2e..9e78247 100644
--- a/power/stats/aidl/default/main.cpp
+++ b/power/stats/aidl/default/main.cpp
@@ -73,7 +73,7 @@
 
     const std::string instance = std::string() + PowerStats::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(p->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index d108951..152858f 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -1271,8 +1271,12 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
 
     int32_t firstApiLevel = android::base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
+    int32_t boardApiLevel = android::base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
     // Allow devices shipping with Radio::1_5 and Android 11 to not support barring info.
-    if (firstApiLevel > 0 && firstApiLevel <= 30) {
+    // b/212384410 Some GRF targets lauched with S release but with vendor R release
+    // do not support getBarringInfo API. Allow these devices to not support barring info.
+    if ((firstApiLevel > 0 && firstApiLevel <= 30) ||
+        (boardApiLevel > 0 && boardApiLevel <= 30)) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                      {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
         // Early exit for devices that don't support barring info.
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index c167a6d..9f530b3 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -645,6 +645,10 @@
     if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
         ALOGI("Skipping emergencyDial because voice call is not supported in device");
         return;
+    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+        return;
     } else {
         ALOGI("Running emergencyDial because voice call is supported in device");
     }
@@ -699,6 +703,10 @@
     if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
         ALOGI("Skipping emergencyDial because voice call is not supported in device");
         return;
+    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+        return;
     } else {
         ALOGI("Running emergencyDial because voice call is supported in device");
     }
@@ -752,6 +760,10 @@
     if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
         ALOGI("Skipping emergencyDial because voice call is not supported in device");
         return;
+    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+        return;
     } else {
         ALOGI("Running emergencyDial because voice call is supported in device");
     }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
index 6982d40..980b042 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
@@ -47,4 +47,7 @@
   EMERGENCY = 512,
   MCX = 1024,
   XCAP = 2048,
+  VSIM = 4096,
+  BIP = 8192,
+  ENTERPRISE = 16384,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl
index cfcd42c..c8efea0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl
@@ -46,12 +46,14 @@
   int maxConns;
   int waitTime;
   boolean enabled;
-  android.hardware.radio.data.ApnTypes supportedApnTypesBitmap;
-  android.hardware.radio.RadioAccessFamily bearerBitmap;
+  int supportedApnTypesBitmap;
+  int bearerBitmap;
   int mtuV4;
   int mtuV6;
   boolean preferred;
   boolean persistent;
+  boolean alwaysOn;
+  @nullable android.hardware.radio.data.TrafficDescriptor trafficDescriptor;
   const int ID_DEFAULT = 0;
   const int ID_TETHERED = 1;
   const int ID_IMS = 2;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl
index a648675..dc6092a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl
@@ -46,7 +46,7 @@
   oneway void setDataThrottling(in int serial, in android.hardware.radio.data.DataThrottlingAction dataThrottlingAction, in long completionDurationMillis);
   oneway void setInitialAttachApn(in int serial, in android.hardware.radio.data.DataProfileInfo dataProfileInfo);
   oneway void setResponseFunctions(in android.hardware.radio.data.IRadioDataResponse radioDataResponse, in android.hardware.radio.data.IRadioDataIndication radioDataIndication);
-  oneway void setupDataCall(in int serial, in android.hardware.radio.AccessNetwork accessNetwork, in android.hardware.radio.data.DataProfileInfo dataProfileInfo, in boolean roamingAllowed, in android.hardware.radio.data.DataRequestReason reason, in android.hardware.radio.data.LinkAddress[] addresses, in String[] dnses, in int pduSessionId, in @nullable android.hardware.radio.data.SliceInfo sliceInfo, in @nullable android.hardware.radio.data.TrafficDescriptor trafficDescriptor, in boolean matchAllRuleAllowed);
+  oneway void setupDataCall(in int serial, in android.hardware.radio.AccessNetwork accessNetwork, in android.hardware.radio.data.DataProfileInfo dataProfileInfo, in boolean roamingAllowed, in android.hardware.radio.data.DataRequestReason reason, in android.hardware.radio.data.LinkAddress[] addresses, in String[] dnses, in int pduSessionId, in @nullable android.hardware.radio.data.SliceInfo sliceInfo, in boolean matchAllRuleAllowed);
   oneway void startHandover(in int serial, in int callId);
   oneway void startKeepalive(in int serial, in android.hardware.radio.data.KeepaliveRequest keepalive);
   oneway void stopKeepalive(in int serial, in int sessionHandle);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl
index e496c7b..0ffa1f7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl
@@ -37,5 +37,6 @@
   oneway void dataCallListChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.data.SetupDataCallResult[] dcList);
   oneway void keepaliveStatus(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.data.KeepaliveStatus status);
   oneway void pcoData(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.data.PcoDataInfo pco);
-  oneway void unthrottleApn(in android.hardware.radio.RadioIndicationType type, in String apn);
+  oneway void unthrottleApn(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.data.DataProfileInfo dataProfileInfo);
+  oneway void slicingConfigChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.data.SlicingConfig slicingConfig);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl
index 2da0167..93940fd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl
@@ -36,6 +36,5 @@
 parcelable ActivityStatsInfo {
   int sleepModeTimeMs;
   int idleModeTimeMs;
-  int[] txmModetimeMs;
-  int rxModeTimeMs;
+  android.hardware.radio.modem.ActivityStatsTechSpecificInfo[] techSpecificInfo;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
new file mode 100644
index 0000000..798ec36
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.modem;
+@VintfStability
+parcelable ActivityStatsTechSpecificInfo {
+  android.hardware.radio.AccessNetwork rat;
+  int frequencyRange;
+  int[] txmModetimeMs;
+  int rxModeTimeMs;
+  const int FREQUENCY_RANGE_UNKNOWN = 0;
+  const int FREQUENCY_RANGE_LOW = 1;
+  const int FREQUENCY_RANGE_MID = 2;
+  const int FREQUENCY_RANGE_HIGH = 3;
+  const int FREQUENCY_RANGE_MMWAVE = 4;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl
index d5716ac..5aaf5a7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl
@@ -36,7 +36,7 @@
 parcelable RadioCapability {
   int session;
   int phase;
-  android.hardware.radio.RadioAccessFamily raf;
+  int raf;
   String logicalModemUuid;
   int status;
   const int PHASE_CONFIGURED = 0;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index 16433be..2b70e45 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -50,12 +50,12 @@
   oneway void getVoiceRegistrationState(in int serial);
   oneway void isNrDualConnectivityEnabled(in int serial);
   oneway void responseAcknowledgement();
-  oneway void setAllowedNetworkTypesBitmap(in int serial, in android.hardware.radio.RadioAccessFamily networkTypeBitmap);
+  oneway void setAllowedNetworkTypesBitmap(in int serial, in int networkTypeBitmap);
   oneway void setBandMode(in int serial, in android.hardware.radio.network.RadioBandMode mode);
   oneway void setBarringPassword(in int serial, in String facility, in String oldPassword, in String newPassword);
   oneway void setCdmaRoamingPreference(in int serial, in android.hardware.radio.network.CdmaRoamingType type);
   oneway void setCellInfoListRate(in int serial, in int rate);
-  oneway void setIndicationFilter(in int serial, in android.hardware.radio.network.IndicationFilter indicationFilter);
+  oneway void setIndicationFilter(in int serial, in int indicationFilter);
   oneway void setLinkCapacityReportingCriteria(in int serial, in int hysteresisMs, in int hysteresisDlKbps, in int hysteresisUlKbps, in int[] thresholdsDownlinkKbps, in int[] thresholdsUplinkKbps, in android.hardware.radio.AccessNetwork accessNetwork);
   oneway void setLocationUpdates(in int serial, in boolean enable);
   oneway void setNetworkSelectionModeAutomatic(in int serial);
@@ -68,4 +68,6 @@
   oneway void startNetworkScan(in int serial, in android.hardware.radio.network.NetworkScanRequest request);
   oneway void stopNetworkScan(in int serial);
   oneway void supplyNetworkDepersonalization(in int serial, in String netPin);
+  oneway void setUsageSetting(in int serial, in android.hardware.radio.network.UsageSetting usageSetting);
+  oneway void getUsageSetting(in int serial);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
index d135a69..bd03c51 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -44,7 +44,7 @@
   oneway void networkScanResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.NetworkScanResult result);
   oneway void networkStateChanged(in android.hardware.radio.RadioIndicationType type);
   oneway void nitzTimeReceived(in android.hardware.radio.RadioIndicationType type, in String nitzTime, in long receivedTimeMs, in long ageMs);
-  oneway void registrationFailed(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.CellIdentity cellIdentity, in String chosenPlmn, in android.hardware.radio.network.Domain domain, in int causeCode, in int additionalCauseCode);
+  oneway void registrationFailed(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.CellIdentity cellIdentity, in String chosenPlmn, in int domain, in int causeCode, in int additionalCauseCode);
   oneway void restrictedStateChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.PhoneRestrictedState state);
   oneway void suppSvcNotify(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.SuppSvcNotification suppSvc);
   oneway void voiceRadioTechChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.RadioTechnology rat);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index ff95396..5f6c736 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -35,7 +35,7 @@
 @VintfStability
 interface IRadioNetworkResponse {
   oneway void acknowledgeRequest(in int serial);
-  oneway void getAllowedNetworkTypesBitmapResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.RadioAccessFamily networkTypeBitmap);
+  oneway void getAllowedNetworkTypesBitmapResponse(in android.hardware.radio.RadioResponseInfo info, in int networkTypeBitmap);
   oneway void getAvailableBandModesResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.RadioBandMode[] bandModes);
   oneway void getAvailableNetworksResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.OperatorInfo[] networkInfos);
   oneway void getBarringInfoResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.CellIdentity cellIdentity, in android.hardware.radio.network.BarringInfo[] barringInfos);
@@ -67,4 +67,6 @@
   oneway void startNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void stopNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void supplyNetworkDepersonalizationResponse(in android.hardware.radio.RadioResponseInfo info, in int remainingRetries);
+  oneway void setUsageSettingResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void getUsageSettingResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.UsageSetting usageSetting);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UsageSetting.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UsageSetting.aidl
new file mode 100644
index 0000000..7fdf831
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UsageSetting.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.radio.network;
+@Backing(type="int") @VintfStability
+enum UsageSetting {
+  VOICE_CENTRIC = 1,
+  DATA_CENTRIC = 2,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl
index 4f415ee..39bcf1a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl
@@ -37,7 +37,7 @@
   String number;
   String mcc;
   String mnc;
-  android.hardware.radio.voice.EmergencyServiceCategory categories;
+  int categories;
   String[] urns;
   int sources;
   const int SOURCE_NETWORK_SIGNALING = 1;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl
index 68c82fa..34d155a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl
@@ -37,7 +37,7 @@
   oneway void acceptCall(in int serial);
   oneway void conference(in int serial);
   oneway void dial(in int serial, in android.hardware.radio.voice.Dial dialInfo);
-  oneway void emergencyDial(in int serial, in android.hardware.radio.voice.Dial dialInfo, in android.hardware.radio.voice.EmergencyServiceCategory categories, in String[] urns, in android.hardware.radio.voice.EmergencyCallRouting routing, in boolean hasKnownUserIntentEmergency, in boolean isTesting);
+  oneway void emergencyDial(in int serial, in android.hardware.radio.voice.Dial dialInfo, in int categories, in String[] urns, in android.hardware.radio.voice.EmergencyCallRouting routing, in boolean hasKnownUserIntentEmergency, in boolean isTesting);
   oneway void exitEmergencyCallbackMode(in int serial);
   oneway void explicitCallTransfer(in int serial);
   oneway void getCallForwardStatus(in int serial, in android.hardware.radio.voice.CallForwardInfo callInfo);
diff --git a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
index a1c3c27..b5cf633 100644
--- a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
@@ -42,7 +42,13 @@
      */
     String eid;
     /**
-     * PortInfo contains the ICCID, logical slot ID, and port state
+     * PortInfo contains the ICCID, logical slot ID, and port state.
+     * Cardstate has no relationship with whether the slot is active or inactive. Should always
+     * report up at least 1 port otherwise the logicalSlotIndex and portActive info will be lost.
+     * For example, the pSIM can be removed, but the slot can still be active. In that case, the
+     * SIM_STATUS reported for the corresponding logical stack will show CARDSTATE_ABSENT.
+     * Similarly, even if there is no profile enabled on the eSIM, that port can still be the
+     * active port in the slot mapping.
      */
     SimPortInfo[] portInfo;
 }
diff --git a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
index e780d8e..ae103fc 100644
--- a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
@@ -73,4 +73,16 @@
      * APN type for XCAP
      */
     XCAP = 1 << 11,
+    /**
+     * APN type for VSIM.
+     */
+    VSIM = 1 << 12,
+    /**
+     * APN type for BIP.
+     */
+    BIP = 1 << 13,
+    /**
+     * APN type for ENTERPRISE
+     */
+    ENTERPRISE = 1 << 14
 }
diff --git a/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl b/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl
index 7657fc9..7360202 100644
--- a/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl
+++ b/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.data.ApnAuthType;
 import android.hardware.radio.data.ApnTypes;
 import android.hardware.radio.data.PdpProtocolType;
+import android.hardware.radio.data.TrafficDescriptor;
 
 @VintfStability
 parcelable DataProfileInfo {
@@ -92,11 +93,11 @@
     /**
      * Supported APN types bitmap. See ApnTypes for the value of each bit.
      */
-    ApnTypes supportedApnTypesBitmap;
+    int supportedApnTypesBitmap;
     /**
      * The bearer bitmap. See RadioAccessFamily for the value of each bit.
      */
-    RadioAccessFamily bearerBitmap;
+    int bearerBitmap;
     /**
      * Maximum transmission unit (MTU) size in bytes for IPv4.
      */
@@ -115,4 +116,19 @@
      * If the same data profile exists, this data profile must overwrite it.
      */
     boolean persistent;
+    /**
+     * Indicates the PDU session brought up by this data profile should be always-on.
+     * An always-on PDU Session is a PDU Session for which User Plane resources have to be
+     * activated during every transition from CM-IDLE mode to CM-CONNECTED state.
+     * See 3GPP TS 23.501 section 5.6.13 for the details.
+     */
+    boolean alwaysOn;
+    /**
+     * TrafficDescriptor for which data connection needs to be established.
+     * It is used for URSP traffic matching as described in TS 24.526 Section 4.2.2.
+     * It includes an optional DNN which, if present, must be used for traffic matching --
+     * it does not specify the end point to be used for the data call. The end point is specified by
+     * apn; apn must be used as the end point if one is not specified through URSP rules.
+     */
+    @nullable TrafficDescriptor trafficDescriptor;
 }
diff --git a/radio/aidl/android/hardware/radio/data/IRadioData.aidl b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
index 9f5ba4c..54a045c 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioData.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
@@ -219,12 +219,6 @@
      *        EPDG to 5G. It is valid only when accessNetwork is AccessNetwork:NGRAN. If the slice
      *        passed from EPDG is rejected, then the data failure cause must be
      *        DataCallFailCause:SLICE_REJECTED.
-     * @param trafficDescriptor TrafficDescriptor for which data connection needs to be established.
-     *        It is used for URSP traffic matching as described in TS 24.526 Section 4.2.2.
-     *        It includes an optional DNN which, if present, must be used for traffic matching --
-     *        it does not specify the end point to be used for the data call. The end point is
-     *        specified by DataProfileInfo.apn; DataProfileInfo.apn must be used as the end point if
-     *        one is not specified through URSP rules.
      * @param matchAllRuleAllowed bool to indicate if using default match-all URSP rule for this
      *        request is allowed. If false, this request must not use the match-all URSP rule and if
      *        a non-match-all rule is not found (or if URSP rules are not available) it should
@@ -238,7 +232,6 @@
             in DataProfileInfo dataProfileInfo, in boolean roamingAllowed,
             in DataRequestReason reason, in LinkAddress[] addresses, in String[] dnses,
             in int pduSessionId, in @nullable SliceInfo sliceInfo,
-            in @nullable TrafficDescriptor trafficDescriptor,
             in boolean matchAllRuleAllowed);
 
     /**
diff --git a/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl b/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl
index 8e73ee3..938c695 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl
@@ -17,9 +17,11 @@
 package android.hardware.radio.data;
 
 import android.hardware.radio.RadioIndicationType;
+import android.hardware.radio.data.DataProfileInfo;
 import android.hardware.radio.data.KeepaliveStatus;
 import android.hardware.radio.data.PcoDataInfo;
 import android.hardware.radio.data.SetupDataCallResult;
+import android.hardware.radio.data.SlicingConfig;
 
 /**
  * Interface declaring unsolicited radio indications for data APIs.
@@ -68,7 +70,20 @@
      * is sent, AOSP will no longer throttle calls to IRadioData.SetupDataCall for the given APN.
      *
      * @param type Type of radio indication
-     * @param apn Apn to unthrottle
+     * @param dataProfileInfo Data profile info.
      */
-    void unthrottleApn(in RadioIndicationType type, in String apn);
+    void unthrottleApn(in RadioIndicationType type, in DataProfileInfo dataProfileInfo);
+
+    /**
+     * Indicates the current slicing configuration including URSP rules and NSSAIs
+     * (configured, allowed and rejected). URSP stands for UE route selection policy and is defined
+     * in 3GPP TS 24.526 Section 4.2. An NSSAI is a collection of network slices. Each network slice
+     * is identified by an S-NSSAI and is represented by the struct SliceInfo. NSSAI and S-NSSAI
+     * are defined in 3GPP TS 24.501.
+     *
+     * @param type Type of radio indication
+     * @param slicingConfig Current slicing configuration
+     *
+     */
+    void slicingConfigChanged(in RadioIndicationType type, in SlicingConfig slicingConfig);
 }
diff --git a/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl b/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl
index 764a86d..d0aa695 100644
--- a/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl
+++ b/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.radio.modem;
 
+import android.hardware.radio.modem.ActivityStatsTechSpecificInfo;
+
 @VintfStability
 parcelable ActivityStatsInfo {
     /**
@@ -28,17 +30,10 @@
      */
     int idleModeTimeMs;
     /**
-     * Each index represent total time (in ms) during which the transmitter is active/awake for a
-     * particular power range as shown below.
-     * index 0 = tx_power < 0dBm
-     * index 1 = 0dBm < tx_power < 5dBm
-     * index 2 = 5dBm < tx_power < 15dBm
-     * index 3 = 15dBm < tx_power < 20dBm
-     * index 4 = tx_power > 20dBm
+     * Technology specific activity stats info.
+     * List of the activity stats for each RATs (2G, 3G, 4G and 5G) and frequency ranges (HIGH for
+     * sub6 and MMWAVE) in case of 5G. In case implementation doesn't have RAT specific activity
+     * stats then send only one activity stats info with RAT unknown.
      */
-    int[] txmModetimeMs;
-    /**
-     * Total time (in ms) for which receiver is active/awake and the transmitter is inactive
-     */
-    int rxModeTimeMs;
+    ActivityStatsTechSpecificInfo[] techSpecificInfo;
 }
diff --git a/radio/aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl b/radio/aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
new file mode 100644
index 0000000..fb14223
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.modem;
+
+import android.hardware.radio.AccessNetwork;
+
+@VintfStability
+parcelable ActivityStatsTechSpecificInfo {
+    /** Indicates the frequency range is unknown. */
+    const int FREQUENCY_RANGE_UNKNOWN = 0;
+    /** Indicates the frequency range is below 1GHz. */
+    const int FREQUENCY_RANGE_LOW = 1;
+    /** Indicates the frequency range is between 1GHz and 3GHz. */
+    const int FREQUENCY_RANGE_MID = 2;
+    /** Indicates the frequency range is between 3GHz and 6GHz. */
+    const int FREQUENCY_RANGE_HIGH = 3;
+    /** Indicates the frequency range is above 6GHz (millimeter wave frequency). */
+    const int FREQUENCY_RANGE_MMWAVE = 4;
+    /**
+     * Radio access technology. Set UNKNOWN if the Activity statistics
+     * is RAT independent.
+     */
+    AccessNetwork rat;
+    /**
+     * Frequency range. Values are FREQUENCY_RANGE_
+     * Set FREQUENCY_RANGE_UNKNOWN if the Activity statistics when frequency range
+     * is not applicable.
+     */
+    int frequencyRange;
+    /**
+     * Each index represent total time (in ms) during which the transmitter is active/awake for a
+     * particular power range as shown below.
+     * index 0 = tx_power <= 0dBm
+     * index 1 = 0dBm < tx_power <= 5dBm
+     * index 2 = 5dBm < tx_power <= 15dBm
+     * index 3 = 15dBm < tx_power <= 20dBm
+     * index 4 = tx_power > 20dBm
+     */
+    int[] txmModetimeMs;
+    /**
+     * Total time (in ms) for which receiver is active/awake and the transmitter is inactive
+     */
+    int rxModeTimeMs;
+}
diff --git a/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl b/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl
index b7b8ef3..9bd5f21 100644
--- a/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl
+++ b/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl
@@ -71,7 +71,7 @@
     /**
      * 32-bit bitmap of RadioAccessFamily.
      */
-    RadioAccessFamily raf;
+    int raf;
     /**
      * A UUID typically "com.xxxx.lmX" where X is the logical modem.
      * RadioConst:MAX_UUID_LENGTH is the max length.
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index 1081a75..7a22a9a 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -27,6 +27,7 @@
 import android.hardware.radio.network.RadioAccessSpecifier;
 import android.hardware.radio.network.RadioBandMode;
 import android.hardware.radio.network.SignalThresholdInfo;
+import android.hardware.radio.network.UsageSetting;
 
 /**
  * This interface is used by telephony and telecom to talk to cellular radio for network APIs.
@@ -194,7 +195,7 @@
      *
      * Response function is IRadioNetworkResponse.setAllowedNetworkTypesBitmapResponse()
      */
-    void setAllowedNetworkTypesBitmap(in int serial, in RadioAccessFamily networkTypeBitmap);
+    void setAllowedNetworkTypesBitmap(in int serial, in int networkTypeBitmap);
 
     /**
      * Assign a specified band for RF configuration.
@@ -252,7 +253,7 @@
      *
      * Response function is IRadioNetworkResponse.setIndicationFilterResponse()
      */
-    void setIndicationFilter(in int serial, in IndicationFilter indicationFilter);
+    void setIndicationFilter(in int serial, in int indicationFilter);
 
     /**
      * Sets the link capacity reporting criteria. The resulting reporting criteria are the AND of
@@ -416,4 +417,25 @@
      * Response function is IRadioNetworkResponse.supplyNetworkDepersonalizationResponse()
      */
     void supplyNetworkDepersonalization(in int serial, in String netPin);
+
+    /**
+     * Set the UE usage setting for data/voice centric usage.
+     *
+     * <p>Sets the usage setting in accordance with 3gpp 24.301 sec 4.3 and 3gpp 24.501 sec 4.3.
+     * <p>This value must be independently preserved for each SIM; (setting the value is not a
+     * "global" override).
+     *
+     * @param serial Serial number of request.
+     * @param usageSetting the usage setting for the current SIM.
+     */
+    oneway void setUsageSetting(in int serial, in UsageSetting usageSetting);
+
+    /**
+     * Get the UE usage setting for data/voice centric usage.
+     *
+     * <p>Gets the usage setting in accordance with 3gpp 24.301 sec 4.3 and 3gpp 24.501 sec 4.3.
+     *
+     * @param serial Serial number of request.
+     */
+    oneway void getUsageSetting(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
index ba7610d..6863ac3 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -136,8 +136,8 @@
      *        include the time spend in sleep / low power states. If it can not be guaranteed,
      *        there must not be any caching done at the modem and should fill in 0 for ageMs
      */
-    void nitzTimeReceived(in RadioIndicationType type, in String nitzTime,
-            in long receivedTimeMs, in long ageMs);
+    void nitzTimeReceived(
+            in RadioIndicationType type, in String nitzTime, in long receivedTimeMs, in long ageMs);
 
     /**
      * Report that Registration or a Location/Routing/Tracking Area update has failed.
@@ -165,7 +165,7 @@
      *        MAX_INT if this value is unused.
      */
     void registrationFailed(in RadioIndicationType type, in CellIdentity cellIdentity,
-            in String chosenPlmn, in Domain domain, in int causeCode, in int additionalCauseCode);
+            in String chosenPlmn, in int domain, in int causeCode, in int additionalCauseCode);
 
     /**
      * Indicates a restricted state change (eg, for Domain Specific Access Control).
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 429b5a8..e650321 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -31,6 +31,7 @@
 import android.hardware.radio.network.RadioBandMode;
 import android.hardware.radio.network.RegStateResult;
 import android.hardware.radio.network.SignalStrength;
+import android.hardware.radio.network.UsageSetting;
 
 /**
  * Interface declaring response functions to solicited radio requests for network APIs.
@@ -61,8 +62,7 @@
      *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      */
-    void getAllowedNetworkTypesBitmapResponse(
-            in RadioResponseInfo info, in RadioAccessFamily networkTypeBitmap);
+    void getAllowedNetworkTypesBitmapResponse(in RadioResponseInfo info, in int networkTypeBitmap);
 
     /**
      * @param info Response info struct containing response type, serial no. and error
@@ -549,4 +549,30 @@
      *   RadioError:SIM_ABSENT
      */
     void supplyNetworkDepersonalizationResponse(in RadioResponseInfo info, in int remainingRetries);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:SIM_ABSENT
+     */
+    oneway void setUsageSettingResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error.
+     * @param usageSetting the usage setting for the current SIM.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:SIM_ABSENT
+     */
+    oneway void getUsageSettingResponse(in RadioResponseInfo info, in UsageSetting usageSetting);
 }
diff --git a/radio/aidl/android/hardware/radio/network/UsageSetting.aidl b/radio/aidl/android/hardware/radio/network/UsageSetting.aidl
new file mode 100644
index 0000000..ba8fe93
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/UsageSetting.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+/**
+ * Cellular usage setting with values according to 3gpp 24.301 sec 4.3 and 3gpp 24.501 sec 4.3.
+ *
+ * <p>Also refer to "UE's usage setting" as defined in 3gpp 24.301 section 3.1 and 3gpp 23.221
+ * Annex A.
+ */
+@VintfStability
+@Backing(type="int")
+enum UsageSetting {
+    /**
+     * UE operates in voice-centric mode. Generally speaking, in this mode of operation, the UE
+     * will not remain camped on a cell or attached to a network unless that cell/network provides
+     * voice service.
+     */
+    VOICE_CENTRIC = 1,
+
+    /**
+     * UE operates in data-centric mode. Generally speaking, in this mode of operation, the UE
+     * will not reselect away from a cell/network that only provides data services.
+     */
+    DATA_CENTRIC = 2,
+}
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
index c731caf..7923b14 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
@@ -205,6 +205,12 @@
      * Open a new logical channel and select the given application. This command
      * reflects TS 27.007 "open logical channel" operation (+CCHO).
      *
+     * For MEP-A(Multiple enabled profile), only dedicated port 0 is ISDR selectable.
+     * e.g., Port0 - for ISDR access and Port1/Port2 - the currently active ports/subscriptions.
+     * Port 0 should be transparent to AP and iccLogicalChannel API should remain the same.
+     * Even if the ISDR request comes over port1 or port2, Modem would just internally convert the
+     * portID to port0 and add the real port index as the payload of MANAGE_CHANNEL command.
+     *
      * @param serial Serial number of request.
      * @param aid AID value, See ETSI 102.221 and 101.220.
      * @param p2 P2 value, described in ISO 7816-4. Ignore if equal to RadioConst:P2_CONSTANT_NO_P2
diff --git a/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl b/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl
index aa4dde2..ddc5d76 100644
--- a/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl
+++ b/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl
@@ -78,7 +78,7 @@
      * The bitfield of EmergencyServiceCategory(s). See EmergencyServiceCategory for the value of
      * each bit.
      */
-    EmergencyServiceCategory categories;
+    int categories;
     /**
      * The list of emergency Uniform Resource Names (URN).
      */
diff --git a/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl b/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl
index a012be4..b25e63d 100644
--- a/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl
+++ b/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl
@@ -117,9 +117,9 @@
      *
      * Response function is IRadioVoiceResponse.emergencyDialResponse()
      */
-    void emergencyDial(in int serial, in Dial dialInfo, in EmergencyServiceCategory categories,
-            in String[] urns, in EmergencyCallRouting routing,
-            in boolean hasKnownUserIntentEmergency, in boolean isTesting);
+    void emergencyDial(in int serial, in Dial dialInfo, in int categories, in String[] urns,
+            in EmergencyCallRouting routing, in boolean hasKnownUserIntentEmergency,
+            in boolean isTesting);
 
     /**
      * Request the radio's system selection module to exit emergency callback mode. Radio must not
diff --git a/radio/aidl/compat/OWNERS b/radio/aidl/compat/OWNERS
new file mode 100644
index 0000000..471d806
--- /dev/null
+++ b/radio/aidl/compat/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 20868
+include ../../1.0/vts/OWNERS
+twasilczyk@google.com
diff --git a/radio/aidl/compat/libradiocompat/Android.bp b/radio/aidl/compat/libradiocompat/Android.bp
index 43d9378..487d91b 100644
--- a/radio/aidl/compat/libradiocompat/Android.bp
+++ b/radio/aidl/compat/libradiocompat/Android.bp
@@ -28,7 +28,6 @@
     cflags: [
         "-Wall",
         "-Wextra",
-        //"-Wold-style-cast",  // TODO(b/203699028) enable after aosp/1900880 gets merged
         "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
     shared_libs: [
@@ -56,7 +55,10 @@
         "libutils",
     ],
     srcs: [
+        "CallbackManager.cpp",
+        "DriverContext.cpp",
         "RadioCompatBase.cpp",
+        "RadioIndication.cpp",
         "RadioResponse.cpp",
         "commonStructs.cpp",
         "config/RadioConfig.cpp",
diff --git a/radio/aidl/compat/libradiocompat/CallbackManager.cpp b/radio/aidl/compat/libradiocompat/CallbackManager.cpp
new file mode 100644
index 0000000..c2eaed1
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/CallbackManager.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libradiocompat/CallbackManager.h>
+
+#include <android-base/logging.h>
+
+using namespace std::literals::chrono_literals;
+
+namespace android::hardware::radio::compat {
+
+/**
+ * How much setter thread will wait with setting response functions after the last
+ * setResponseFunctions call from the framework. Subsequent calls from the framework reset the
+ * clock, so this number should be larger than the longest time between setResponseFunctions calls
+ * from the framework.
+ *
+ * Real world measurements with Cuttlefish give <10ms delay between Modem and Data and <2ms delays
+ * between all others.
+ */
+static constexpr auto kDelayedSetterDelay = 100ms;
+
+CallbackManager::CallbackManager(std::shared_ptr<DriverContext> context, sp<V1_5::IRadio> hidlHal)
+    : mHidlHal(hidlHal),
+      mRadioResponse(sp<compat::RadioResponse>::make(context)),
+      mRadioIndication(sp<compat::RadioIndication>::make(context)),
+      mDelayedSetterThread(&CallbackManager::delayedSetterThread, this) {}
+
+CallbackManager::~CallbackManager() {
+    {
+        std::unique_lock<std::mutex> lock(mDelayedSetterGuard);
+        mDelayedSetterDeadline = std::nullopt;
+        mDestroy = true;
+        mDelayedSetterCv.notify_all();
+    }
+    mDelayedSetterThread.join();
+}
+
+RadioResponse& CallbackManager::response() const {
+    return *mRadioResponse;
+}
+
+void CallbackManager::setResponseFunctionsDelayed() {
+    std::unique_lock<std::mutex> lock(mDelayedSetterGuard);
+    mDelayedSetterDeadline = std::chrono::steady_clock::now() + kDelayedSetterDelay;
+    mDelayedSetterCv.notify_all();
+}
+
+void CallbackManager::delayedSetterThread() {
+    while (!mDestroy) {
+        std::unique_lock<std::mutex> lock(mDelayedSetterGuard);
+        auto deadline = mDelayedSetterDeadline;
+
+        // not waiting to set response functions
+        if (!deadline) {
+            mDelayedSetterCv.wait(lock);
+            continue;
+        }
+
+        // waiting to set response functions, but not yet
+        if (*deadline > std::chrono::steady_clock::now()) {
+            mDelayedSetterCv.wait_until(lock, *deadline);
+            continue;
+        }
+
+        mHidlHal->setResponseFunctions(mRadioResponse, mRadioIndication).assertOk();
+        mDelayedSetterDeadline = std::nullopt;
+    }
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/DriverContext.cpp b/radio/aidl/compat/libradiocompat/DriverContext.cpp
new file mode 100644
index 0000000..a07173e
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/DriverContext.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libradiocompat/DriverContext.h>
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio;
+
+void DriverContext::addDataProfile(const aidl::data::DataProfileInfo& profile) {
+    mDataProfiles[profile.apn] = profile;
+}
+
+aidl::data::DataProfileInfo DriverContext::getDataProfile(const std::string& apn) {
+    const auto it = mDataProfiles.find(apn);
+    if (it != mDataProfiles.end()) return it->second;
+
+    // if not found in cache, return a made up default
+    return {
+            .apn = apn,
+    };
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/RadioCompatBase.cpp b/radio/aidl/compat/libradiocompat/RadioCompatBase.cpp
index a9eac68..2a2d7a3 100644
--- a/radio/aidl/compat/libradiocompat/RadioCompatBase.cpp
+++ b/radio/aidl/compat/libradiocompat/RadioCompatBase.cpp
@@ -20,16 +20,11 @@
 
 namespace android::hardware::radio::compat {
 
-RadioCompatBase::RadioCompatBase(sp<V1_5::IRadio> hidlHal, sp<RadioResponse> radioResponse,
-                                 sp<RadioIndication> radioIndication)
-    : mHal1_5(hidlHal),
+RadioCompatBase::RadioCompatBase(std::shared_ptr<DriverContext> context, sp<V1_5::IRadio> hidlHal,
+                                 std::shared_ptr<CallbackManager> cbMgr)
+    : mContext(context),
+      mHal1_5(hidlHal),
       mHal1_6(V1_6::IRadio::castFrom(hidlHal)),
-      mRadioResponse(radioResponse),
-      mRadioIndication(radioIndication) {}
-
-V1_6::IRadioResponse& RadioCompatBase::respond() {
-    CHECK(mRadioResponse) << "This shouldn't happen (response functions are passed in constructor)";
-    return *mRadioResponse;
-}
+      mCallbackManager(cbMgr) {}
 
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/RadioIndication.cpp b/radio/aidl/compat/libradiocompat/RadioIndication.cpp
new file mode 100644
index 0000000..30ef6a0
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/RadioIndication.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libradiocompat/RadioIndication.h>
+
+namespace android::hardware::radio::compat {
+
+RadioIndication::RadioIndication(std::shared_ptr<DriverContext> context) : mContext(context) {}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/RadioResponse.cpp b/radio/aidl/compat/libradiocompat/RadioResponse.cpp
index 35b0ac1..dab70cc 100644
--- a/radio/aidl/compat/libradiocompat/RadioResponse.cpp
+++ b/radio/aidl/compat/libradiocompat/RadioResponse.cpp
@@ -22,15 +22,20 @@
 
 namespace android::hardware::radio::compat {
 
+RadioResponse::RadioResponse(std::shared_ptr<DriverContext> context) : mContext(context) {}
+
 Return<void> RadioResponse::acknowledgeRequest(int32_t serial) {
     LOG_CALL << serial;
-    // TODO(b/203699028): send to correct requestor or confirm if spam is not a problem
-    if (mDataCb) mDataCb->acknowledgeRequest(serial);
-    if (mMessagingCb) mMessagingCb->acknowledgeRequest(serial);
-    if (mModemCb) mModemCb->acknowledgeRequest(serial);
-    if (mNetworkCb) mNetworkCb->acknowledgeRequest(serial);
-    if (mSimCb) mSimCb->acknowledgeRequest(serial);
-    if (mVoiceCb) mVoiceCb->acknowledgeRequest(serial);
+    /* We send ACKs to all callbacks instead of the one requested it to make implementation simpler.
+     * If it turns out to be a problem, we would have to track where serials come from and make sure
+     * this tracking data (e.g. a map) doesn't grow indefinitely.
+     */
+    if (mDataCb) mDataCb.get()->acknowledgeRequest(serial);
+    if (mMessagingCb) mMessagingCb.get()->acknowledgeRequest(serial);
+    if (mModemCb) mModemCb.get()->acknowledgeRequest(serial);
+    if (mNetworkCb) mNetworkCb.get()->acknowledgeRequest(serial);
+    if (mSimCb) mSimCb.get()->acknowledgeRequest(serial);
+    if (mVoiceCb) mVoiceCb.get()->acknowledgeRequest(serial);
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.cpp b/radio/aidl/compat/libradiocompat/commonStructs.cpp
index c25768d..6e4c873 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.cpp
+++ b/radio/aidl/compat/libradiocompat/commonStructs.cpp
@@ -20,11 +20,11 @@
 
 namespace aidl = ::aidl::android::hardware::radio;
 
-V1_6::RadioResponseInfo notSupported(int32_t serial) {
+aidl::RadioResponseInfo notSupported(int32_t serial) {
     return {
-            .type = V1_0::RadioResponseType::SOLICITED,
+            .type = aidl::RadioResponseType::SOLICITED,
             .serial = serial,
-            .error = V1_6::RadioError::REQUEST_NOT_SUPPORTED,
+            .error = aidl::RadioError::REQUEST_NOT_SUPPORTED,
     };
 }
 
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.h b/radio/aidl/compat/libradiocompat/commonStructs.h
index b859916..a4a4869 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.h
+++ b/radio/aidl/compat/libradiocompat/commonStructs.h
@@ -21,7 +21,7 @@
 
 namespace android::hardware::radio::compat {
 
-V1_6::RadioResponseInfo notSupported(int32_t serial);
+aidl::android::hardware::radio::RadioResponseInfo notSupported(int32_t serial);
 
 std::string toAidl(const hidl_string& str);
 hidl_string toHidl(const std::string& str);
diff --git a/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp b/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
index d0d6f7a..b450418 100644
--- a/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
+++ b/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
@@ -16,12 +16,12 @@
 
 #include <libradiocompat/RadioConfig.h>
 
-#include "RadioConfigIndication.h"
-#include "RadioConfigResponse.h"
 #include "commonStructs.h"
 #include "debug.h"
 #include "structs.h"
 
+#include "collections.h"
+
 #define RADIO_MODULE "Config"
 
 namespace android::hardware::radio::compat {
@@ -31,11 +31,13 @@
 constexpr auto ok = &ScopedAStatus::ok;
 
 RadioConfig::RadioConfig(sp<config::V1_1::IRadioConfig> hidlHal)
-    : mHal1_1(hidlHal), mHal1_3(config::V1_3::IRadioConfig::castFrom(hidlHal)) {}
+    : mHal1_1(hidlHal),
+      mHal1_3(config::V1_3::IRadioConfig::castFrom(hidlHal)),
+      mRadioConfigResponse(sp<RadioConfigResponse>::make()),
+      mRadioConfigIndication(sp<RadioConfigIndication>::make()) {}
 
-config::V1_3::IRadioConfigResponse& RadioConfig::respond() {
-    CHECK(mRadioConfigResponse) << "setResponseFunctions was not called yet";
-    return *mRadioConfigResponse;
+std::shared_ptr<aidl::IRadioConfigResponse> RadioConfig::respond() {
+    return mRadioConfigResponse->respond();
 }
 
 ScopedAStatus RadioConfig::getHalDeviceCapabilities(int32_t serial) {
@@ -43,7 +45,7 @@
     if (mHal1_3) {
         mHal1_3->getHalDeviceCapabilities(serial);
     } else {
-        respond().getHalDeviceCapabilitiesResponse(notSupported(serial), false);
+        respond()->getHalDeviceCapabilitiesResponse(notSupported(serial), false);
     }
     return ok();
 }
@@ -86,9 +88,9 @@
     CHECK(radioConfigResponse);
     CHECK(radioConfigIndication);
 
-    mRadioConfigResponse = sp<RadioConfigResponse>::make(radioConfigResponse);
-    mRadioConfigIndication = sp<RadioConfigIndication>::make(radioConfigIndication);
-    mHal1_1->setResponseFunctions(mRadioConfigResponse, mRadioConfigIndication);
+    mRadioConfigResponse->setResponseFunction(radioConfigResponse);
+    mRadioConfigIndication->setResponseFunction(radioConfigIndication);
+    mHal1_1->setResponseFunctions(mRadioConfigResponse, mRadioConfigIndication).assertOk();
 
     return ok();
 }
diff --git a/radio/aidl/compat/libradiocompat/config/RadioConfigIndication.cpp b/radio/aidl/compat/libradiocompat/config/RadioConfigIndication.cpp
index 0320ad7..c1e32c1 100644
--- a/radio/aidl/compat/libradiocompat/config/RadioConfigIndication.cpp
+++ b/radio/aidl/compat/libradiocompat/config/RadioConfigIndication.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "RadioConfigIndication.h"
+#include <libradiocompat/RadioConfigIndication.h>
 
 #include "commonStructs.h"
 #include "debug.h"
@@ -28,20 +28,26 @@
 
 namespace aidl = ::aidl::android::hardware::radio::config;
 
-RadioConfigIndication::RadioConfigIndication(std::shared_ptr<aidl::IRadioConfigIndication> callback)
-    : mCallback(callback) {}
+void RadioConfigIndication::setResponseFunction(
+        std::shared_ptr<aidl::IRadioConfigIndication> callback) {
+    mCallback = callback;
+}
+
+std::shared_ptr<aidl::IRadioConfigIndication> RadioConfigIndication::indicate() {
+    return mCallback.get();
+}
 
 Return<void> RadioConfigIndication::simSlotsStatusChanged(
         V1_0::RadioIndicationType type, const hidl_vec<config::V1_0::SimSlotStatus>& slotStatus) {
     LOG_CALL << type;
-    mCallback->simSlotsStatusChanged(toAidl(type), toAidl(slotStatus));
+    indicate()->simSlotsStatusChanged(toAidl(type), toAidl(slotStatus));
     return {};
 }
 
 Return<void> RadioConfigIndication::simSlotsStatusChanged_1_2(
         V1_0::RadioIndicationType type, const hidl_vec<config::V1_2::SimSlotStatus>& slotStatus) {
     LOG_CALL << type;
-    mCallback->simSlotsStatusChanged(toAidl(type), toAidl(slotStatus));
+    indicate()->simSlotsStatusChanged(toAidl(type), toAidl(slotStatus));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/config/RadioConfigIndication.h b/radio/aidl/compat/libradiocompat/config/RadioConfigIndication.h
deleted file mode 100644
index 3d8d971..0000000
--- a/radio/aidl/compat/libradiocompat/config/RadioConfigIndication.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <aidl/android/hardware/radio/config/IRadioConfigIndication.h>
-#include <android/hardware/radio/config/1.2/IRadioConfigIndication.h>
-
-namespace android::hardware::radio::compat {
-
-class RadioConfigIndication : public config::V1_2::IRadioConfigIndication {
-    std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigIndication> mCallback;
-
-    Return<void> simSlotsStatusChanged(
-            V1_0::RadioIndicationType type,
-            const hidl_vec<config::V1_0::SimSlotStatus>& slotStatus) override;
-    Return<void> simSlotsStatusChanged_1_2(
-            V1_0::RadioIndicationType type,
-            const hidl_vec<config::V1_2::SimSlotStatus>& slotStatus) override;
-
-  public:
-    RadioConfigIndication(
-            std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigIndication> cb);
-};
-
-}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/config/RadioConfigResponse.cpp b/radio/aidl/compat/libradiocompat/config/RadioConfigResponse.cpp
index 7066ae4..523c504 100644
--- a/radio/aidl/compat/libradiocompat/config/RadioConfigResponse.cpp
+++ b/radio/aidl/compat/libradiocompat/config/RadioConfigResponse.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "RadioConfigResponse.h"
+#include <libradiocompat/RadioConfigResponse.h>
 
 #include "commonStructs.h"
 #include "debug.h"
@@ -28,14 +28,20 @@
 
 namespace aidl = ::aidl::android::hardware::radio::config;
 
-RadioConfigResponse::RadioConfigResponse(std::shared_ptr<aidl::IRadioConfigResponse> callback)
-    : mCallback(callback) {}
+void RadioConfigResponse::setResponseFunction(
+        std::shared_ptr<aidl::IRadioConfigResponse> callback) {
+    mCallback = callback;
+}
+
+std::shared_ptr<aidl::IRadioConfigResponse> RadioConfigResponse::respond() {
+    return mCallback.get();
+}
 
 Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
         const V1_0::RadioResponseInfo& info,
         const hidl_vec<config::V1_0::SimSlotStatus>& slotStatus) {
     LOG_CALL << info.serial;
-    mCallback->getSimSlotsStatusResponse(toAidl(info), toAidl(slotStatus));
+    respond()->getSimSlotsStatusResponse(toAidl(info), toAidl(slotStatus));
     return {};
 };
 
@@ -43,47 +49,47 @@
         const V1_0::RadioResponseInfo& info,
         const hidl_vec<config::V1_2::SimSlotStatus>& slotStatus) {
     LOG_CALL << info.serial;
-    mCallback->getSimSlotsStatusResponse(toAidl(info), toAidl(slotStatus));
+    respond()->getSimSlotsStatusResponse(toAidl(info), toAidl(slotStatus));
     return {};
 };
 
 Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    mCallback->setSimSlotsMappingResponse(toAidl(info));
+    respond()->setSimSlotsMappingResponse(toAidl(info));
     return {};
 };
 
 Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
         const V1_0::RadioResponseInfo& info, const config::V1_1::PhoneCapability& phoneCapability) {
     LOG_CALL << info.serial;
-    mCallback->getPhoneCapabilityResponse(toAidl(info), toAidl(phoneCapability));
+    respond()->getPhoneCapabilityResponse(toAidl(info), toAidl(phoneCapability));
     return {};
 };
 
 Return<void> RadioConfigResponse::setPreferredDataModemResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    mCallback->setPreferredDataModemResponse(toAidl(info));
+    respond()->setPreferredDataModemResponse(toAidl(info));
     return {};
 };
 
 Return<void> RadioConfigResponse::setModemsConfigResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    mCallback->setNumOfLiveModemsResponse(toAidl(info));
+    respond()->setNumOfLiveModemsResponse(toAidl(info));
     return {};
 };
 
 Return<void> RadioConfigResponse::getModemsConfigResponse(
         const V1_0::RadioResponseInfo& info, const config::V1_1::ModemsConfig& modemsConfig) {
     LOG_CALL << info.serial;
-    mCallback->getNumOfLiveModemsResponse(toAidl(info), modemsConfig.numOfLiveModems);
+    respond()->getNumOfLiveModemsResponse(toAidl(info), modemsConfig.numOfLiveModems);
     return {};
 };
 
 Return<void> RadioConfigResponse::getHalDeviceCapabilitiesResponse(
         const V1_6::RadioResponseInfo& info, bool modemReducedFeatureSet1) {
     LOG_CALL << info.serial;
-    mCallback->getHalDeviceCapabilitiesResponse(toAidl(info), modemReducedFeatureSet1);
+    respond()->getHalDeviceCapabilitiesResponse(toAidl(info), modemReducedFeatureSet1);
     return {};
 };
 
diff --git a/radio/aidl/compat/libradiocompat/config/RadioConfigResponse.h b/radio/aidl/compat/libradiocompat/config/RadioConfigResponse.h
deleted file mode 100644
index 1461dd2..0000000
--- a/radio/aidl/compat/libradiocompat/config/RadioConfigResponse.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <aidl/android/hardware/radio/config/IRadioConfigResponse.h>
-#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
-
-namespace android::hardware::radio::compat {
-
-class RadioConfigResponse : public config::V1_3::IRadioConfigResponse {
-    std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigResponse> mCallback;
-
-    Return<void> getSimSlotsStatusResponse(
-            const V1_0::RadioResponseInfo& info,
-            const hidl_vec<config::V1_0::SimSlotStatus>& slotStatus) override;
-    Return<void> setSimSlotsMappingResponse(const V1_0::RadioResponseInfo& info) override;
-    Return<void> getPhoneCapabilityResponse(
-            const V1_0::RadioResponseInfo& info,
-            const config::V1_1::PhoneCapability& phoneCapability) override;
-    Return<void> setPreferredDataModemResponse(const V1_0::RadioResponseInfo& info) override;
-    Return<void> setModemsConfigResponse(const V1_0::RadioResponseInfo& info) override;
-    Return<void> getModemsConfigResponse(const V1_0::RadioResponseInfo& info,
-                                         const config::V1_1::ModemsConfig& modemsConfig) override;
-    Return<void> getSimSlotsStatusResponse_1_2(
-            const V1_0::RadioResponseInfo& info,
-            const hidl_vec<config::V1_2::SimSlotStatus>& slotStatus) override;
-    Return<void> getHalDeviceCapabilitiesResponse(const V1_6::RadioResponseInfo& info,
-                                                  bool modemReducedFeatureSet1) override;
-
-  public:
-    RadioConfigResponse(
-            std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigResponse> callback);
-};
-
-}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/config/structs.cpp b/radio/aidl/compat/libradiocompat/config/structs.cpp
index 9ba5623..39ad944 100644
--- a/radio/aidl/compat/libradiocompat/config/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/config/structs.cpp
@@ -24,14 +24,11 @@
 
 namespace aidl = ::aidl::android::hardware::radio::config;
 
-hidl_vec<uint32_t> toHidl(const std::vector<aidl::SlotPortMapping>& slotMap) {
-    hidl_vec<uint32_t> out(slotMap.size());
-    for (const auto& el : slotMap) {
-        CHECK_GE(el.portId, 0);
-        CHECK_LT(static_cast<size_t>(el.portId), out.size());
-        out[el.portId] = el.physicalSlotId;
+uint32_t toHidl(const aidl::SlotPortMapping& slotPortMapping) {
+    if (slotPortMapping.portId != 0) {
+        LOG(ERROR) << "Port ID " << slotPortMapping.portId << " != 0 not supported by HIDL HAL";
     }
-    return out;
+    return slotPortMapping.physicalSlotId;
 }
 
 aidl::SimSlotStatus toAidl(const config::V1_0::SimSlotStatus& sst) {
diff --git a/radio/aidl/compat/libradiocompat/config/structs.h b/radio/aidl/compat/libradiocompat/config/structs.h
index b8a0385..6ea4e4a 100644
--- a/radio/aidl/compat/libradiocompat/config/structs.h
+++ b/radio/aidl/compat/libradiocompat/config/structs.h
@@ -23,8 +23,7 @@
 
 namespace android::hardware::radio::compat {
 
-hidl_vec<uint32_t>  //
-toHidl(const std::vector<aidl::android::hardware::radio::config::SlotPortMapping>& slotMap);
+uint32_t toHidl(const aidl::android::hardware::radio::config::SlotPortMapping& slotPortMapping);
 
 aidl::android::hardware::radio::config::SimSlotStatus  //
 toAidl(const config::V1_0::SimSlotStatus& sst);
diff --git a/radio/aidl/compat/libradiocompat/data/RadioData.cpp b/radio/aidl/compat/libradiocompat/data/RadioData.cpp
index fdb1273..d2f3687 100644
--- a/radio/aidl/compat/libradiocompat/data/RadioData.cpp
+++ b/radio/aidl/compat/libradiocompat/data/RadioData.cpp
@@ -31,12 +31,16 @@
 namespace aidlCommon = ::aidl::android::hardware::radio;
 constexpr auto ok = &ScopedAStatus::ok;
 
+std::shared_ptr<aidl::IRadioDataResponse> RadioData::respond() {
+    return mCallbackManager->response().dataCb();
+}
+
 ScopedAStatus RadioData::allocatePduSessionId(int32_t serial) {
     LOG_CALL << serial;
     if (mHal1_6) {
         mHal1_6->allocatePduSessionId(serial);
     } else {
-        respond().allocatePduSessionIdResponse(notSupported(serial), 0);
+        respond()->allocatePduSessionIdResponse(notSupported(serial), 0);
     }
     return ok();
 }
@@ -46,7 +50,7 @@
     if (mHal1_6) {
         mHal1_6->cancelHandover(serial, callId);
     } else {
-        respond().cancelHandoverResponse(notSupported(serial));
+        respond()->cancelHandoverResponse(notSupported(serial));
     }
     return ok();
 }
@@ -60,7 +64,11 @@
 
 ScopedAStatus RadioData::getDataCallList(int32_t serial) {
     LOG_CALL << serial;
-    mHal1_5->getDataCallList(serial);
+    if (mHal1_6) {
+        mHal1_6->getDataCallList_1_6(serial);
+    } else {
+        mHal1_5->getDataCallList(serial);
+    }
     return ok();
 }
 
@@ -69,7 +77,7 @@
     if (mHal1_6) {
         mHal1_6->getSlicingConfig(serial);
     } else {
-        respond().getSlicingConfigResponse(notSupported(serial), {});
+        respond()->getSlicingConfigResponse(notSupported(serial), {});
     }
     return ok();
 }
@@ -79,7 +87,7 @@
     if (mHal1_6) {
         mHal1_6->releasePduSessionId(serial, id);
     } else {
-        respond().releasePduSessionIdResponse(notSupported(serial));
+        respond()->releasePduSessionIdResponse(notSupported(serial));
     }
     return ok();
 }
@@ -109,7 +117,7 @@
     if (mHal1_6) {
         mHal1_6->setDataThrottling(serial, V1_6::DataThrottlingAction(dta), completionDurationMs);
     } else {
-        respond().setDataThrottlingResponse(notSupported(serial));
+        respond()->setDataThrottlingResponse(notSupported(serial));
     }
     return ok();
 }
@@ -121,16 +129,10 @@
 }
 
 ScopedAStatus RadioData::setResponseFunctions(
-        const std::shared_ptr<aidl::IRadioDataResponse>& dataResponse,
-        const std::shared_ptr<aidl::IRadioDataIndication>& dataIndication) {
-    LOG_CALL << dataResponse << ' ' << dataIndication;
-
-    CHECK(dataResponse);
-    CHECK(dataIndication);
-
-    mRadioResponse->setResponseFunction(dataResponse);
-    mRadioIndication->setResponseFunction(dataIndication);
-
+        const std::shared_ptr<aidl::IRadioDataResponse>& response,
+        const std::shared_ptr<aidl::IRadioDataIndication>& indication) {
+    LOG_CALL << response << ' ' << indication;
+    mCallbackManager->setResponseFunctions(response, indication);
     return ok();
 }
 
@@ -139,14 +141,15 @@
         const aidl::DataProfileInfo& dataProfileInfo, bool roamingAllowed,
         aidl::DataRequestReason reason, const std::vector<aidl::LinkAddress>& addresses,
         const std::vector<std::string>& dnses, int32_t pduSessId,
-        const std::optional<aidl::SliceInfo>& sliceInfo,
-        const std::optional<aidl::TrafficDescriptor>& trDesc, bool matchAllRuleAllowed) {
+        const std::optional<aidl::SliceInfo>& sliceInfo, bool matchAllRuleAllowed) {
     if (mHal1_6) {
         mHal1_6->setupDataCall_1_6(  //
                 serial, V1_5::AccessNetwork(accessNetwork), toHidl(dataProfileInfo), roamingAllowed,
                 V1_2::DataRequestReason(reason), toHidl(addresses), toHidl(dnses), pduSessId,
                 toHidl<V1_6::OptionalSliceInfo>(sliceInfo),
-                toHidl<V1_6::OptionalTrafficDescriptor>(trDesc), matchAllRuleAllowed);
+                toHidl<V1_6::OptionalTrafficDescriptor>(dataProfileInfo.trafficDescriptor),
+                matchAllRuleAllowed);
+        mContext->addDataProfile(dataProfileInfo);
     } else {
         mHal1_5->setupDataCall_1_5(  //
                 serial, V1_5::AccessNetwork(accessNetwork), toHidl(dataProfileInfo), roamingAllowed,
@@ -160,7 +163,7 @@
     if (mHal1_6) {
         mHal1_6->startHandover(serial, callId);
     } else {
-        respond().startHandoverResponse(notSupported(serial));
+        respond()->startHandoverResponse(notSupported(serial));
     }
     return ok();
 }
diff --git a/radio/aidl/compat/libradiocompat/data/RadioIndication-data.cpp b/radio/aidl/compat/libradiocompat/data/RadioIndication-data.cpp
index f51d1a8..602bb39 100644
--- a/radio/aidl/compat/libradiocompat/data/RadioIndication-data.cpp
+++ b/radio/aidl/compat/libradiocompat/data/RadioIndication-data.cpp
@@ -29,10 +29,13 @@
 namespace aidl = ::aidl::android::hardware::radio::data;
 
 void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioDataIndication> dataCb) {
-    CHECK(dataCb);
     mDataCb = dataCb;
 }
 
+std::shared_ptr<aidl::IRadioDataIndication> RadioIndication::dataCb() {
+    return mDataCb.get();
+}
+
 Return<void> RadioIndication::dataCallListChanged(V1_0::RadioIndicationType type,
                                                   const hidl_vec<V1_0::SetupDataCallResult>&) {
     LOG_CALL << type;
@@ -50,40 +53,42 @@
 Return<void> RadioIndication::dataCallListChanged_1_5(
         V1_0::RadioIndicationType type, const hidl_vec<V1_5::SetupDataCallResult>& dcList) {
     LOG_CALL << type;
-    CHECK_CB(mDataCb);
-    mDataCb->dataCallListChanged(toAidl(type), toAidl(dcList));
+    dataCb()->dataCallListChanged(toAidl(type), toAidl(dcList));
     return {};
 }
 
 Return<void> RadioIndication::dataCallListChanged_1_6(
         V1_0::RadioIndicationType type, const hidl_vec<V1_6::SetupDataCallResult>& dcList) {
     LOG_CALL << type;
-    CHECK_CB(mDataCb);
-    mDataCb->dataCallListChanged(toAidl(type), toAidl(dcList));
+    dataCb()->dataCallListChanged(toAidl(type), toAidl(dcList));
     return {};
 }
 
 Return<void> RadioIndication::keepaliveStatus(V1_0::RadioIndicationType type,
                                               const V1_1::KeepaliveStatus& status) {
     LOG_CALL << type;
-    CHECK_CB(mDataCb);
-    mDataCb->keepaliveStatus(toAidl(type), toAidl(status));
+    dataCb()->keepaliveStatus(toAidl(type), toAidl(status));
     return {};
 }
 
 Return<void> RadioIndication::pcoData(V1_0::RadioIndicationType type,
                                       const V1_0::PcoDataInfo& pco) {
     LOG_CALL << type;
-    CHECK_CB(mDataCb);
-    mDataCb->pcoData(toAidl(type), toAidl(pco));
+    dataCb()->pcoData(toAidl(type), toAidl(pco));
     return {};
 }
 
 Return<void> RadioIndication::unthrottleApn(V1_0::RadioIndicationType type,
                                             const hidl_string& apn) {
     LOG_CALL << type;
-    CHECK_CB(mDataCb);
-    mDataCb->unthrottleApn(toAidl(type), apn);
+    dataCb()->unthrottleApn(toAidl(type), mContext->getDataProfile(apn));
+    return {};
+}
+
+Return<void> RadioIndication::slicingConfigChanged(V1_0::RadioIndicationType type,
+                                                   const V1_6::SlicingConfig& slicingConfig) {
+    LOG_CALL << type;
+    dataCb()->slicingConfigChanged(toAidl(type), toAidl(slicingConfig));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/data/RadioResponse-data.cpp b/radio/aidl/compat/libradiocompat/data/RadioResponse-data.cpp
index 171f692..0bfa2df 100644
--- a/radio/aidl/compat/libradiocompat/data/RadioResponse-data.cpp
+++ b/radio/aidl/compat/libradiocompat/data/RadioResponse-data.cpp
@@ -29,29 +29,29 @@
 namespace aidl = ::aidl::android::hardware::radio::data;
 
 void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioDataResponse> dataCb) {
-    CHECK(dataCb);
     mDataCb = dataCb;
 }
 
+std::shared_ptr<aidl::IRadioDataResponse> RadioResponse::dataCb() {
+    return mDataCb.get();
+}
+
 Return<void> RadioResponse::allocatePduSessionIdResponse(const V1_6::RadioResponseInfo& info,
                                                          int32_t id) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->allocatePduSessionIdResponse(toAidl(info), id);
+    dataCb()->allocatePduSessionIdResponse(toAidl(info), id);
     return {};
 }
 
 Return<void> RadioResponse::cancelHandoverResponse(const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->cancelHandoverResponse(toAidl(info));
+    dataCb()->cancelHandoverResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::deactivateDataCallResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->deactivateDataCallResponse(toAidl(info));
+    dataCb()->deactivateDataCallResponse(toAidl(info));
     return {};
 }
 
@@ -73,8 +73,7 @@
         const V1_0::RadioResponseInfo& info,
         const hidl_vec<V1_5::SetupDataCallResult>& dcResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->getDataCallListResponse(toAidl(info), toAidl(dcResponse));
+    dataCb()->getDataCallListResponse(toAidl(info), toAidl(dcResponse));
     return {};
 }
 
@@ -82,65 +81,56 @@
         const V1_6::RadioResponseInfo& info,
         const hidl_vec<V1_6::SetupDataCallResult>& dcResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->getDataCallListResponse(toAidl(info), toAidl(dcResponse));
+    dataCb()->getDataCallListResponse(toAidl(info), toAidl(dcResponse));
     return {};
 }
 
 Return<void> RadioResponse::getSlicingConfigResponse(const V1_6::RadioResponseInfo& info,
                                                      const V1_6::SlicingConfig& slicingConfig) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->getSlicingConfigResponse(toAidl(info), toAidl(slicingConfig));
+    dataCb()->getSlicingConfigResponse(toAidl(info), toAidl(slicingConfig));
     return {};
 }
 
 Return<void> RadioResponse::releasePduSessionIdResponse(const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->releasePduSessionIdResponse(toAidl(info));
+    dataCb()->releasePduSessionIdResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setDataAllowedResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setDataAllowedResponse(toAidl(info));
+    dataCb()->setDataAllowedResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setDataProfileResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setDataProfileResponse(toAidl(info));
+    dataCb()->setDataProfileResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setDataProfileResponse_1_5(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setDataProfileResponse(toAidl(info));
+    dataCb()->setDataProfileResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setDataThrottlingResponse(const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setDataThrottlingResponse(toAidl(info));
+    dataCb()->setDataThrottlingResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setInitialAttachApnResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setInitialAttachApnResponse(toAidl(info));
+    dataCb()->setInitialAttachApnResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setInitialAttachApnResponse_1_5(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setInitialAttachApnResponse(toAidl(info));
+    dataCb()->setInitialAttachApnResponse(toAidl(info));
     return {};
 }
 
@@ -161,38 +151,33 @@
 Return<void> RadioResponse::setupDataCallResponse_1_5(const V1_0::RadioResponseInfo& info,
                                                       const V1_5::SetupDataCallResult& dcResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setupDataCallResponse(toAidl(info), toAidl(dcResponse));
+    dataCb()->setupDataCallResponse(toAidl(info), toAidl(dcResponse));
     return {};
 }
 
 Return<void> RadioResponse::setupDataCallResponse_1_6(const V1_6::RadioResponseInfo& info,
                                                       const V1_6::SetupDataCallResult& dcResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->setupDataCallResponse(toAidl(info), toAidl(dcResponse));
+    dataCb()->setupDataCallResponse(toAidl(info), toAidl(dcResponse));
     return {};
 }
 
 Return<void> RadioResponse::startHandoverResponse(const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->startHandoverResponse(toAidl(info));
+    dataCb()->startHandoverResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::startKeepaliveResponse(const V1_0::RadioResponseInfo& info,
                                                    const V1_1::KeepaliveStatus& status) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->startKeepaliveResponse(toAidl(info), toAidl(status));
+    dataCb()->startKeepaliveResponse(toAidl(info), toAidl(status));
     return {};
 }
 
 Return<void> RadioResponse::stopKeepaliveResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mDataCb);
-    mDataCb->stopKeepaliveResponse(toAidl(info));
+    dataCb()->stopKeepaliveResponse(toAidl(info));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/debug.h b/radio/aidl/compat/libradiocompat/debug.h
index 4158059..cb773bf 100644
--- a/radio/aidl/compat/libradiocompat/debug.h
+++ b/radio/aidl/compat/libradiocompat/debug.h
@@ -26,12 +26,6 @@
 #define LOG_CALL \
     if constexpr (debug::kSuperVerbose) LOG(VERBOSE) << (RADIO_MODULE ".") << __func__ << ' '
 
-#define CHECK_CB(field)                     \
-    if (!field) {                           \
-        LOG(WARNING) << "Callback not set"; \
-        return {};                          \
-    }
-
 }  // namespace debug
 
 inline std::ostream& operator<<(std::ostream& os, const V1_0::RadioIndicationType& type) {
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/CallbackManager.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/CallbackManager.h
new file mode 100644
index 0000000..f1a7b49
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/CallbackManager.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "DriverContext.h"
+#include "RadioIndication.h"
+#include "RadioResponse.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/radio/1.6/IRadio.h>
+
+#include <thread>
+
+namespace android::hardware::radio::compat {
+
+class CallbackManager {
+    sp<V1_5::IRadio> mHidlHal;
+    sp<RadioResponse> mRadioResponse;
+    sp<RadioIndication> mRadioIndication;
+
+    std::thread mDelayedSetterThread;
+    std::mutex mDelayedSetterGuard;
+    std::optional<std::chrono::time_point<std::chrono::steady_clock>> mDelayedSetterDeadline
+            GUARDED_BY(mDelayedSetterGuard);
+    std::condition_variable mDelayedSetterCv GUARDED_BY(mDelayedSetterGuard);
+    bool mDestroy GUARDED_BY(mDelayedSetterGuard) = false;
+
+    void setResponseFunctionsDelayed();
+    void delayedSetterThread();
+
+  public:
+    CallbackManager(std::shared_ptr<DriverContext> context, sp<V1_5::IRadio> hidlHal);
+    ~CallbackManager();
+
+    RadioResponse& response() const;
+
+    template <typename ResponseType, typename IndicationType>
+    void setResponseFunctions(const std::shared_ptr<ResponseType>& response,
+                              const std::shared_ptr<IndicationType>& indication) {
+        CHECK(response);
+        CHECK(indication);
+
+        mRadioResponse->setResponseFunction(response);
+        mRadioIndication->setResponseFunction(indication);
+        setResponseFunctionsDelayed();
+    }
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/DriverContext.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/DriverContext.h
new file mode 100644
index 0000000..6833aca
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/DriverContext.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/radio/data/DataProfileInfo.h>
+
+#include <map>
+
+namespace android::hardware::radio::compat {
+
+class DriverContext {
+    std::map<std::string, ::aidl::android::hardware::radio::data::DataProfileInfo> mDataProfiles;
+
+  public:
+    void addDataProfile(const ::aidl::android::hardware::radio::data::DataProfileInfo& profile);
+    ::aidl::android::hardware::radio::data::DataProfileInfo getDataProfile(const std::string& apn);
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/GuaranteedCallback.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/GuaranteedCallback.h
new file mode 100644
index 0000000..0b6ee11
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/GuaranteedCallback.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <utils/Mutex.h>
+
+namespace android::hardware::radio::compat {
+
+template <typename Interface, typename DefaultImplementation, bool isIndication = false>
+class GuaranteedCallback {
+    mutable std::mutex mCallbackGuard;
+    std::shared_ptr<Interface> mCallback GUARDED_BY(mCallbackGuard);
+
+  public:
+    GuaranteedCallback<Interface, DefaultImplementation, isIndication>& operator=(
+            const std::shared_ptr<Interface>& callback) {
+        CHECK(callback);
+        const std::lock_guard<std::mutex> lock(mCallbackGuard);
+        mCallback = callback;
+        return *this;
+    }
+
+    std::shared_ptr<Interface> get() {
+        if (mCallback) return mCallback;
+        const std::lock_guard<std::mutex> lock(mCallbackGuard);
+        if (mCallback) return mCallback;
+
+        LOG(isIndication ? WARNING : ERROR) << "Callback is not set";
+        return mCallback = ndk::SharedRefBase::make<DefaultImplementation>();
+    }
+
+    operator bool() const { return mCallback != nullptr; }
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioCompatBase.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioCompatBase.h
index a412c34..eb22fff 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioCompatBase.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioCompatBase.h
@@ -15,8 +15,8 @@
  */
 #pragma once
 
-#include "RadioIndication.h"
-#include "RadioResponse.h"
+#include "CallbackManager.h"
+#include "DriverContext.h"
 
 #include <android/hardware/radio/1.6/IRadio.h>
 
@@ -24,17 +24,16 @@
 
 class RadioCompatBase {
   protected:
+    std::shared_ptr<DriverContext> mContext;
+
     sp<V1_5::IRadio> mHal1_5;
     sp<V1_6::IRadio> mHal1_6;
 
-    sp<RadioResponse> mRadioResponse;
-    sp<RadioIndication> mRadioIndication;
-
-    V1_6::IRadioResponse& respond();
+    std::shared_ptr<CallbackManager> mCallbackManager;
 
   public:
-    RadioCompatBase(sp<V1_5::IRadio> hidlHal, sp<RadioResponse> radioResponse,
-                    sp<RadioIndication> radioIndication);
+    RadioCompatBase(std::shared_ptr<DriverContext> context, sp<V1_5::IRadio> hidlHal,
+                    std::shared_ptr<CallbackManager> cbMgr);
 };
 
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
index 31ad207..bbfff61 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
@@ -15,6 +15,9 @@
  */
 #pragma once
 
+#include "RadioConfigIndication.h"
+#include "RadioConfigResponse.h"
+
 #include <aidl/android/hardware/radio/config/BnRadioConfig.h>
 #include <android/hardware/radio/config/1.2/IRadioConfigIndication.h>
 #include <android/hardware/radio/config/1.3/IRadioConfig.h>
@@ -30,11 +33,13 @@
  * fetch source implementation and publish resulting HAL instance.
  */
 class RadioConfig : public aidl::android::hardware::radio::config::BnRadioConfig {
-    sp<config::V1_1::IRadioConfig> mHal1_1;
-    sp<config::V1_3::IRadioConfig> mHal1_3;
+    const sp<config::V1_1::IRadioConfig> mHal1_1;
+    const sp<config::V1_3::IRadioConfig> mHal1_3;
 
-    sp<config::V1_3::IRadioConfigResponse> mRadioConfigResponse;
-    sp<config::V1_2::IRadioConfigIndication> mRadioConfigIndication;
+    const sp<RadioConfigResponse> mRadioConfigResponse;
+    const sp<RadioConfigIndication> mRadioConfigIndication;
+
+    std::shared_ptr<::aidl::android::hardware::radio::config::IRadioConfigResponse> respond();
 
     ::ndk::ScopedAStatus getHalDeviceCapabilities(int32_t serial) override;
     ::ndk::ScopedAStatus getNumOfLiveModems(int32_t serial) override;
@@ -52,8 +57,6 @@
             const std::vector<aidl::android::hardware::radio::config::SlotPortMapping>& slotMap)
             override;
 
-    config::V1_3::IRadioConfigResponse& respond();
-
   public:
     /**
      * Constructs AIDL IRadioConfig instance wrapping existing HIDL IRadioConfig instance.
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfigIndication.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfigIndication.h
new file mode 100644
index 0000000..d256a87
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfigIndication.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "GuaranteedCallback.h"
+
+#include <aidl/android/hardware/radio/config/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.2/IRadioConfigIndication.h>
+
+namespace android::hardware::radio::compat {
+
+class RadioConfigIndication : public config::V1_2::IRadioConfigIndication {
+    GuaranteedCallback<aidl::android::hardware::radio::config::IRadioConfigIndication,
+                       aidl::android::hardware::radio::config::IRadioConfigIndicationDefault, true>
+            mCallback;
+
+    Return<void> simSlotsStatusChanged(
+            V1_0::RadioIndicationType type,
+            const hidl_vec<config::V1_0::SimSlotStatus>& slotStatus) override;
+    Return<void> simSlotsStatusChanged_1_2(
+            V1_0::RadioIndicationType type,
+            const hidl_vec<config::V1_2::SimSlotStatus>& slotStatus) override;
+
+  public:
+    void setResponseFunction(
+            std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigIndication> cb);
+
+    std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigIndication> indicate();
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfigResponse.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfigResponse.h
new file mode 100644
index 0000000..dc86da2
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfigResponse.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include "GuaranteedCallback.h"
+
+#include <aidl/android/hardware/radio/config/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+
+namespace android::hardware::radio::compat {
+
+class RadioConfigResponse : public config::V1_3::IRadioConfigResponse {
+    GuaranteedCallback<aidl::android::hardware::radio::config::IRadioConfigResponse,
+                       aidl::android::hardware::radio::config::IRadioConfigResponseDefault>
+            mCallback;
+
+    Return<void> getSimSlotsStatusResponse(
+            const V1_0::RadioResponseInfo& info,
+            const hidl_vec<config::V1_0::SimSlotStatus>& slotStatus) override;
+    Return<void> setSimSlotsMappingResponse(const V1_0::RadioResponseInfo& info) override;
+    Return<void> getPhoneCapabilityResponse(
+            const V1_0::RadioResponseInfo& info,
+            const config::V1_1::PhoneCapability& phoneCapability) override;
+    Return<void> setPreferredDataModemResponse(const V1_0::RadioResponseInfo& info) override;
+    Return<void> setModemsConfigResponse(const V1_0::RadioResponseInfo& info) override;
+    Return<void> getModemsConfigResponse(const V1_0::RadioResponseInfo& info,
+                                         const config::V1_1::ModemsConfig& modemsConfig) override;
+    Return<void> getSimSlotsStatusResponse_1_2(
+            const V1_0::RadioResponseInfo& info,
+            const hidl_vec<config::V1_2::SimSlotStatus>& slotStatus) override;
+    Return<void> getHalDeviceCapabilitiesResponse(const V1_6::RadioResponseInfo& info,
+                                                  bool modemReducedFeatureSet1) override;
+
+  public:
+    void setResponseFunction(
+            std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigResponse> callback);
+
+    std::shared_ptr<aidl::android::hardware::radio::config::IRadioConfigResponse> respond();
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioData.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioData.h
index 900a669..c617ec2 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioData.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioData.h
@@ -22,6 +22,8 @@
 namespace android::hardware::radio::compat {
 
 class RadioData : public RadioCompatBase, public aidl::android::hardware::radio::data::BnRadioData {
+    std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataResponse> respond();
+
     ::ndk::ScopedAStatus allocatePduSessionId(int32_t serial) override;
     ::ndk::ScopedAStatus cancelHandover(int32_t serial, int32_t callId) override;
     ::ndk::ScopedAStatus deactivateDataCall(
@@ -55,7 +57,6 @@
             const std::vector<::aidl::android::hardware::radio::data::LinkAddress>& addresses,
             const std::vector<std::string>& dnses, int32_t pduSessionId,
             const std::optional<::aidl::android::hardware::radio::data::SliceInfo>& sliceInfo,
-            const std::optional<::aidl::android::hardware::radio::data::TrafficDescriptor>& trDescr,
             bool matchAllRuleAllowed) override;
     ::ndk::ScopedAStatus startHandover(int32_t serial, int32_t callId) override;
     ::ndk::ScopedAStatus startKeepalive(
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
index 20e0973..6cfd59c 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
@@ -15,6 +15,9 @@
  */
 #pragma once
 
+#include "DriverContext.h"
+#include "GuaranteedCallback.h"
+
 #include <aidl/android/hardware/radio/data/IRadioDataIndication.h>
 #include <aidl/android/hardware/radio/messaging/IRadioMessagingIndication.h>
 #include <aidl/android/hardware/radio/modem/IRadioModemIndication.h>
@@ -26,13 +29,32 @@
 namespace android::hardware::radio::compat {
 
 class RadioIndication : public V1_6::IRadioIndication {
-    std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataIndication> mDataCb;
-    std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingIndication>
+    std::shared_ptr<DriverContext> mContext;
+
+    GuaranteedCallback<  //
+            ::aidl::android::hardware::radio::data::IRadioDataIndication,
+            ::aidl::android::hardware::radio::data::IRadioDataIndicationDefault, true>
+            mDataCb;
+    GuaranteedCallback<  //
+            ::aidl::android::hardware::radio::messaging::IRadioMessagingIndication,
+            ::aidl::android::hardware::radio::messaging::IRadioMessagingIndicationDefault, true>
             mMessagingCb;
-    std::shared_ptr<::aidl::android::hardware::radio::modem::IRadioModemIndication> mModemCb;
-    std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkIndication> mNetworkCb;
-    std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimIndication> mSimCb;
-    std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceIndication> mVoiceCb;
+    GuaranteedCallback<  //
+            ::aidl::android::hardware::radio::modem::IRadioModemIndication,
+            ::aidl::android::hardware::radio::modem::IRadioModemIndicationDefault, true>
+            mModemCb;
+    GuaranteedCallback<  //
+            ::aidl::android::hardware::radio::network::IRadioNetworkIndication,
+            ::aidl::android::hardware::radio::network::IRadioNetworkIndicationDefault, true>
+            mNetworkCb;
+    GuaranteedCallback<  //
+            ::aidl::android::hardware::radio::sim::IRadioSimIndication,
+            ::aidl::android::hardware::radio::sim::IRadioSimIndicationDefault, true>
+            mSimCb;
+    GuaranteedCallback<  //
+            ::aidl::android::hardware::radio::voice::IRadioVoiceIndication,
+            ::aidl::android::hardware::radio::voice::IRadioVoiceIndicationDefault, true>
+            mVoiceCb;
 
     // IRadioIndication @ 1.0
     Return<void> radioStateChanged(V1_0::RadioIndicationType type,
@@ -164,6 +186,8 @@
             V1_0::RadioIndicationType type,
             const hidl_vec<V1_6::SetupDataCallResult>& dcList) override;
     Return<void> unthrottleApn(V1_0::RadioIndicationType type, const hidl_string& apn) override;
+    Return<void> slicingConfigChanged(V1_0::RadioIndicationType type,
+                                      const V1_6::SlicingConfig& slicingConfig);
     Return<void> currentLinkCapacityEstimate_1_6(V1_0::RadioIndicationType type,
                                                  const V1_6::LinkCapacityEstimate& lce) override;
     Return<void> currentSignalStrength_1_6(V1_0::RadioIndicationType type,
@@ -181,6 +205,8 @@
             const hidl_vec<V1_6::PhonebookRecordInfo>& records) override;
 
   public:
+    RadioIndication(std::shared_ptr<DriverContext> context);
+
     void setResponseFunction(
             std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataIndication> dataCb);
     void setResponseFunction(
@@ -194,6 +220,14 @@
             std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimIndication> simCb);
     void setResponseFunction(
             std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceIndication> voicCb);
+
+    std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataIndication> dataCb();
+    std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingIndication>
+    messagingCb();
+    std::shared_ptr<::aidl::android::hardware::radio::modem::IRadioModemIndication> modemCb();
+    std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkIndication> networkCb();
+    std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimIndication> simCb();
+    std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceIndication> voiceCb();
 };
 
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioMessaging.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioMessaging.h
index 0cd3381..419e9fb 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioMessaging.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioMessaging.h
@@ -23,6 +23,8 @@
 
 class RadioMessaging : public RadioCompatBase,
                        public aidl::android::hardware::radio::messaging::BnRadioMessaging {
+    std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingResponse> respond();
+
     ::ndk::ScopedAStatus acknowledgeIncomingGsmSmsWithPdu(int32_t serial, bool success,
                                                           const std::string& ackPdu) override;
     ::ndk::ScopedAStatus acknowledgeLastIncomingCdmaSms(
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
index 666ff47..fdca124 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
@@ -23,6 +23,8 @@
 
 class RadioModem : public RadioCompatBase,
                    public aidl::android::hardware::radio::modem::BnRadioModem {
+    std::shared_ptr<::aidl::android::hardware::radio::modem::IRadioModemResponse> respond();
+
     ::ndk::ScopedAStatus enableModem(int32_t serial, bool on) override;
     ::ndk::ScopedAStatus getBasebandVersion(int32_t serial) override;
     ::ndk::ScopedAStatus getDeviceIdentity(int32_t serial) override;
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index c776fd1..1731b78 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -23,6 +23,8 @@
 
 class RadioNetwork : public RadioCompatBase,
                      public aidl::android::hardware::radio::network::BnRadioNetwork {
+    std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
+
     ::ndk::ScopedAStatus getAllowedNetworkTypesBitmap(int32_t serial) override;
     ::ndk::ScopedAStatus getAvailableBandModes(int32_t serial) override;
     ::ndk::ScopedAStatus getAvailableNetworks(int32_t serial) override;
@@ -39,9 +41,8 @@
     ::ndk::ScopedAStatus getVoiceRegistrationState(int32_t serial) override;
     ::ndk::ScopedAStatus isNrDualConnectivityEnabled(int32_t serial) override;
     ::ndk::ScopedAStatus responseAcknowledgement() override;
-    ::ndk::ScopedAStatus setAllowedNetworkTypesBitmap(
-            int32_t serial,
-            ::aidl::android::hardware::radio::RadioAccessFamily networkTypeBitmap) override;
+    ::ndk::ScopedAStatus setAllowedNetworkTypesBitmap(int32_t serial,
+                                                      int32_t networkTypeBitmap) override;
     ::ndk::ScopedAStatus setBandMode(
             int32_t serial, ::aidl::android::hardware::radio::network::RadioBandMode mode) override;
     ::ndk::ScopedAStatus setBarringPassword(int32_t serial, const std::string& facility,
@@ -51,9 +52,7 @@
             int32_t serial,
             ::aidl::android::hardware::radio::network::CdmaRoamingType type) override;
     ::ndk::ScopedAStatus setCellInfoListRate(int32_t serial, int32_t rate) override;
-    ::ndk::ScopedAStatus setIndicationFilter(
-            int32_t serial,
-            ::aidl::android::hardware::radio::network::IndicationFilter indicationFilter) override;
+    ::ndk::ScopedAStatus setIndicationFilter(int32_t serial, int32_t indicationFilter) override;
     ::ndk::ScopedAStatus setLinkCapacityReportingCriteria(
             int32_t serial, int32_t hysteresisMs, int32_t hysteresisDlKbps,
             int32_t hysteresisUlKbps, const std::vector<int32_t>& thresholdsDownlinkKbps,
@@ -88,6 +87,10 @@
     ::ndk::ScopedAStatus stopNetworkScan(int32_t serial) override;
     ::ndk::ScopedAStatus supplyNetworkDepersonalization(int32_t serial,
                                                         const std::string& netPin) override;
+    ::ndk::ScopedAStatus setUsageSetting(
+            int32_t serial,
+            ::aidl::android::hardware::radio::network::UsageSetting usageSetting) override;
+    ::ndk::ScopedAStatus getUsageSetting(int32_t serial) override;
 
   public:
     using RadioCompatBase::RadioCompatBase;
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
index 5db963f..1f82dd1 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
@@ -15,6 +15,9 @@
  */
 #pragma once
 
+#include "DriverContext.h"
+#include "GuaranteedCallback.h"
+
 #include <aidl/android/hardware/radio/data/IRadioDataResponse.h>
 #include <aidl/android/hardware/radio/messaging/IRadioMessagingResponse.h>
 #include <aidl/android/hardware/radio/modem/IRadioModemResponse.h>
@@ -26,13 +29,26 @@
 namespace android::hardware::radio::compat {
 
 class RadioResponse : public V1_6::IRadioResponse {
-    std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataResponse> mDataCb;
-    std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingResponse>
+    std::shared_ptr<DriverContext> mContext;
+
+    GuaranteedCallback<::aidl::android::hardware::radio::data::IRadioDataResponse,
+                       ::aidl::android::hardware::radio::data::IRadioDataResponseDefault>
+            mDataCb;
+    GuaranteedCallback<::aidl::android::hardware::radio::messaging::IRadioMessagingResponse,
+                       ::aidl::android::hardware::radio::messaging::IRadioMessagingResponseDefault>
             mMessagingCb;
-    std::shared_ptr<::aidl::android::hardware::radio::modem::IRadioModemResponse> mModemCb;
-    std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> mNetworkCb;
-    std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> mSimCb;
-    std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> mVoiceCb;
+    GuaranteedCallback<::aidl::android::hardware::radio::modem::IRadioModemResponse,
+                       ::aidl::android::hardware::radio::modem::IRadioModemResponseDefault>
+            mModemCb;
+    GuaranteedCallback<::aidl::android::hardware::radio::network::IRadioNetworkResponse,
+                       ::aidl::android::hardware::radio::network::IRadioNetworkResponseDefault>
+            mNetworkCb;
+    GuaranteedCallback<::aidl::android::hardware::radio::sim::IRadioSimResponse,
+                       ::aidl::android::hardware::radio::sim::IRadioSimResponseDefault>
+            mSimCb;
+    GuaranteedCallback<::aidl::android::hardware::radio::voice::IRadioVoiceResponse,
+                       ::aidl::android::hardware::radio::voice::IRadioVoiceResponseDefault>
+            mVoiceCb;
 
     // IRadioResponse @ 1.0
     Return<void> getIccCardStatusResponse(const V1_0::RadioResponseInfo& info,
@@ -409,6 +425,8 @@
                                                    int32_t updatedRecordIndex) override;
 
   public:
+    RadioResponse(std::shared_ptr<DriverContext> context);
+
     void setResponseFunction(
             std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataResponse> dataCb);
     void setResponseFunction(
@@ -422,6 +440,14 @@
             std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> simCb);
     void setResponseFunction(
             std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> voiceCb);
+
+    std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataResponse> dataCb();
+    std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingResponse>
+    messagingCb();
+    std::shared_ptr<::aidl::android::hardware::radio::modem::IRadioModemResponse> modemCb();
+    std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> networkCb();
+    std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> simCb();
+    std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> voiceCb();
 };
 
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioSim.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioSim.h
index a6b77fd..84bb68b 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioSim.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioSim.h
@@ -22,6 +22,8 @@
 namespace android::hardware::radio::compat {
 
 class RadioSim : public RadioCompatBase, public aidl::android::hardware::radio::sim::BnRadioSim {
+    std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> respond();
+
     ::ndk::ScopedAStatus areUiccApplicationsEnabled(int32_t serial) override;
     ::ndk::ScopedAStatus changeIccPin2ForApp(int32_t serial, const std::string& oldPin2,
                                              const std::string& newPin2,
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioVoice.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioVoice.h
index 5bf93e0..a0e1e82 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioVoice.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioVoice.h
@@ -23,14 +23,15 @@
 
 class RadioVoice : public RadioCompatBase,
                    public aidl::android::hardware::radio::voice::BnRadioVoice {
+    std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> respond();
+
     ::ndk::ScopedAStatus acceptCall(int32_t serial) override;
     ::ndk::ScopedAStatus conference(int32_t serial) override;
     ::ndk::ScopedAStatus dial(
             int32_t serial, const ::aidl::android::hardware::radio::voice::Dial& dialInfo) override;
     ::ndk::ScopedAStatus emergencyDial(
             int32_t serial, const ::aidl::android::hardware::radio::voice::Dial& dialInfo,
-            ::aidl::android::hardware::radio::voice::EmergencyServiceCategory categories,
-            const std::vector<std::string>& urns,
+            int32_t categories, const std::vector<std::string>& urns,
             ::aidl::android::hardware::radio::voice::EmergencyCallRouting routing,
             bool hasKnownUserIntentEmergency, bool isTesting) override;
     ::ndk::ScopedAStatus exitEmergencyCallbackMode(int32_t serial) override;
diff --git a/radio/aidl/compat/libradiocompat/messaging/RadioIndication-messaging.cpp b/radio/aidl/compat/libradiocompat/messaging/RadioIndication-messaging.cpp
index c7342b1..e5c33b3 100644
--- a/radio/aidl/compat/libradiocompat/messaging/RadioIndication-messaging.cpp
+++ b/radio/aidl/compat/libradiocompat/messaging/RadioIndication-messaging.cpp
@@ -27,67 +27,62 @@
 namespace aidl = ::aidl::android::hardware::radio::messaging;
 
 void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioMessagingIndication> rmiCb) {
-    CHECK(rmiCb);
     mMessagingCb = rmiCb;
 }
 
+std::shared_ptr<aidl::IRadioMessagingIndication> RadioIndication::messagingCb() {
+    return mMessagingCb.get();
+}
+
 Return<void> RadioIndication::cdmaNewSms(V1_0::RadioIndicationType type,
                                          const V1_0::CdmaSmsMessage& msg) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->cdmaNewSms(toAidl(type), toAidl(msg));
+    messagingCb()->cdmaNewSms(toAidl(type), toAidl(msg));
     return {};
 }
 
 Return<void> RadioIndication::cdmaRuimSmsStorageFull(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->cdmaRuimSmsStorageFull(toAidl(type));
+    messagingCb()->cdmaRuimSmsStorageFull(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::newBroadcastSms(V1_0::RadioIndicationType type,
                                               const hidl_vec<uint8_t>& data) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->newBroadcastSms(toAidl(type), data);
+    messagingCb()->newBroadcastSms(toAidl(type), data);
     return {};
 }
 
 Return<void> RadioIndication::newSms(V1_0::RadioIndicationType type, const hidl_vec<uint8_t>& pdu) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->newSms(toAidl(type), pdu);
+    messagingCb()->newSms(toAidl(type), pdu);
     return {};
 }
 
 Return<void> RadioIndication::newSmsOnSim(V1_0::RadioIndicationType type, int32_t recordNumber) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->newSmsOnSim(toAidl(type), recordNumber);
+    messagingCb()->newSmsOnSim(toAidl(type), recordNumber);
     return {};
 }
 
 Return<void> RadioIndication::newSmsStatusReport(V1_0::RadioIndicationType type,
                                                  const hidl_vec<uint8_t>& pdu) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->newSmsStatusReport(toAidl(type), pdu);
+    messagingCb()->newSmsStatusReport(toAidl(type), pdu);
     return {};
 }
 
 Return<void> RadioIndication::onUssd(V1_0::RadioIndicationType type, V1_0::UssdModeType modeType,
                                      const hidl_string& msg) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->onUssd(toAidl(type), aidl::UssdModeType(modeType), msg);
+    messagingCb()->onUssd(toAidl(type), aidl::UssdModeType(modeType), msg);
     return {};
 }
 
 Return<void> RadioIndication::simSmsStorageFull(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->simSmsStorageFull(toAidl(type));
+    messagingCb()->simSmsStorageFull(toAidl(type));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/messaging/RadioMessaging.cpp b/radio/aidl/compat/libradiocompat/messaging/RadioMessaging.cpp
index c1a82b5..4d94e17 100644
--- a/radio/aidl/compat/libradiocompat/messaging/RadioMessaging.cpp
+++ b/radio/aidl/compat/libradiocompat/messaging/RadioMessaging.cpp
@@ -29,6 +29,10 @@
 namespace aidl = ::aidl::android::hardware::radio::messaging;
 constexpr auto ok = &ScopedAStatus::ok;
 
+std::shared_ptr<aidl::IRadioMessagingResponse> RadioMessaging::respond() {
+    return mCallbackManager->response().messagingCb();
+}
+
 ScopedAStatus RadioMessaging::acknowledgeIncomingGsmSmsWithPdu(  //
         int32_t serial, bool success, const std::string& ackPdu) {
     LOG_CALL << serial << ' ' << success << ' ' << ackPdu;
@@ -100,13 +104,21 @@
 
 ScopedAStatus RadioMessaging::sendCdmaSms(int32_t serial, const aidl::CdmaSmsMessage& sms) {
     LOG_CALL << serial;
-    mHal1_5->sendCdmaSms(serial, toHidl(sms));
+    if (mHal1_6) {
+        mHal1_6->sendCdmaSms_1_6(serial, toHidl(sms));
+    } else {
+        mHal1_5->sendCdmaSms(serial, toHidl(sms));
+    }
     return ok();
 }
 
 ScopedAStatus RadioMessaging::sendCdmaSmsExpectMore(int32_t serial, const aidl::CdmaSmsMessage& m) {
     LOG_CALL << serial;
-    mHal1_5->sendCdmaSmsExpectMore(serial, toHidl(m));
+    if (mHal1_6) {
+        mHal1_6->sendCdmaSmsExpectMore_1_6(serial, toHidl(m));
+    } else {
+        mHal1_5->sendCdmaSmsExpectMore(serial, toHidl(m));
+    }
     return ok();
 }
 
@@ -118,13 +130,21 @@
 
 ScopedAStatus RadioMessaging::sendSms(int32_t serial, const aidl::GsmSmsMessage& message) {
     LOG_CALL << serial;
-    mHal1_5->sendSms(serial, toHidl(message));
+    if (mHal1_6) {
+        mHal1_6->sendSms_1_6(serial, toHidl(message));
+    } else {
+        mHal1_5->sendSms(serial, toHidl(message));
+    }
     return ok();
 }
 
 ScopedAStatus RadioMessaging::sendSmsExpectMore(int32_t serial, const aidl::GsmSmsMessage& msg) {
     LOG_CALL << serial;
-    mHal1_5->sendSMSExpectMore(serial, toHidl(msg));
+    if (mHal1_6) {
+        mHal1_6->sendSmsExpectMore_1_6(serial, toHidl(msg));
+    } else {
+        mHal1_5->sendSMSExpectMore(serial, toHidl(msg));
+    }
     return ok();
 }
 
@@ -161,16 +181,10 @@
 }
 
 ScopedAStatus RadioMessaging::setResponseFunctions(
-        const std::shared_ptr<aidl::IRadioMessagingResponse>& messagingResponse,
-        const std::shared_ptr<aidl::IRadioMessagingIndication>& messagingIndication) {
-    LOG_CALL << messagingResponse << ' ' << messagingIndication;
-
-    CHECK(messagingResponse);
-    CHECK(messagingIndication);
-
-    mRadioResponse->setResponseFunction(messagingResponse);
-    mRadioIndication->setResponseFunction(messagingIndication);
-
+        const std::shared_ptr<aidl::IRadioMessagingResponse>& response,
+        const std::shared_ptr<aidl::IRadioMessagingIndication>& indication) {
+    LOG_CALL << response << ' ' << indication;
+    mCallbackManager->setResponseFunctions(response, indication);
     return ok();
 }
 
diff --git a/radio/aidl/compat/libradiocompat/messaging/RadioResponse-messaging.cpp b/radio/aidl/compat/libradiocompat/messaging/RadioResponse-messaging.cpp
index 379e463..24ad3d7 100644
--- a/radio/aidl/compat/libradiocompat/messaging/RadioResponse-messaging.cpp
+++ b/radio/aidl/compat/libradiocompat/messaging/RadioResponse-messaging.cpp
@@ -29,52 +29,49 @@
 namespace aidl = ::aidl::android::hardware::radio::messaging;
 
 void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioMessagingResponse> rmrCb) {
-    CHECK(rmrCb);
     mMessagingCb = rmrCb;
 }
 
+std::shared_ptr<aidl::IRadioMessagingResponse> RadioResponse::messagingCb() {
+    return mMessagingCb.get();
+}
+
 Return<void> RadioResponse::acknowledgeIncomingGsmSmsWithPduResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->acknowledgeIncomingGsmSmsWithPduResponse(toAidl(info));
+    messagingCb()->acknowledgeIncomingGsmSmsWithPduResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::acknowledgeLastIncomingCdmaSmsResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->acknowledgeLastIncomingCdmaSmsResponse(toAidl(info));
+    messagingCb()->acknowledgeLastIncomingCdmaSmsResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::acknowledgeLastIncomingGsmSmsResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->acknowledgeLastIncomingGsmSmsResponse(toAidl(info));
+    messagingCb()->acknowledgeLastIncomingGsmSmsResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::cancelPendingUssdResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->cancelPendingUssdResponse(toAidl(info));
+    messagingCb()->cancelPendingUssdResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::deleteSmsOnRuimResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->deleteSmsOnRuimResponse(toAidl(info));
+    messagingCb()->deleteSmsOnRuimResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::deleteSmsOnSimResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->deleteSmsOnSimResponse(toAidl(info));
+    messagingCb()->deleteSmsOnSimResponse(toAidl(info));
     return {};
 }
 
@@ -82,162 +79,141 @@
         const V1_0::RadioResponseInfo& info,
         const hidl_vec<V1_0::CdmaBroadcastSmsConfigInfo>& configs) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->getCdmaBroadcastConfigResponse(toAidl(info), toAidl(configs));
+    messagingCb()->getCdmaBroadcastConfigResponse(toAidl(info), toAidl(configs));
     return {};
 }
 
 Return<void> RadioResponse::getGsmBroadcastConfigResponse(
         const V1_0::RadioResponseInfo& info, const hidl_vec<V1_0::GsmBroadcastSmsConfigInfo>& cfg) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->getGsmBroadcastConfigResponse(toAidl(info), toAidl(cfg));
+    messagingCb()->getGsmBroadcastConfigResponse(toAidl(info), toAidl(cfg));
     return {};
 }
 
 Return<void> RadioResponse::getSmscAddressResponse(const V1_0::RadioResponseInfo& info,
                                                    const hidl_string& smsc) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->getSmscAddressResponse(toAidl(info), smsc);
+    messagingCb()->getSmscAddressResponse(toAidl(info), smsc);
     return {};
 }
 
 Return<void> RadioResponse::reportSmsMemoryStatusResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->reportSmsMemoryStatusResponse(toAidl(info));
+    messagingCb()->reportSmsMemoryStatusResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::sendCdmaSmsExpectMoreResponse(const V1_0::RadioResponseInfo& info,
                                                           const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendCdmaSmsExpectMoreResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendCdmaSmsExpectMoreResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendCdmaSmsExpectMoreResponse_1_6(const V1_6::RadioResponseInfo& info,
                                                               const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendCdmaSmsExpectMoreResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendCdmaSmsExpectMoreResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendCdmaSmsResponse(const V1_0::RadioResponseInfo& info,
                                                 const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendCdmaSmsResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendCdmaSmsResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendCdmaSmsResponse_1_6(const V1_6::RadioResponseInfo& info,
                                                     const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendCdmaSmsResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendCdmaSmsResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendImsSmsResponse(const V1_0::RadioResponseInfo& info,
                                                const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendImsSmsResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendImsSmsResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendSMSExpectMoreResponse(const V1_0::RadioResponseInfo& info,
                                                       const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendSmsExpectMoreResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendSmsExpectMoreResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendSmsExpectMoreResponse_1_6(const V1_6::RadioResponseInfo& info,
                                                           const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendSmsExpectMoreResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendSmsExpectMoreResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendSmsResponse(const V1_0::RadioResponseInfo& info,
                                             const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendSmsResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendSmsResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendSmsResponse_1_6(const V1_6::RadioResponseInfo& info,
                                                 const V1_0::SendSmsResult& sms) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendSmsResponse(toAidl(info), toAidl(sms));
+    messagingCb()->sendSmsResponse(toAidl(info), toAidl(sms));
     return {};
 }
 
 Return<void> RadioResponse::sendUssdResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->sendUssdResponse(toAidl(info));
+    messagingCb()->sendUssdResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCdmaBroadcastActivationResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->setCdmaBroadcastActivationResponse(toAidl(info));
+    messagingCb()->setCdmaBroadcastActivationResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCdmaBroadcastConfigResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->setCdmaBroadcastConfigResponse(toAidl(info));
+    messagingCb()->setCdmaBroadcastConfigResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setGsmBroadcastActivationResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->setGsmBroadcastActivationResponse(toAidl(info));
+    messagingCb()->setGsmBroadcastActivationResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setGsmBroadcastConfigResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->setGsmBroadcastConfigResponse(toAidl(info));
+    messagingCb()->setGsmBroadcastConfigResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSmscAddressResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->setSmscAddressResponse(toAidl(info));
+    messagingCb()->setSmscAddressResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::writeSmsToRuimResponse(const V1_0::RadioResponseInfo& info,
                                                    uint32_t index) {
     LOG_CALL << info.serial << ' ' << index;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->writeSmsToRuimResponse(toAidl(info), index);
+    messagingCb()->writeSmsToRuimResponse(toAidl(info), index);
     return {};
 }
 
 Return<void> RadioResponse::writeSmsToSimResponse(const V1_0::RadioResponseInfo& info,
                                                   int32_t index) {
     LOG_CALL << info.serial << ' ' << index;
-    CHECK_CB(mMessagingCb);
-    mMessagingCb->writeSmsToSimResponse(toAidl(info), index);
+    messagingCb()->writeSmsToSimResponse(toAidl(info), index);
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp b/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp
index 8fc4da6..851c93b 100644
--- a/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp
@@ -29,44 +29,42 @@
 namespace aidl = ::aidl::android::hardware::radio::modem;
 
 void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioModemIndication> modemCb) {
-    CHECK(modemCb);
     mModemCb = modemCb;
 }
 
+std::shared_ptr<aidl::IRadioModemIndication> RadioIndication::modemCb() {
+    return mModemCb.get();
+}
+
 Return<void> RadioIndication::hardwareConfigChanged(V1_0::RadioIndicationType type,
                                                     const hidl_vec<V1_0::HardwareConfig>& configs) {
     LOG_CALL << type;
-    CHECK_CB(mModemCb);
-    mModemCb->hardwareConfigChanged(toAidl(type), toAidl(configs));
+    modemCb()->hardwareConfigChanged(toAidl(type), toAidl(configs));
     return {};
 }
 
 Return<void> RadioIndication::modemReset(V1_0::RadioIndicationType type, const hidl_string& reasn) {
     LOG_CALL << type;
-    CHECK_CB(mModemCb);
-    mModemCb->modemReset(toAidl(type), reasn);
+    modemCb()->modemReset(toAidl(type), reasn);
     return {};
 }
 
 Return<void> RadioIndication::radioCapabilityIndication(V1_0::RadioIndicationType type,
                                                         const V1_0::RadioCapability& rc) {
     LOG_CALL << type;
-    CHECK_CB(mModemCb);
-    mModemCb->radioCapabilityIndication(toAidl(type), toAidl(rc));
+    modemCb()->radioCapabilityIndication(toAidl(type), toAidl(rc));
     return {};
 }
 
 Return<void> RadioIndication::radioStateChanged(V1_0::RadioIndicationType t, V1_0::RadioState st) {
     LOG_CALL << t;
-    CHECK_CB(mModemCb);
-    mModemCb->radioStateChanged(toAidl(t), aidl::RadioState(st));
+    modemCb()->radioStateChanged(toAidl(t), aidl::RadioState(st));
     return {};
 }
 
 Return<void> RadioIndication::rilConnected(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mModemCb);
-    mModemCb->rilConnected(toAidl(type));
+    modemCb()->rilConnected(toAidl(type));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp b/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
index 660ae9f..d28b940 100644
--- a/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
@@ -27,6 +27,10 @@
 namespace aidl = ::aidl::android::hardware::radio::modem;
 constexpr auto ok = &ScopedAStatus::ok;
 
+std::shared_ptr<aidl::IRadioModemResponse> RadioModem::respond() {
+    return mCallbackManager->response().modemCb();
+}
+
 ScopedAStatus RadioModem::enableModem(int32_t serial, bool on) {
     LOG_CALL << serial;
     mHal1_5->enableModem(serial, on);
@@ -129,16 +133,10 @@
 }
 
 ScopedAStatus RadioModem::setResponseFunctions(
-        const std::shared_ptr<aidl::IRadioModemResponse>& modemResponse,
-        const std::shared_ptr<aidl::IRadioModemIndication>& modemIndication) {
-    LOG_CALL << modemResponse << ' ' << modemIndication;
-
-    CHECK(modemResponse);
-    CHECK(modemIndication);
-
-    mRadioResponse->setResponseFunction(modemResponse);
-    mRadioIndication->setResponseFunction(modemIndication);
-
+        const std::shared_ptr<aidl::IRadioModemResponse>& response,
+        const std::shared_ptr<aidl::IRadioModemIndication>& indication) {
+    LOG_CALL << response << ' ' << indication;
+    mCallbackManager->setResponseFunctions(response, indication);
     return ok();
 }
 
diff --git a/radio/aidl/compat/libradiocompat/modem/RadioResponse-modem.cpp b/radio/aidl/compat/libradiocompat/modem/RadioResponse-modem.cpp
index 300627c..6e1a962 100644
--- a/radio/aidl/compat/libradiocompat/modem/RadioResponse-modem.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/RadioResponse-modem.cpp
@@ -29,22 +29,23 @@
 namespace aidl = ::aidl::android::hardware::radio::modem;
 
 void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioModemResponse> modemCb) {
-    CHECK(modemCb);
     mModemCb = modemCb;
 }
 
+std::shared_ptr<aidl::IRadioModemResponse> RadioResponse::modemCb() {
+    return mModemCb.get();
+}
+
 Return<void> RadioResponse::enableModemResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->enableModemResponse(toAidl(info));
+    modemCb()->enableModemResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::getBasebandVersionResponse(const V1_0::RadioResponseInfo& info,
                                                        const hidl_string& version) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->getBasebandVersionResponse(toAidl(info), version);
+    modemCb()->getBasebandVersionResponse(toAidl(info), version);
     return {};
 }
 
@@ -52,112 +53,97 @@
         const V1_0::RadioResponseInfo& info, const hidl_string& imei, const hidl_string& imeisv,
         const hidl_string& esn, const hidl_string& meid) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->getDeviceIdentityResponse(toAidl(info), imei, imeisv, esn, meid);
+    modemCb()->getDeviceIdentityResponse(toAidl(info), imei, imeisv, esn, meid);
     return {};
 }
 
 Return<void> RadioResponse::getHardwareConfigResponse(
         const V1_0::RadioResponseInfo& info, const hidl_vec<V1_0::HardwareConfig>& config) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->getHardwareConfigResponse(toAidl(info), toAidl(config));
+    modemCb()->getHardwareConfigResponse(toAidl(info), toAidl(config));
     return {};
 }
 
 Return<void> RadioResponse::getModemActivityInfoResponse(
         const V1_0::RadioResponseInfo& info, const V1_0::ActivityStatsInfo& activityInfo) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->getModemActivityInfoResponse(toAidl(info), toAidl(activityInfo));
+    modemCb()->getModemActivityInfoResponse(toAidl(info), toAidl(activityInfo));
     return {};
 }
 
 Return<void> RadioResponse::getModemStackStatusResponse(const V1_0::RadioResponseInfo& info,
                                                         bool isEnabled) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->getModemStackStatusResponse(toAidl(info), isEnabled);
+    modemCb()->getModemStackStatusResponse(toAidl(info), isEnabled);
     return {};
 }
 
 Return<void> RadioResponse::getRadioCapabilityResponse(const V1_0::RadioResponseInfo& info,
                                                        const V1_0::RadioCapability& rc) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->getRadioCapabilityResponse(toAidl(info), toAidl(rc));
+    modemCb()->getRadioCapabilityResponse(toAidl(info), toAidl(rc));
     return {};
 }
 
 Return<void> RadioResponse::nvReadItemResponse(const V1_0::RadioResponseInfo& info,
                                                const hidl_string& result) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->nvReadItemResponse(toAidl(info), result);
+    modemCb()->nvReadItemResponse(toAidl(info), result);
     return {};
 }
 
 Return<void> RadioResponse::nvResetConfigResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->nvResetConfigResponse(toAidl(info));
+    modemCb()->nvResetConfigResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::nvWriteCdmaPrlResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->nvWriteCdmaPrlResponse(toAidl(info));
+    modemCb()->nvWriteCdmaPrlResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::nvWriteItemResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->nvWriteItemResponse(toAidl(info));
+    modemCb()->nvWriteItemResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::requestShutdownResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->requestShutdownResponse(toAidl(info));
+    modemCb()->requestShutdownResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::sendDeviceStateResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->sendDeviceStateResponse(toAidl(info));
+    modemCb()->sendDeviceStateResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setRadioCapabilityResponse(const V1_0::RadioResponseInfo& info,
                                                        const V1_0::RadioCapability& rc) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->setRadioCapabilityResponse(toAidl(info), toAidl(rc));
+    modemCb()->setRadioCapabilityResponse(toAidl(info), toAidl(rc));
     return {};
 }
 
 Return<void> RadioResponse::setRadioPowerResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->setRadioPowerResponse(toAidl(info));
+    modemCb()->setRadioPowerResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setRadioPowerResponse_1_5(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->setRadioPowerResponse(toAidl(info));
+    modemCb()->setRadioPowerResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setRadioPowerResponse_1_6(const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mModemCb);
-    mModemCb->setRadioPowerResponse(toAidl(info));
+    modemCb()->setRadioPowerResponse(toAidl(info));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/modem/structs.cpp b/radio/aidl/compat/libradiocompat/modem/structs.cpp
index c1cd64c..69e651b 100644
--- a/radio/aidl/compat/libradiocompat/modem/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/structs.cpp
@@ -24,7 +24,7 @@
 
 namespace android::hardware::radio::compat {
 
-using ::aidl::android::hardware::radio::RadioAccessFamily;
+using ::aidl::android::hardware::radio::AccessNetwork;
 using ::aidl::android::hardware::radio::RadioTechnology;
 namespace aidl = ::aidl::android::hardware::radio::modem;
 
@@ -39,7 +39,7 @@
     return {
             .session = capa.session,
             .phase = static_cast<int32_t>(capa.phase),
-            .raf = RadioAccessFamily(capa.raf),
+            .raf = static_cast<int32_t>(capa.raf),
             .logicalModemUuid = capa.logicalModemUuid,
             .status = static_cast<int32_t>(capa.status),
     };
@@ -82,11 +82,18 @@
 }
 
 aidl::ActivityStatsInfo toAidl(const V1_0::ActivityStatsInfo& info) {
+    const aidl::ActivityStatsTechSpecificInfo techSpecificInfo = {
+            .rat = AccessNetwork(AccessNetwork::UNKNOWN),
+            .frequencyRange = static_cast<int32_t>(
+                    aidl::ActivityStatsTechSpecificInfo::FREQUENCY_RANGE_UNKNOWN),
+            .txmModetimeMs = toAidl(info.txmModetimeMs),
+            .rxModeTimeMs = static_cast<int32_t>(info.rxModeTimeMs),
+    };
+
     return {
             .sleepModeTimeMs = static_cast<int32_t>(info.sleepModeTimeMs),
             .idleModeTimeMs = static_cast<int32_t>(info.idleModeTimeMs),
-            .txmModetimeMs = toAidl(info.txmModetimeMs),
-            .rxModeTimeMs = static_cast<int32_t>(info.rxModeTimeMs),
+            .techSpecificInfo = {techSpecificInfo},
     };
 }
 
diff --git a/radio/aidl/compat/libradiocompat/modem/structs.h b/radio/aidl/compat/libradiocompat/modem/structs.h
index 3ac1edb..af714c7 100644
--- a/radio/aidl/compat/libradiocompat/modem/structs.h
+++ b/radio/aidl/compat/libradiocompat/modem/structs.h
@@ -16,6 +16,7 @@
 #pragma once
 
 #include <aidl/android/hardware/radio/modem/ActivityStatsInfo.h>
+#include <aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.h>
 #include <aidl/android/hardware/radio/modem/HardwareConfig.h>
 #include <aidl/android/hardware/radio/modem/HardwareConfigModem.h>
 #include <aidl/android/hardware/radio/modem/HardwareConfigSim.h>
diff --git a/radio/aidl/compat/libradiocompat/network/RadioIndication-network.cpp b/radio/aidl/compat/libradiocompat/network/RadioIndication-network.cpp
index 899b133..4eb99f7 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioIndication-network.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioIndication-network.cpp
@@ -30,23 +30,24 @@
 namespace aidl = ::aidl::android::hardware::radio::network;
 
 void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioNetworkIndication> netCb) {
-    CHECK(netCb);
     mNetworkCb = netCb;
 }
 
+std::shared_ptr<aidl::IRadioNetworkIndication> RadioIndication::networkCb() {
+    return mNetworkCb.get();
+}
+
 Return<void> RadioIndication::barringInfoChanged(V1_0::RadioIndicationType type,
                                                  const V1_5::CellIdentity& cellIdentity,
                                                  const hidl_vec<V1_5::BarringInfo>& barringInfos) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->barringInfoChanged(toAidl(type), toAidl(cellIdentity), toAidl(barringInfos));
+    networkCb()->barringInfoChanged(toAidl(type), toAidl(cellIdentity), toAidl(barringInfos));
     return {};
 }
 
 Return<void> RadioIndication::cdmaPrlChanged(V1_0::RadioIndicationType type, int32_t version) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->cdmaPrlChanged(toAidl(type), version);
+    networkCb()->cdmaPrlChanged(toAidl(type), version);
     return {};
 }
 
@@ -74,32 +75,28 @@
 Return<void> RadioIndication::cellInfoList_1_5(V1_0::RadioIndicationType type,
                                                const hidl_vec<V1_5::CellInfo>& records) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->cellInfoList(toAidl(type), toAidl(records));
+    networkCb()->cellInfoList(toAidl(type), toAidl(records));
     return {};
 }
 
 Return<void> RadioIndication::cellInfoList_1_6(V1_0::RadioIndicationType type,
                                                const hidl_vec<V1_6::CellInfo>& records) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->cellInfoList(toAidl(type), toAidl(records));
+    networkCb()->cellInfoList(toAidl(type), toAidl(records));
     return {};
 }
 
 Return<void> RadioIndication::currentLinkCapacityEstimate(V1_0::RadioIndicationType type,
                                                           const V1_2::LinkCapacityEstimate& lce) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->currentLinkCapacityEstimate(toAidl(type), toAidl(lce));
+    networkCb()->currentLinkCapacityEstimate(toAidl(type), toAidl(lce));
     return {};
 }
 
 Return<void> RadioIndication::currentLinkCapacityEstimate_1_6(
         V1_0::RadioIndicationType type, const V1_6::LinkCapacityEstimate& lce) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->currentLinkCapacityEstimate(toAidl(type), toAidl(lce));
+    networkCb()->currentLinkCapacityEstimate(toAidl(type), toAidl(lce));
     return {};
 }
 
@@ -113,16 +110,14 @@
 Return<void> RadioIndication::currentPhysicalChannelConfigs_1_4(
         V1_0::RadioIndicationType type, const hidl_vec<V1_4::PhysicalChannelConfig>& configs) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->currentPhysicalChannelConfigs(toAidl(type), toAidl(configs));
+    networkCb()->currentPhysicalChannelConfigs(toAidl(type), toAidl(configs));
     return {};
 }
 
 Return<void> RadioIndication::currentPhysicalChannelConfigs_1_6(
         V1_0::RadioIndicationType type, const hidl_vec<V1_6::PhysicalChannelConfig>& configs) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->currentPhysicalChannelConfigs(toAidl(type), toAidl(configs));
+    networkCb()->currentPhysicalChannelConfigs(toAidl(type), toAidl(configs));
     return {};
 }
 
@@ -143,23 +138,20 @@
 Return<void> RadioIndication::currentSignalStrength_1_4(
         V1_0::RadioIndicationType type, const V1_4::SignalStrength& signalStrength) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->currentSignalStrength(toAidl(type), toAidl(signalStrength));
+    networkCb()->currentSignalStrength(toAidl(type), toAidl(signalStrength));
     return {};
 }
 
 Return<void> RadioIndication::currentSignalStrength_1_6(
         V1_0::RadioIndicationType type, const V1_6::SignalStrength& signalStrength) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->currentSignalStrength(toAidl(type), toAidl(signalStrength));
+    networkCb()->currentSignalStrength(toAidl(type), toAidl(signalStrength));
     return {};
 }
 
 Return<void> RadioIndication::imsNetworkStateChanged(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->imsNetworkStateChanged(toAidl(type));
+    networkCb()->imsNetworkStateChanged(toAidl(type));
     return {};
 }
 
@@ -187,31 +179,27 @@
 Return<void> RadioIndication::networkScanResult_1_5(V1_0::RadioIndicationType type,
                                                     const V1_5::NetworkScanResult& result) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->networkScanResult(toAidl(type), toAidl(result));
+    networkCb()->networkScanResult(toAidl(type), toAidl(result));
     return {};
 }
 
 Return<void> RadioIndication::networkScanResult_1_6(V1_0::RadioIndicationType type,
                                                     const V1_6::NetworkScanResult& result) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->networkScanResult(toAidl(type), toAidl(result));
+    networkCb()->networkScanResult(toAidl(type), toAidl(result));
     return {};
 }
 
 Return<void> RadioIndication::networkStateChanged(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->networkStateChanged(toAidl(type));
+    networkCb()->networkStateChanged(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::nitzTimeReceived(V1_0::RadioIndicationType type,
                                                const hidl_string& nitzTime, uint64_t receivedTime) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->nitzTimeReceived(toAidl(type), nitzTime, receivedTime, 0);
+    networkCb()->nitzTimeReceived(toAidl(type), nitzTime, receivedTime, 0);
     return {};
 }
 
@@ -220,33 +208,29 @@
         const hidl_string& chosenPlmn, hidl_bitfield<V1_5::Domain> domain, int32_t causeCode,
         int32_t additionalCauseCode) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->registrationFailed(toAidl(type), toAidl(cellIdentity), chosenPlmn,
-                                   aidl::Domain(domain), causeCode, additionalCauseCode);
+    networkCb()->registrationFailed(toAidl(type), toAidl(cellIdentity), chosenPlmn, domain,
+                                    causeCode, additionalCauseCode);
     return {};
 }
 
 Return<void> RadioIndication::restrictedStateChanged(V1_0::RadioIndicationType type,
                                                      V1_0::PhoneRestrictedState state) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->restrictedStateChanged(toAidl(type), aidl::PhoneRestrictedState(state));
+    networkCb()->restrictedStateChanged(toAidl(type), aidl::PhoneRestrictedState(state));
     return {};
 }
 
 Return<void> RadioIndication::suppSvcNotify(V1_0::RadioIndicationType type,
                                             const V1_0::SuppSvcNotification& suppSvc) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->suppSvcNotify(toAidl(type), toAidl(suppSvc));
+    networkCb()->suppSvcNotify(toAidl(type), toAidl(suppSvc));
     return {};
 }
 
 Return<void> RadioIndication::voiceRadioTechChanged(V1_0::RadioIndicationType type,
                                                     V1_0::RadioTechnology rat) {
     LOG_CALL << type;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->voiceRadioTechChanged(toAidl(type), RadioTechnology(rat));
+    networkCb()->voiceRadioTechChanged(toAidl(type), RadioTechnology(rat));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index af0bc46..22b9ede 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -28,11 +28,14 @@
 namespace android::hardware::radio::compat {
 
 using ::aidl::android::hardware::radio::AccessNetwork;
-using ::aidl::android::hardware::radio::RadioAccessFamily;
 using ::ndk::ScopedAStatus;
 namespace aidl = ::aidl::android::hardware::radio::network;
 constexpr auto ok = &ScopedAStatus::ok;
 
+std::shared_ptr<aidl::IRadioNetworkResponse> RadioNetwork::respond() {
+    return mCallbackManager->response().networkCb();
+}
+
 ScopedAStatus RadioNetwork::getAllowedNetworkTypesBitmap(int32_t serial) {
     LOG_CALL << serial;
     if (mHal1_6) {
@@ -69,13 +72,21 @@
 
 ScopedAStatus RadioNetwork::getCellInfoList(int32_t serial) {
     LOG_CALL << serial;
-    mHal1_5->getCellInfoList(serial);
+    if (mHal1_6) {
+        mHal1_6->getCellInfoList_1_6(serial);
+    } else {
+        mHal1_5->getCellInfoList(serial);
+    }
     return ok();
 }
 
 ScopedAStatus RadioNetwork::getDataRegistrationState(int32_t serial) {
     LOG_CALL << serial;
-    mHal1_5->getDataRegistrationState(serial);
+    if (mHal1_6) {
+        mHal1_6->getDataRegistrationState_1_6(serial);
+    } else {
+        mHal1_5->getDataRegistrationState_1_5(serial);
+    }
     return ok();
 }
 
@@ -99,7 +110,11 @@
 
 ScopedAStatus RadioNetwork::getSignalStrength(int32_t serial) {
     LOG_CALL << serial;
-    mHal1_5->getSignalStrength(serial);
+    if (mHal1_6) {
+        mHal1_6->getSignalStrength_1_6(serial);
+    } else {
+        mHal1_5->getSignalStrength_1_4(serial);
+    }
     return ok();
 }
 
@@ -108,7 +123,7 @@
     if (mHal1_6) {
         mHal1_6->getSystemSelectionChannels(serial);
     } else {
-        respond().getSystemSelectionChannelsResponse(notSupported(serial), {});
+        respond()->getSystemSelectionChannelsResponse(notSupported(serial), {});
     }
     return ok();
 }
@@ -121,7 +136,11 @@
 
 ScopedAStatus RadioNetwork::getVoiceRegistrationState(int32_t serial) {
     LOG_CALL << serial;
-    mHal1_5->getVoiceRegistrationState(serial);
+    if (mHal1_6) {
+        mHal1_6->getVoiceRegistrationState_1_6(serial);
+    } else {
+        mHal1_5->getVoiceRegistrationState_1_5(serial);
+    }
     return ok();
 }
 
@@ -130,7 +149,7 @@
     if (mHal1_6) {
         mHal1_6->isNrDualConnectivityEnabled(serial);
     } else {
-        respond().isNrDualConnectivityEnabledResponse(notSupported(serial), false);
+        respond()->isNrDualConnectivityEnabledResponse(notSupported(serial), false);
     }
     return ok();
 }
@@ -141,7 +160,7 @@
     return ok();
 }
 
-ScopedAStatus RadioNetwork::setAllowedNetworkTypesBitmap(int32_t serial, RadioAccessFamily ntype) {
+ScopedAStatus RadioNetwork::setAllowedNetworkTypesBitmap(int32_t serial, int32_t ntype) {
     LOG_CALL << serial;
     const auto raf = toHidlBitfield<V1_4::RadioAccessFamily>(ntype);
     if (mHal1_6) {
@@ -177,9 +196,9 @@
     return ok();
 }
 
-ScopedAStatus RadioNetwork::setIndicationFilter(int32_t serial, aidl::IndicationFilter indFilter) {
+ScopedAStatus RadioNetwork::setIndicationFilter(int32_t serial, int32_t indFilter) {
     LOG_CALL << serial;
-    mHal1_5->setIndicationFilter(serial, toHidlBitfield<V1_0::IndicationFilter>(indFilter));
+    mHal1_5->setIndicationFilter_1_5(serial, toHidlBitfield<V1_5::IndicationFilter>(indFilter));
     return ok();
 }
 
@@ -188,9 +207,9 @@
         const std::vector<int32_t>& thrDownlinkKbps, const std::vector<int32_t>& thrUplinkKbps,
         AccessNetwork accessNetwork) {
     LOG_CALL << serial;
-    mHal1_5->setLinkCapacityReportingCriteria(  //
+    mHal1_5->setLinkCapacityReportingCriteria_1_5(  //
             serial, hysteresisMs, hysteresisDlKbps, hysteresisUlKbps, thrDownlinkKbps,
-            thrUplinkKbps, V1_2::AccessNetwork(accessNetwork));
+            thrUplinkKbps, V1_5::AccessNetwork(accessNetwork));
     return ok();
 }
 
@@ -219,29 +238,29 @@
     if (mHal1_6) {
         mHal1_6->setNrDualConnectivityState(serial, V1_6::NrDualConnectivityState(st));
     } else {
-        respond().setNrDualConnectivityStateResponse(notSupported(serial));
+        respond()->setNrDualConnectivityStateResponse(notSupported(serial));
     }
     return ok();
 }
 
 ScopedAStatus RadioNetwork::setResponseFunctions(
-        const std::shared_ptr<aidl::IRadioNetworkResponse>& networkResponse,
-        const std::shared_ptr<aidl::IRadioNetworkIndication>& networkIndication) {
-    LOG_CALL << networkResponse << ' ' << networkIndication;
-
-    CHECK(networkResponse);
-    CHECK(networkIndication);
-
-    mRadioResponse->setResponseFunction(networkResponse);
-    mRadioIndication->setResponseFunction(networkIndication);
-
+        const std::shared_ptr<aidl::IRadioNetworkResponse>& response,
+        const std::shared_ptr<aidl::IRadioNetworkIndication>& indication) {
+    LOG_CALL << response << ' ' << indication;
+    mCallbackManager->setResponseFunctions(response, indication);
     return ok();
 }
 
 ScopedAStatus RadioNetwork::setSignalStrengthReportingCriteria(
         int32_t serial, const std::vector<aidl::SignalThresholdInfo>& infos) {
     LOG_CALL << serial;
-    // TODO(b/203699028): how about other infos?
+    if (infos.size() == 0) {
+        LOG(ERROR) << "Threshold info array is empty - dropping setSignalStrengthReportingCriteria";
+        return ok();
+    }
+    if (infos.size() > 1) {
+        LOG(WARNING) << "Multi-element reporting criteria are not supported with HIDL HAL";
+    }
     mHal1_5->setSignalStrengthReportingCriteria_1_5(serial, toHidl(infos[0]),
                                                     V1_5::AccessNetwork(infos[0].ran));
     return ok();
@@ -278,4 +297,18 @@
     return ok();
 }
 
+ScopedAStatus RadioNetwork::setUsageSetting(int32_t serial, aidl::UsageSetting) {
+    LOG_CALL << serial;
+    LOG(ERROR) << "setUsageSetting is unsupported by HIDL HALs";
+    respond()->setUsageSettingResponse(notSupported(serial));
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::getUsageSetting(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << "getUsageSetting is unsupported by HIDL HALs";
+    respond()->getUsageSettingResponse(notSupported(serial), {});  // {} = neither voice nor data
+    return ok();
+}
+
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/network/RadioResponse-network.cpp b/radio/aidl/compat/libradiocompat/network/RadioResponse-network.cpp
index 81f7775..5a98eb2 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioResponse-network.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioResponse-network.cpp
@@ -27,32 +27,30 @@
 
 namespace android::hardware::radio::compat {
 
-using ::aidl::android::hardware::radio::RadioAccessFamily;
 using ::aidl::android::hardware::radio::RadioTechnology;
 using ::aidl::android::hardware::radio::RadioTechnologyFamily;
 namespace aidl = ::aidl::android::hardware::radio::network;
 
 void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioNetworkResponse> netCb) {
-    CHECK(netCb);
     mNetworkCb = netCb;
 }
 
+std::shared_ptr<aidl::IRadioNetworkResponse> RadioResponse::networkCb() {
+    return mNetworkCb.get();
+}
+
 Return<void> RadioResponse::getAllowedNetworkTypesBitmapResponse(
         const V1_6::RadioResponseInfo& info,
         hidl_bitfield<V1_4::RadioAccessFamily> networkTypeBitmap) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getAllowedNetworkTypesBitmapResponse(toAidl(info),
-                                                     RadioAccessFamily(networkTypeBitmap));
+    networkCb()->getAllowedNetworkTypesBitmapResponse(toAidl(info), networkTypeBitmap);
     return {};
 }
 
 Return<void> RadioResponse::getPreferredNetworkTypeResponse(const V1_0::RadioResponseInfo& info,
                                                             V1_0::PreferredNetworkType nwType) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getAllowedNetworkTypesBitmapResponse(  //
-            toAidl(info), RadioAccessFamily(getRafFromNetworkType(nwType)));
+    networkCb()->getAllowedNetworkTypesBitmapResponse(toAidl(info), getRafFromNetworkType(nwType));
     return {};
 }
 
@@ -66,16 +64,14 @@
 Return<void> RadioResponse::getAvailableBandModesResponse(
         const V1_0::RadioResponseInfo& info, const hidl_vec<V1_0::RadioBandMode>& bandModes) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getAvailableBandModesResponse(toAidl(info), toAidl(bandModes));
+    networkCb()->getAvailableBandModesResponse(toAidl(info), toAidl(bandModes));
     return {};
 }
 
 Return<void> RadioResponse::getAvailableNetworksResponse(
         const V1_0::RadioResponseInfo& info, const hidl_vec<V1_0::OperatorInfo>& networkInfos) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getAvailableNetworksResponse(toAidl(info), toAidl(networkInfos));
+    networkCb()->getAvailableNetworksResponse(toAidl(info), toAidl(networkInfos));
     return {};
 }
 
@@ -83,16 +79,14 @@
         const V1_0::RadioResponseInfo& info, const V1_5::CellIdentity& cellIdentity,
         const hidl_vec<V1_5::BarringInfo>& barringInfos) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getBarringInfoResponse(toAidl(info), toAidl(cellIdentity), toAidl(barringInfos));
+    networkCb()->getBarringInfoResponse(toAidl(info), toAidl(cellIdentity), toAidl(barringInfos));
     return {};
 }
 
 Return<void> RadioResponse::getCdmaRoamingPreferenceResponse(const V1_0::RadioResponseInfo& info,
                                                              V1_0::CdmaRoamingType type) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getCdmaRoamingPreferenceResponse(toAidl(info), aidl::CdmaRoamingType(type));
+    networkCb()->getCdmaRoamingPreferenceResponse(toAidl(info), aidl::CdmaRoamingType(type));
     return {};
 }
 
@@ -120,16 +114,14 @@
 Return<void> RadioResponse::getCellInfoListResponse_1_5(const V1_0::RadioResponseInfo& info,
                                                         const hidl_vec<V1_5::CellInfo>& cellInfo) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getCellInfoListResponse(toAidl(info), toAidl(cellInfo));
+    networkCb()->getCellInfoListResponse(toAidl(info), toAidl(cellInfo));
     return {};
 }
 
 Return<void> RadioResponse::getCellInfoListResponse_1_6(const V1_6::RadioResponseInfo& info,
                                                         const hidl_vec<V1_6::CellInfo>& cellInfo) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getCellInfoListResponse(toAidl(info), toAidl(cellInfo));
+    networkCb()->getCellInfoListResponse(toAidl(info), toAidl(cellInfo));
     return {};
 }
 
@@ -157,25 +149,22 @@
 Return<void> RadioResponse::getDataRegistrationStateResponse_1_5(
         const V1_0::RadioResponseInfo& info, const V1_5::RegStateResult& dataRegResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getDataRegistrationStateResponse(toAidl(info), toAidl(dataRegResponse));
+    networkCb()->getDataRegistrationStateResponse(toAidl(info), toAidl(dataRegResponse));
     return {};
 }
 
 Return<void> RadioResponse::getDataRegistrationStateResponse_1_6(
         const V1_6::RadioResponseInfo& info, const V1_6::RegStateResult& dataRegResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getDataRegistrationStateResponse(toAidl(info), toAidl(dataRegResponse));
+    networkCb()->getDataRegistrationStateResponse(toAidl(info), toAidl(dataRegResponse));
     return {};
 }
 
 Return<void> RadioResponse::getImsRegistrationStateResponse(  //
         const V1_0::RadioResponseInfo& info, bool isRegd, V1_0::RadioTechnologyFamily ratFamily) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getImsRegistrationStateResponse(toAidl(info), isRegd,
-                                                RadioTechnologyFamily(ratFamily));
+    networkCb()->getImsRegistrationStateResponse(toAidl(info), isRegd,
+                                                 RadioTechnologyFamily(ratFamily));
     return {};
 }
 
@@ -189,8 +178,7 @@
 Return<void> RadioResponse::getNetworkSelectionModeResponse(const V1_0::RadioResponseInfo& info,
                                                             bool manual) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getNetworkSelectionModeResponse(toAidl(info), manual);
+    networkCb()->getNetworkSelectionModeResponse(toAidl(info), manual);
     return {};
 }
 
@@ -198,8 +186,7 @@
         const V1_0::RadioResponseInfo& info, const hidl_string& longName,
         const hidl_string& shortName, const hidl_string& numeric) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getOperatorResponse(toAidl(info), longName, shortName, numeric);
+    networkCb()->getOperatorResponse(toAidl(info), longName, shortName, numeric);
     return {};
 }
 
@@ -220,16 +207,14 @@
 Return<void> RadioResponse::getSignalStrengthResponse_1_4(
         const V1_0::RadioResponseInfo& info, const V1_4::SignalStrength& signalStrength) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getSignalStrengthResponse(toAidl(info), toAidl(signalStrength));
+    networkCb()->getSignalStrengthResponse(toAidl(info), toAidl(signalStrength));
     return {};
 }
 
 Return<void> RadioResponse::getSignalStrengthResponse_1_6(
         const V1_6::RadioResponseInfo& info, const V1_6::SignalStrength& signalStrength) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getSignalStrengthResponse(toAidl(info), toAidl(signalStrength));
+    networkCb()->getSignalStrengthResponse(toAidl(info), toAidl(signalStrength));
     return {};
 }
 
@@ -237,16 +222,14 @@
         const V1_6::RadioResponseInfo& info,
         const hidl_vec<V1_5::RadioAccessSpecifier>& specifiers) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getSystemSelectionChannelsResponse(toAidl(info), toAidl(specifiers));
+    networkCb()->getSystemSelectionChannelsResponse(toAidl(info), toAidl(specifiers));
     return {};
 }
 
 Return<void> RadioResponse::getVoiceRadioTechnologyResponse(const V1_0::RadioResponseInfo& info,
                                                             V1_0::RadioTechnology rat) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getVoiceRadioTechnologyResponse(toAidl(info), RadioTechnology(rat));
+    networkCb()->getVoiceRadioTechnologyResponse(toAidl(info), RadioTechnology(rat));
     return {};
 }
 
@@ -267,24 +250,21 @@
 Return<void> RadioResponse::getVoiceRegistrationStateResponse_1_5(
         const V1_0::RadioResponseInfo& info, const V1_5::RegStateResult& voiceRegResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getVoiceRegistrationStateResponse(toAidl(info), toAidl(voiceRegResponse));
+    networkCb()->getVoiceRegistrationStateResponse(toAidl(info), toAidl(voiceRegResponse));
     return {};
 }
 
 Return<void> RadioResponse::getVoiceRegistrationStateResponse_1_6(
         const V1_6::RadioResponseInfo& info, const V1_6::RegStateResult& voiceRegResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->getVoiceRegistrationStateResponse(toAidl(info), toAidl(voiceRegResponse));
+    networkCb()->getVoiceRegistrationStateResponse(toAidl(info), toAidl(voiceRegResponse));
     return {};
 }
 
 Return<void> RadioResponse::isNrDualConnectivityEnabledResponse(const V1_6::RadioResponseInfo& info,
                                                                 bool isEnabled) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->isNrDualConnectivityEnabledResponse(toAidl(info), isEnabled);
+    networkCb()->isNrDualConnectivityEnabledResponse(toAidl(info), isEnabled);
     return {};
 }
 
@@ -297,15 +277,13 @@
 
 Return<void> RadioResponse::setAllowedNetworkTypesBitmapResponse(const V1_6::RadioResponseInfo& i) {
     LOG_CALL << i.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setAllowedNetworkTypesBitmapResponse(toAidl(i));
+    networkCb()->setAllowedNetworkTypesBitmapResponse(toAidl(i));
     return {};
 }
 
 Return<void> RadioResponse::setPreferredNetworkTypeResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setAllowedNetworkTypesBitmapResponse(toAidl(info));
+    networkCb()->setAllowedNetworkTypesBitmapResponse(toAidl(info));
     return {};
 }
 
@@ -318,174 +296,151 @@
 
 Return<void> RadioResponse::setBandModeResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setBandModeResponse(toAidl(info));
+    networkCb()->setBandModeResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setBarringPasswordResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setBarringPasswordResponse(toAidl(info));
+    networkCb()->setBarringPasswordResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCdmaRoamingPreferenceResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setCdmaRoamingPreferenceResponse(toAidl(info));
+    networkCb()->setCdmaRoamingPreferenceResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCellInfoListRateResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setCellInfoListRateResponse(toAidl(info));
+    networkCb()->setCellInfoListRateResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setIndicationFilterResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setIndicationFilterResponse(toAidl(info));
+    networkCb()->setIndicationFilterResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setIndicationFilterResponse_1_5(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setIndicationFilterResponse(toAidl(info));
+    networkCb()->setIndicationFilterResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setLinkCapacityReportingCriteriaResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setLinkCapacityReportingCriteriaResponse(toAidl(info));
+    networkCb()->setLinkCapacityReportingCriteriaResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setLinkCapacityReportingCriteriaResponse_1_5(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setLinkCapacityReportingCriteriaResponse(toAidl(info));
+    networkCb()->setLinkCapacityReportingCriteriaResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setLocationUpdatesResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setLocationUpdatesResponse(toAidl(info));
+    networkCb()->setLocationUpdatesResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setNetworkSelectionModeAutomaticResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setNetworkSelectionModeAutomaticResponse(toAidl(info));
+    networkCb()->setNetworkSelectionModeAutomaticResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setNetworkSelectionModeManualResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setNetworkSelectionModeManualResponse(toAidl(info));
+    networkCb()->setNetworkSelectionModeManualResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setNetworkSelectionModeManualResponse_1_5(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setNetworkSelectionModeManualResponse(toAidl(info));
+    networkCb()->setNetworkSelectionModeManualResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setNrDualConnectivityStateResponse(
         const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setNrDualConnectivityStateResponse(toAidl(info));
+    networkCb()->setNrDualConnectivityStateResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSignalStrengthReportingCriteriaResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setSignalStrengthReportingCriteriaResponse(toAidl(info));
+    networkCb()->setSignalStrengthReportingCriteriaResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSignalStrengthReportingCriteriaResponse_1_5(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setSignalStrengthReportingCriteriaResponse(toAidl(info));
+    networkCb()->setSignalStrengthReportingCriteriaResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSuppServiceNotificationsResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setSuppServiceNotificationsResponse(toAidl(info));
+    networkCb()->setSuppServiceNotificationsResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSystemSelectionChannelsResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setSystemSelectionChannelsResponse(toAidl(info));
+    networkCb()->setSystemSelectionChannelsResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSystemSelectionChannelsResponse_1_5(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->setSystemSelectionChannelsResponse(toAidl(info));
+    networkCb()->setSystemSelectionChannelsResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::startNetworkScanResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->startNetworkScanResponse(toAidl(info));
+    networkCb()->startNetworkScanResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::startNetworkScanResponse_1_4(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->startNetworkScanResponse(toAidl(info));
+    networkCb()->startNetworkScanResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::startNetworkScanResponse_1_5(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->startNetworkScanResponse(toAidl(info));
+    networkCb()->startNetworkScanResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::stopNetworkScanResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->stopNetworkScanResponse(toAidl(info));
+    networkCb()->stopNetworkScanResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::supplyNetworkDepersonalizationResponse(
         const V1_0::RadioResponseInfo& info, int32_t remainingRetries) {
     LOG_CALL << info.serial;
-    CHECK_CB(mNetworkCb);
-    mNetworkCb->supplyNetworkDepersonalizationResponse(toAidl(info), remainingRetries);
+    networkCb()->supplyNetworkDepersonalizationResponse(toAidl(info), remainingRetries);
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/sim/RadioIndication-sim.cpp b/radio/aidl/compat/libradiocompat/sim/RadioIndication-sim.cpp
index 6b906c6..3938e00 100644
--- a/radio/aidl/compat/libradiocompat/sim/RadioIndication-sim.cpp
+++ b/radio/aidl/compat/libradiocompat/sim/RadioIndication-sim.cpp
@@ -29,29 +29,29 @@
 namespace aidl = ::aidl::android::hardware::radio::sim;
 
 void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioSimIndication> simCb) {
-    CHECK(simCb);
     mSimCb = simCb;
 }
 
+std::shared_ptr<aidl::IRadioSimIndication> RadioIndication::simCb() {
+    return mSimCb.get();
+}
+
 Return<void> RadioIndication::carrierInfoForImsiEncryption(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->carrierInfoForImsiEncryption(toAidl(type));
+    simCb()->carrierInfoForImsiEncryption(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::cdmaSubscriptionSourceChanged(
         V1_0::RadioIndicationType type, V1_0::CdmaSubscriptionSource cdmaSource) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->cdmaSubscriptionSourceChanged(toAidl(type), aidl::CdmaSubscriptionSource(cdmaSource));
+    simCb()->cdmaSubscriptionSourceChanged(toAidl(type), aidl::CdmaSubscriptionSource(cdmaSource));
     return {};
 }
 
 Return<void> RadioIndication::simPhonebookChanged(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->simPhonebookChanged(toAidl(type));
+    simCb()->simPhonebookChanged(toAidl(type));
     return {};
 }
 
@@ -59,62 +59,54 @@
         V1_0::RadioIndicationType type, V1_6::PbReceivedStatus status,
         const hidl_vec<V1_6::PhonebookRecordInfo>& rec) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->simPhonebookRecordsReceived(toAidl(type), aidl::PbReceivedStatus(status), toAidl(rec));
+    simCb()->simPhonebookRecordsReceived(toAidl(type), aidl::PbReceivedStatus(status), toAidl(rec));
     return {};
 }
 
 Return<void> RadioIndication::simRefresh(V1_0::RadioIndicationType type,
                                          const V1_0::SimRefreshResult& refreshResult) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->simRefresh(toAidl(type), toAidl(refreshResult));
+    simCb()->simRefresh(toAidl(type), toAidl(refreshResult));
     return {};
 }
 
 Return<void> RadioIndication::simStatusChanged(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->simStatusChanged(toAidl(type));
+    simCb()->simStatusChanged(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::stkEventNotify(V1_0::RadioIndicationType type,
                                              const hidl_string& cmd) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->stkEventNotify(toAidl(type), cmd);
+    simCb()->stkEventNotify(toAidl(type), cmd);
     return {};
 }
 
 Return<void> RadioIndication::stkProactiveCommand(V1_0::RadioIndicationType type,
                                                   const hidl_string& cmd) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->stkProactiveCommand(toAidl(type), cmd);
+    simCb()->stkProactiveCommand(toAidl(type), cmd);
     return {};
 }
 
 Return<void> RadioIndication::stkSessionEnd(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->stkSessionEnd(toAidl(type));
+    simCb()->stkSessionEnd(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::subscriptionStatusChanged(V1_0::RadioIndicationType type,
                                                         bool activate) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->subscriptionStatusChanged(toAidl(type), activate);
+    simCb()->subscriptionStatusChanged(toAidl(type), activate);
     return {};
 }
 
 Return<void> RadioIndication::uiccApplicationsEnablementChanged(V1_0::RadioIndicationType type,
                                                                 bool enabled) {
     LOG_CALL << type;
-    CHECK_CB(mSimCb);
-    mSimCb->uiccApplicationsEnablementChanged(toAidl(type), enabled);
+    simCb()->uiccApplicationsEnablementChanged(toAidl(type), enabled);
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/sim/RadioResponse-sim.cpp b/radio/aidl/compat/libradiocompat/sim/RadioResponse-sim.cpp
index 2dfbc50..3ad9130 100644
--- a/radio/aidl/compat/libradiocompat/sim/RadioResponse-sim.cpp
+++ b/radio/aidl/compat/libradiocompat/sim/RadioResponse-sim.cpp
@@ -29,48 +29,46 @@
 namespace aidl = ::aidl::android::hardware::radio::sim;
 
 void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioSimResponse> simCb) {
-    CHECK(simCb);
     mSimCb = simCb;
 }
 
+std::shared_ptr<aidl::IRadioSimResponse> RadioResponse::simCb() {
+    return mSimCb.get();
+}
+
 Return<void> RadioResponse::areUiccApplicationsEnabledResponse(const V1_0::RadioResponseInfo& info,
                                                                bool enabled) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->areUiccApplicationsEnabledResponse(toAidl(info), enabled);
+    simCb()->areUiccApplicationsEnabledResponse(toAidl(info), enabled);
     return {};
 }
 
 Return<void> RadioResponse::changeIccPin2ForAppResponse(const V1_0::RadioResponseInfo& info,
                                                         int32_t remainingRetries) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->changeIccPin2ForAppResponse(toAidl(info), remainingRetries);
+    simCb()->changeIccPin2ForAppResponse(toAidl(info), remainingRetries);
     return {};
 }
 
 Return<void> RadioResponse::changeIccPinForAppResponse(const V1_0::RadioResponseInfo& info,
                                                        int32_t remainingRetries) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->changeIccPinForAppResponse(toAidl(info), remainingRetries);
+    simCb()->changeIccPinForAppResponse(toAidl(info), remainingRetries);
     return {};
 }
 
 Return<void> RadioResponse::enableUiccApplicationsResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->enableUiccApplicationsResponse(toAidl(info));
+    simCb()->enableUiccApplicationsResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::getAllowedCarriersResponse(  //
         const V1_0::RadioResponseInfo& info, bool allAllowed, const V1_0::CarrierRestrictions& cr) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
     aidl::CarrierRestrictions aidlCr = toAidl(cr);
     if (allAllowed) aidlCr = {};
-    mSimCb->getAllowedCarriersResponse(toAidl(info), aidlCr, {});
+    simCb()->getAllowedCarriersResponse(toAidl(info), aidlCr, {});
     return {};
 }
 
@@ -78,9 +76,8 @@
         const V1_0::RadioResponseInfo& info, const V1_4::CarrierRestrictionsWithPriority& carriers,
         V1_4::SimLockMultiSimPolicy multiSimPolicy) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getAllowedCarriersResponse(toAidl(info), toAidl(carriers),
-                                       aidl::SimLockMultiSimPolicy(multiSimPolicy));
+    simCb()->getAllowedCarriersResponse(toAidl(info), toAidl(carriers),
+                                        aidl::SimLockMultiSimPolicy(multiSimPolicy));
     return {};
 }
 
@@ -88,133 +85,116 @@
         const V1_0::RadioResponseInfo& info, const hidl_string& mdn, const hidl_string& hSid,
         const hidl_string& hNid, const hidl_string& min, const hidl_string& prl) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getCdmaSubscriptionResponse(toAidl(info), mdn, hSid, hNid, min, prl);
+    simCb()->getCdmaSubscriptionResponse(toAidl(info), mdn, hSid, hNid, min, prl);
     return {};
 }
 
 Return<void> RadioResponse::getCdmaSubscriptionSourceResponse(const V1_0::RadioResponseInfo& info,
                                                               V1_0::CdmaSubscriptionSource s) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getCdmaSubscriptionSourceResponse(toAidl(info), aidl::CdmaSubscriptionSource(s));
+    simCb()->getCdmaSubscriptionSourceResponse(toAidl(info), aidl::CdmaSubscriptionSource(s));
     return {};
 }
 
 Return<void> RadioResponse::getFacilityLockForAppResponse(const V1_0::RadioResponseInfo& info,
                                                           int32_t response) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getFacilityLockForAppResponse(toAidl(info), response);
+    simCb()->getFacilityLockForAppResponse(toAidl(info), response);
     return {};
 }
 
 Return<void> RadioResponse::getIccCardStatusResponse(const V1_0::RadioResponseInfo& info,
                                                      const V1_0::CardStatus& cardStatus) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
+    simCb()->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
     return {};
 }
 
 Return<void> RadioResponse::getIccCardStatusResponse_1_2(const V1_0::RadioResponseInfo& info,
                                                          const V1_2::CardStatus& cardStatus) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
+    simCb()->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
     return {};
 }
 
 Return<void> RadioResponse::getIccCardStatusResponse_1_4(const V1_0::RadioResponseInfo& info,
                                                          const V1_4::CardStatus& cardStatus) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
+    simCb()->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
     return {};
 }
 
 Return<void> RadioResponse::getIccCardStatusResponse_1_5(const V1_0::RadioResponseInfo& info,
                                                          const V1_5::CardStatus& cardStatus) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
+    simCb()->getIccCardStatusResponse(toAidl(info), toAidl(cardStatus));
     return {};
 }
 
 Return<void> RadioResponse::getIMSIForAppResponse(const V1_0::RadioResponseInfo& info,
                                                   const hidl_string& imsi) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getImsiForAppResponse(toAidl(info), imsi);
+    simCb()->getImsiForAppResponse(toAidl(info), imsi);
     return {};
 }
 
 Return<void> RadioResponse::getSimPhonebookCapacityResponse(
         const V1_6::RadioResponseInfo& info, const V1_6::PhonebookCapacity& capacity) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getSimPhonebookCapacityResponse(toAidl(info), toAidl(capacity));
+    simCb()->getSimPhonebookCapacityResponse(toAidl(info), toAidl(capacity));
     return {};
 }
 
 Return<void> RadioResponse::getSimPhonebookRecordsResponse(const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->getSimPhonebookRecordsResponse(toAidl(info));
+    simCb()->getSimPhonebookRecordsResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::iccCloseLogicalChannelResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->iccCloseLogicalChannelResponse(toAidl(info));
+    simCb()->iccCloseLogicalChannelResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::iccIOForAppResponse(const V1_0::RadioResponseInfo& info,
                                                 const V1_0::IccIoResult& iccIo) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->iccIoForAppResponse(toAidl(info), toAidl(iccIo));
+    simCb()->iccIoForAppResponse(toAidl(info), toAidl(iccIo));
     return {};
 }
 
 Return<void> RadioResponse::iccOpenLogicalChannelResponse(  //
         const V1_0::RadioResponseInfo& info, int32_t chanId, const hidl_vec<int8_t>& selectResp) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->iccOpenLogicalChannelResponse(toAidl(info), chanId, toAidl(selectResp));
+    simCb()->iccOpenLogicalChannelResponse(toAidl(info), chanId, toAidl(selectResp));
     return {};
 }
 
 Return<void> RadioResponse::iccTransmitApduBasicChannelResponse(const V1_0::RadioResponseInfo& info,
                                                                 const V1_0::IccIoResult& result) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->iccTransmitApduBasicChannelResponse(toAidl(info), toAidl(result));
+    simCb()->iccTransmitApduBasicChannelResponse(toAidl(info), toAidl(result));
     return {};
 }
 
 Return<void> RadioResponse::iccTransmitApduLogicalChannelResponse(
         const V1_0::RadioResponseInfo& info, const V1_0::IccIoResult& result) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->iccTransmitApduLogicalChannelResponse(toAidl(info), toAidl(result));
+    simCb()->iccTransmitApduLogicalChannelResponse(toAidl(info), toAidl(result));
     return {};
 }
 
 Return<void> RadioResponse::reportStkServiceIsRunningResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->reportStkServiceIsRunningResponse(toAidl(info));
+    simCb()->reportStkServiceIsRunningResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::requestIccSimAuthenticationResponse(const V1_0::RadioResponseInfo& info,
                                                                 const V1_0::IccIoResult& result) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->requestIccSimAuthenticationResponse(toAidl(info), toAidl(result));
+    simCb()->requestIccSimAuthenticationResponse(toAidl(info), toAidl(result));
     return {};
 }
 
@@ -228,121 +208,105 @@
 Return<void> RadioResponse::sendEnvelopeResponse(const V1_0::RadioResponseInfo& info,
                                                  const hidl_string& commandResponse) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->sendEnvelopeResponse(toAidl(info), commandResponse);
+    simCb()->sendEnvelopeResponse(toAidl(info), commandResponse);
     return {};
 }
 
 Return<void> RadioResponse::sendEnvelopeWithStatusResponse(const V1_0::RadioResponseInfo& info,
                                                            const V1_0::IccIoResult& iccIo) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->sendEnvelopeWithStatusResponse(toAidl(info), toAidl(iccIo));
+    simCb()->sendEnvelopeWithStatusResponse(toAidl(info), toAidl(iccIo));
     return {};
 }
 
 Return<void> RadioResponse::sendTerminalResponseToSimResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->sendTerminalResponseToSimResponse(toAidl(info));
+    simCb()->sendTerminalResponseToSimResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setAllowedCarriersResponse(const V1_0::RadioResponseInfo& info,
                                                        int32_t numAllowed) {
     LOG_CALL << info.serial << ' ' << numAllowed;
-    CHECK_CB(mSimCb);
-    mSimCb->setAllowedCarriersResponse(toAidl(info));
+    simCb()->setAllowedCarriersResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setAllowedCarriersResponse_1_4(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setAllowedCarriersResponse(toAidl(info));
+    simCb()->setAllowedCarriersResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCarrierInfoForImsiEncryptionResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setCarrierInfoForImsiEncryptionResponse(toAidl(info));
+    simCb()->setCarrierInfoForImsiEncryptionResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCdmaSubscriptionSourceResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setCdmaSubscriptionSourceResponse(toAidl(info));
+    simCb()->setCdmaSubscriptionSourceResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setFacilityLockForAppResponse(const V1_0::RadioResponseInfo& info,
                                                           int32_t retry) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setFacilityLockForAppResponse(toAidl(info), retry);
+    simCb()->setFacilityLockForAppResponse(toAidl(info), retry);
     return {};
 }
 
 Return<void> RadioResponse::setSimCardPowerResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setSimCardPowerResponse(toAidl(info));
+    simCb()->setSimCardPowerResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSimCardPowerResponse_1_1(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setSimCardPowerResponse(toAidl(info));
+    simCb()->setSimCardPowerResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setSimCardPowerResponse_1_6(const V1_6::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setSimCardPowerResponse(toAidl(info));
+    simCb()->setSimCardPowerResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setUiccSubscriptionResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->setUiccSubscriptionResponse(toAidl(info));
+    simCb()->setUiccSubscriptionResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::supplyIccPin2ForAppResponse(const V1_0::RadioResponseInfo& info,
                                                         int32_t remainingRetries) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->supplyIccPin2ForAppResponse(toAidl(info), remainingRetries);
+    simCb()->supplyIccPin2ForAppResponse(toAidl(info), remainingRetries);
     return {};
 }
 
 Return<void> RadioResponse::supplyIccPinForAppResponse(const V1_0::RadioResponseInfo& info,
                                                        int32_t remainingRetries) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->supplyIccPinForAppResponse(toAidl(info), remainingRetries);
+    simCb()->supplyIccPinForAppResponse(toAidl(info), remainingRetries);
     return {};
 }
 
 Return<void> RadioResponse::supplyIccPuk2ForAppResponse(const V1_0::RadioResponseInfo& info,
                                                         int32_t remainingRetries) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->supplyIccPuk2ForAppResponse(toAidl(info), remainingRetries);
+    simCb()->supplyIccPuk2ForAppResponse(toAidl(info), remainingRetries);
     return {};
 }
 
 Return<void> RadioResponse::supplyIccPukForAppResponse(const V1_0::RadioResponseInfo& info,
                                                        int32_t remainingRetries) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->supplyIccPukForAppResponse(toAidl(info), remainingRetries);
+    simCb()->supplyIccPukForAppResponse(toAidl(info), remainingRetries);
     return {};
 }
 
@@ -350,16 +314,14 @@
                                                                V1_5::PersoSubstate persoType,
                                                                int32_t rRet) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->supplySimDepersonalizationResponse(toAidl(info), aidl::PersoSubstate(persoType), rRet);
+    simCb()->supplySimDepersonalizationResponse(toAidl(info), aidl::PersoSubstate(persoType), rRet);
     return {};
 }
 
 Return<void> RadioResponse::updateSimPhonebookRecordsResponse(const V1_6::RadioResponseInfo& info,
                                                               int32_t updatedRecordIndex) {
     LOG_CALL << info.serial;
-    CHECK_CB(mSimCb);
-    mSimCb->updateSimPhonebookRecordsResponse(toAidl(info), updatedRecordIndex);
+    simCb()->updateSimPhonebookRecordsResponse(toAidl(info), updatedRecordIndex);
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/sim/RadioSim.cpp b/radio/aidl/compat/libradiocompat/sim/RadioSim.cpp
index ca27918..b43f64f 100644
--- a/radio/aidl/compat/libradiocompat/sim/RadioSim.cpp
+++ b/radio/aidl/compat/libradiocompat/sim/RadioSim.cpp
@@ -30,6 +30,10 @@
 namespace aidl = ::aidl::android::hardware::radio::sim;
 constexpr auto ok = &ScopedAStatus::ok;
 
+std::shared_ptr<aidl::IRadioSimResponse> RadioSim::respond() {
+    return mCallbackManager->response().simCb();
+}
+
 ScopedAStatus RadioSim::areUiccApplicationsEnabled(int32_t serial) {
     LOG_CALL << serial;
     mHal1_5->areUiccApplicationsEnabled(serial);
@@ -58,7 +62,7 @@
 
 ScopedAStatus RadioSim::getAllowedCarriers(int32_t serial) {
     LOG_CALL << serial;
-    mHal1_5->getAllowedCarriers(serial);
+    mHal1_5->getAllowedCarriers_1_4(serial);
     return ok();
 }
 
@@ -99,7 +103,7 @@
     if (mHal1_6) {
         mHal1_6->getSimPhonebookCapacity(serial);
     } else {
-        respond().getSimPhonebookCapacityResponse(notSupported(serial), {});
+        respond()->getSimPhonebookCapacityResponse(notSupported(serial), {});
     }
     return ok();
 }
@@ -109,7 +113,7 @@
     if (mHal1_6) {
         mHal1_6->getSimPhonebookRecords(serial);
     } else {
-        respond().getSimPhonebookRecordsResponse(notSupported(serial));
+        respond()->getSimPhonebookRecordsResponse(notSupported(serial));
     }
     return ok();
 }
@@ -217,16 +221,10 @@
 }
 
 ScopedAStatus RadioSim::setResponseFunctions(
-        const std::shared_ptr<aidl::IRadioSimResponse>& simResponse,
-        const std::shared_ptr<aidl::IRadioSimIndication>& simIndication) {
-    LOG_CALL << simResponse << ' ' << simIndication;
-
-    CHECK(simResponse);
-    CHECK(simIndication);
-
-    mRadioResponse->setResponseFunction(simResponse);
-    mRadioIndication->setResponseFunction(simIndication);
-
+        const std::shared_ptr<aidl::IRadioSimResponse>& response,
+        const std::shared_ptr<aidl::IRadioSimIndication>& indication) {
+    LOG_CALL << response << ' ' << indication;
+    mCallbackManager->setResponseFunctions(response, indication);
     return ok();
 }
 
@@ -287,7 +285,7 @@
     if (mHal1_6) {
         mHal1_6->updateSimPhonebookRecords(serial, toHidl(recordInfo));
     } else {
-        respond().updateSimPhonebookRecordsResponse(notSupported(serial), 0);
+        respond()->updateSimPhonebookRecordsResponse(notSupported(serial), 0);
     }
     return ok();
 }
diff --git a/radio/aidl/compat/libradiocompat/sim/structs.cpp b/radio/aidl/compat/libradiocompat/sim/structs.cpp
index 97a21a1..bfbff02 100644
--- a/radio/aidl/compat/libradiocompat/sim/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/sim/structs.cpp
@@ -173,7 +173,6 @@
             .atr = status.base.base.atr,
             .iccid = status.base.base.iccid,
             .eid = status.base.eid,
-            // TODO(b/203699028): we don't know portId here (but we can get it from RadioConfig)
             .slotMap = {static_cast<int32_t>(status.base.base.physicalSlotId), 0},
     };
 }
diff --git a/radio/aidl/compat/libradiocompat/voice/RadioIndication-voice.cpp b/radio/aidl/compat/libradiocompat/voice/RadioIndication-voice.cpp
index 6d9bda8..359fce0 100644
--- a/radio/aidl/compat/libradiocompat/voice/RadioIndication-voice.cpp
+++ b/radio/aidl/compat/libradiocompat/voice/RadioIndication-voice.cpp
@@ -29,113 +29,102 @@
 namespace aidl = ::aidl::android::hardware::radio::voice;
 
 void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioVoiceIndication> voiceCb) {
-    CHECK(voiceCb);
     mVoiceCb = voiceCb;
 }
 
+std::shared_ptr<aidl::IRadioVoiceIndication> RadioIndication::voiceCb() {
+    return mVoiceCb.get();
+}
+
 Return<void> RadioIndication::callRing(V1_0::RadioIndicationType type, bool isGsm,
                                        const V1_0::CdmaSignalInfoRecord& record) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->callRing(toAidl(type), isGsm, toAidl(record));
+    voiceCb()->callRing(toAidl(type), isGsm, toAidl(record));
     return {};
 }
 
 Return<void> RadioIndication::callStateChanged(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->callStateChanged(toAidl(type));
+    voiceCb()->callStateChanged(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::cdmaCallWaiting(V1_0::RadioIndicationType type,
                                               const V1_0::CdmaCallWaiting& callWaitingRecord) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->cdmaCallWaiting(toAidl(type), toAidl(callWaitingRecord));
+    voiceCb()->cdmaCallWaiting(toAidl(type), toAidl(callWaitingRecord));
     return {};
 }
 
 Return<void> RadioIndication::cdmaInfoRec(V1_0::RadioIndicationType type,
                                           const V1_0::CdmaInformationRecords& records) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->cdmaInfoRec(toAidl(type), toAidl(records.infoRec));
+    voiceCb()->cdmaInfoRec(toAidl(type), toAidl(records.infoRec));
     return {};
 }
 
 Return<void> RadioIndication::cdmaOtaProvisionStatus(V1_0::RadioIndicationType type,
                                                      V1_0::CdmaOtaProvisionStatus status) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->cdmaOtaProvisionStatus(toAidl(type), aidl::CdmaOtaProvisionStatus(status));
+    voiceCb()->cdmaOtaProvisionStatus(toAidl(type), aidl::CdmaOtaProvisionStatus(status));
     return {};
 }
 
 Return<void> RadioIndication::currentEmergencyNumberList(
         V1_0::RadioIndicationType type, const hidl_vec<V1_4::EmergencyNumber>& emergencyNumbers) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->currentEmergencyNumberList(toAidl(type), toAidl(emergencyNumbers));
+    voiceCb()->currentEmergencyNumberList(toAidl(type), toAidl(emergencyNumbers));
     return {};
 }
 
 Return<void> RadioIndication::enterEmergencyCallbackMode(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->enterEmergencyCallbackMode(toAidl(type));
+    voiceCb()->enterEmergencyCallbackMode(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::exitEmergencyCallbackMode(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->exitEmergencyCallbackMode(toAidl(type));
+    voiceCb()->exitEmergencyCallbackMode(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::indicateRingbackTone(V1_0::RadioIndicationType type, bool start) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->indicateRingbackTone(toAidl(type), start);
+    voiceCb()->indicateRingbackTone(toAidl(type), start);
     return {};
 }
 
 Return<void> RadioIndication::onSupplementaryServiceIndication(V1_0::RadioIndicationType type,
                                                                const V1_0::StkCcUnsolSsResult& ss) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->onSupplementaryServiceIndication(toAidl(type), toAidl(ss));
+    voiceCb()->onSupplementaryServiceIndication(toAidl(type), toAidl(ss));
     return {};
 }
 
 Return<void> RadioIndication::resendIncallMute(V1_0::RadioIndicationType type) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->resendIncallMute(toAidl(type));
+    voiceCb()->resendIncallMute(toAidl(type));
     return {};
 }
 
 Return<void> RadioIndication::srvccStateNotify(V1_0::RadioIndicationType type,
                                                V1_0::SrvccState state) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->srvccStateNotify(toAidl(type), aidl::SrvccState(state));
+    voiceCb()->srvccStateNotify(toAidl(type), aidl::SrvccState(state));
     return {};
 }
 
 Return<void> RadioIndication::stkCallControlAlphaNotify(V1_0::RadioIndicationType type,
                                                         const hidl_string& alpha) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->stkCallControlAlphaNotify(toAidl(type), alpha);
+    voiceCb()->stkCallControlAlphaNotify(toAidl(type), alpha);
     return {};
 }
 
 Return<void> RadioIndication::stkCallSetup(V1_0::RadioIndicationType type, int64_t timeout) {
     LOG_CALL << type;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->stkCallSetup(toAidl(type), timeout);
+    voiceCb()->stkCallSetup(toAidl(type), timeout);
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/voice/RadioResponse-voice.cpp b/radio/aidl/compat/libradiocompat/voice/RadioResponse-voice.cpp
index 0a64c56..d233548 100644
--- a/radio/aidl/compat/libradiocompat/voice/RadioResponse-voice.cpp
+++ b/radio/aidl/compat/libradiocompat/voice/RadioResponse-voice.cpp
@@ -29,265 +29,233 @@
 namespace aidl = ::aidl::android::hardware::radio::voice;
 
 void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioVoiceResponse> voiceCb) {
-    CHECK(voiceCb);
     mVoiceCb = voiceCb;
 }
 
+std::shared_ptr<aidl::IRadioVoiceResponse> RadioResponse::voiceCb() {
+    return mVoiceCb.get();
+}
+
 Return<void> RadioResponse::acceptCallResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->acceptCallResponse(toAidl(info));
+    voiceCb()->acceptCallResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::conferenceResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->conferenceResponse(toAidl(info));
+    voiceCb()->conferenceResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::dialResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->dialResponse(toAidl(info));
+    voiceCb()->dialResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::emergencyDialResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->emergencyDialResponse(toAidl(info));
+    voiceCb()->emergencyDialResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::exitEmergencyCallbackModeResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->exitEmergencyCallbackModeResponse(toAidl(info));
+    voiceCb()->exitEmergencyCallbackModeResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::explicitCallTransferResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->explicitCallTransferResponse(toAidl(info));
+    voiceCb()->explicitCallTransferResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::getCallForwardStatusResponse(
         const V1_0::RadioResponseInfo& info, const hidl_vec<V1_0::CallForwardInfo>& callFwdInfos) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getCallForwardStatusResponse(toAidl(info), toAidl(callFwdInfos));
+    voiceCb()->getCallForwardStatusResponse(toAidl(info), toAidl(callFwdInfos));
     return {};
 }
 
 Return<void> RadioResponse::getCallWaitingResponse(const V1_0::RadioResponseInfo& info, bool enable,
                                                    int32_t serviceClass) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getCallWaitingResponse(toAidl(info), enable, serviceClass);
+    voiceCb()->getCallWaitingResponse(toAidl(info), enable, serviceClass);
     return {};
 }
 
 Return<void> RadioResponse::getClipResponse(const V1_0::RadioResponseInfo& info,
                                             V1_0::ClipStatus status) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getClipResponse(toAidl(info), aidl::ClipStatus(status));
+    voiceCb()->getClipResponse(toAidl(info), aidl::ClipStatus(status));
     return {};
 }
 
 Return<void> RadioResponse::getClirResponse(const V1_0::RadioResponseInfo& info, int32_t n,
                                             int32_t m) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getClirResponse(toAidl(info), n, m);
+    voiceCb()->getClirResponse(toAidl(info), n, m);
     return {};
 }
 
 Return<void> RadioResponse::getCurrentCallsResponse(const V1_0::RadioResponseInfo& info,
                                                     const hidl_vec<V1_0::Call>& calls) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getCurrentCallsResponse(toAidl(info), toAidl(calls));
+    voiceCb()->getCurrentCallsResponse(toAidl(info), toAidl(calls));
     return {};
 }
 
 Return<void> RadioResponse::getCurrentCallsResponse_1_2(const V1_0::RadioResponseInfo& info,
                                                         const hidl_vec<V1_2::Call>& calls) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getCurrentCallsResponse(toAidl(info), toAidl(calls));
+    voiceCb()->getCurrentCallsResponse(toAidl(info), toAidl(calls));
     return {};
 }
 
 Return<void> RadioResponse::getCurrentCallsResponse_1_6(const V1_6::RadioResponseInfo& info,
                                                         const hidl_vec<V1_6::Call>& calls) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getCurrentCallsResponse(toAidl(info), toAidl(calls));
+    voiceCb()->getCurrentCallsResponse(toAidl(info), toAidl(calls));
     return {};
 }
 
 Return<void> RadioResponse::getLastCallFailCauseResponse(
         const V1_0::RadioResponseInfo& info, const V1_0::LastCallFailCauseInfo& failCauseinfo) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getLastCallFailCauseResponse(toAidl(info), toAidl(failCauseinfo));
+    voiceCb()->getLastCallFailCauseResponse(toAidl(info), toAidl(failCauseinfo));
     return {};
 }
 
 Return<void> RadioResponse::getMuteResponse(const V1_0::RadioResponseInfo& info, bool enable) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getMuteResponse(toAidl(info), enable);
+    voiceCb()->getMuteResponse(toAidl(info), enable);
     return {};
 }
 
 Return<void> RadioResponse::getPreferredVoicePrivacyResponse(const V1_0::RadioResponseInfo& info,
                                                              bool enable) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getPreferredVoicePrivacyResponse(toAidl(info), enable);
+    voiceCb()->getPreferredVoicePrivacyResponse(toAidl(info), enable);
     return {};
 }
 
 Return<void> RadioResponse::getTTYModeResponse(const V1_0::RadioResponseInfo& info,
                                                V1_0::TtyMode mode) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->getTtyModeResponse(toAidl(info), aidl::TtyMode(mode));
+    voiceCb()->getTtyModeResponse(toAidl(info), aidl::TtyMode(mode));
     return {};
 }
 
 Return<void> RadioResponse::handleStkCallSetupRequestFromSimResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->handleStkCallSetupRequestFromSimResponse(toAidl(info));
+    voiceCb()->handleStkCallSetupRequestFromSimResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::hangupConnectionResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->hangupConnectionResponse(toAidl(info));
+    voiceCb()->hangupConnectionResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::hangupForegroundResumeBackgroundResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->hangupForegroundResumeBackgroundResponse(toAidl(info));
+    voiceCb()->hangupForegroundResumeBackgroundResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::hangupWaitingOrBackgroundResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->hangupWaitingOrBackgroundResponse(toAidl(info));
+    voiceCb()->hangupWaitingOrBackgroundResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::rejectCallResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->rejectCallResponse(toAidl(info));
+    voiceCb()->rejectCallResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::sendBurstDtmfResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->sendBurstDtmfResponse(toAidl(info));
+    voiceCb()->sendBurstDtmfResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::sendCDMAFeatureCodeResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->sendCdmaFeatureCodeResponse(toAidl(info));
+    voiceCb()->sendCdmaFeatureCodeResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::sendDtmfResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->sendDtmfResponse(toAidl(info));
+    voiceCb()->sendDtmfResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::separateConnectionResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->separateConnectionResponse(toAidl(info));
+    voiceCb()->separateConnectionResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCallForwardResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->setCallForwardResponse(toAidl(info));
+    voiceCb()->setCallForwardResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setCallWaitingResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->setCallWaitingResponse(toAidl(info));
+    voiceCb()->setCallWaitingResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setClirResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->setClirResponse(toAidl(info));
+    voiceCb()->setClirResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setMuteResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->setMuteResponse(toAidl(info));
+    voiceCb()->setMuteResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setPreferredVoicePrivacyResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->setPreferredVoicePrivacyResponse(toAidl(info));
+    voiceCb()->setPreferredVoicePrivacyResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::setTTYModeResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->setTtyModeResponse(toAidl(info));
+    voiceCb()->setTtyModeResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::startDtmfResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->startDtmfResponse(toAidl(info));
+    voiceCb()->startDtmfResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::stopDtmfResponse(const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->stopDtmfResponse(toAidl(info));
+    voiceCb()->stopDtmfResponse(toAidl(info));
     return {};
 }
 
 Return<void> RadioResponse::switchWaitingOrHoldingAndActiveResponse(
         const V1_0::RadioResponseInfo& info) {
     LOG_CALL << info.serial;
-    CHECK_CB(mVoiceCb);
-    mVoiceCb->switchWaitingOrHoldingAndActiveResponse(toAidl(info));
+    voiceCb()->switchWaitingOrHoldingAndActiveResponse(toAidl(info));
     return {};
 }
 
diff --git a/radio/aidl/compat/libradiocompat/voice/RadioVoice.cpp b/radio/aidl/compat/libradiocompat/voice/RadioVoice.cpp
index 16c6b14..71d1a56 100644
--- a/radio/aidl/compat/libradiocompat/voice/RadioVoice.cpp
+++ b/radio/aidl/compat/libradiocompat/voice/RadioVoice.cpp
@@ -30,6 +30,10 @@
 namespace aidl = ::aidl::android::hardware::radio::voice;
 constexpr auto ok = &ScopedAStatus::ok;
 
+std::shared_ptr<aidl::IRadioVoiceResponse> RadioVoice::respond() {
+    return mCallbackManager->response().voiceCb();
+}
+
 ScopedAStatus RadioVoice::acceptCall(int32_t serial) {
     LOG_CALL << serial;
     mHal1_5->acceptCall(serial);
@@ -49,13 +53,19 @@
 }
 
 ScopedAStatus RadioVoice::emergencyDial(  //
-        int32_t serial, const aidl::Dial& dialInfo, aidl::EmergencyServiceCategory categories,
+        int32_t serial, const aidl::Dial& info, int32_t categories,
         const std::vector<std::string>& urns, aidl::EmergencyCallRouting routing,
-        bool hasKnownUserIntentEmerg, bool isTesting) {
+        bool knownUserIntentEmerg, bool isTesting) {
     LOG_CALL << serial;
-    mHal1_5->emergencyDial(serial, toHidl(dialInfo),
-                           toHidlBitfield<V1_4::EmergencyServiceCategory>(categories), toHidl(urns),
-                           V1_4::EmergencyCallRouting(routing), hasKnownUserIntentEmerg, isTesting);
+    if (mHal1_6) {
+        mHal1_6->emergencyDial_1_6(  //
+                serial, toHidl(info), toHidlBitfield<V1_4::EmergencyServiceCategory>(categories),
+                toHidl(urns), V1_4::EmergencyCallRouting(routing), knownUserIntentEmerg, isTesting);
+    } else {
+        mHal1_5->emergencyDial(  //
+                serial, toHidl(info), toHidlBitfield<V1_4::EmergencyServiceCategory>(categories),
+                toHidl(urns), V1_4::EmergencyCallRouting(routing), knownUserIntentEmerg, isTesting);
+    }
     return ok();
 }
 
@@ -98,7 +108,11 @@
 
 ScopedAStatus RadioVoice::getCurrentCalls(int32_t serial) {
     LOG_CALL << serial;
-    mHal1_5->getCurrentCalls(serial);
+    if (mHal1_6) {
+        mHal1_6->getCurrentCalls_1_6(serial);
+    } else {
+        mHal1_5->getCurrentCalls(serial);
+    }
     return ok();
 }
 
@@ -152,7 +166,7 @@
 
 ScopedAStatus RadioVoice::isVoNrEnabled(int32_t serial) {
     LOG_CALL << serial;
-    // TODO(b/203699028): can't call isVoNrEnabledResponse with 1.6 callback
+    respond()->isVoNrEnabledResponse(notSupported(serial), false);
     return ok();
 }
 
@@ -224,16 +238,10 @@
 }
 
 ScopedAStatus RadioVoice::setResponseFunctions(
-        const std::shared_ptr<aidl::IRadioVoiceResponse>& voiceResponse,
-        const std::shared_ptr<aidl::IRadioVoiceIndication>& voiceIndication) {
-    LOG_CALL << voiceResponse << ' ' << voiceIndication;
-
-    CHECK(voiceResponse);
-    CHECK(voiceIndication);
-
-    mRadioResponse->setResponseFunction(voiceResponse);
-    mRadioIndication->setResponseFunction(voiceIndication);
-
+        const std::shared_ptr<aidl::IRadioVoiceResponse>& response,
+        const std::shared_ptr<aidl::IRadioVoiceIndication>& indication) {
+    LOG_CALL << response << ' ' << indication;
+    mCallbackManager->setResponseFunctions(response, indication);
     return ok();
 }
 
@@ -245,7 +253,8 @@
 
 ndk::ScopedAStatus RadioVoice::setVoNrEnabled(int32_t serial, [[maybe_unused]] bool enable) {
     LOG_CALL << serial;
-    // TODO(b/203699028): should set `persist.radio.is_vonr_enabled_` property instead
+    // Note: a workaround for older HALs could also be setting persist.radio.is_vonr_enabled_
+    respond()->setVoNrEnabledResponse(notSupported(serial));
     return ok();
 }
 
diff --git a/radio/aidl/compat/libradiocompat/voice/structs.cpp b/radio/aidl/compat/libradiocompat/voice/structs.cpp
index ae6342e..254ea20 100644
--- a/radio/aidl/compat/libradiocompat/voice/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/voice/structs.cpp
@@ -147,7 +147,7 @@
             .number = num.number,
             .mcc = num.mcc,
             .mnc = num.mnc,
-            .categories = aidl::EmergencyServiceCategory(num.categories),
+            .categories = num.categories,
             .urns = toAidl(num.urns),
             .sources = num.sources,
     };
diff --git a/radio/aidl/compat/service/service.cpp b/radio/aidl/compat/service/service.cpp
index 2a67569..8af05de 100644
--- a/radio/aidl/compat/service/service.cpp
+++ b/radio/aidl/compat/service/service.cpp
@@ -19,13 +19,12 @@
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <libradiocompat/CallbackManager.h>
 #include <libradiocompat/RadioConfig.h>
 #include <libradiocompat/RadioData.h>
-#include <libradiocompat/RadioIndication.h>
 #include <libradiocompat/RadioMessaging.h>
 #include <libradiocompat/RadioModem.h>
 #include <libradiocompat/RadioNetwork.h>
-#include <libradiocompat/RadioResponse.h>
 #include <libradiocompat/RadioSim.h>
 #include <libradiocompat/RadioVoice.h>
 
@@ -36,8 +35,8 @@
 static std::vector<std::shared_ptr<ndk::ICInterface>> gPublishedHals;
 
 template <typename T>
-static void publishRadioHal(sp<V1_5::IRadio> hidlHal, sp<compat::RadioResponse> responseCb,
-                            sp<compat::RadioIndication> indicationCb, const std::string& slot) {
+static void publishRadioHal(std::shared_ptr<compat::DriverContext> ctx, sp<V1_5::IRadio> hidlHal,
+                            std::shared_ptr<compat::CallbackManager> cm, const std::string& slot) {
     const auto instance = T::descriptor + "/"s + slot;
     if (!AServiceManager_isDeclared(instance.c_str())) {
         LOG(INFO) << instance << " is not declared in VINTF (this may be intentional)";
@@ -45,7 +44,7 @@
     }
     LOG(DEBUG) << "Publishing " << instance;
 
-    auto aidlHal = ndk::SharedRefBase::make<T>(hidlHal, responseCb, indicationCb);
+    auto aidlHal = ndk::SharedRefBase::make<T>(ctx, hidlHal, cm);
     gPublishedHals.push_back(aidlHal);
     const auto status = AServiceManager_addService(aidlHal->asBinder().get(), instance.c_str());
     CHECK_EQ(status, STATUS_OK);
@@ -57,16 +56,15 @@
 
     hidl_utils::linkDeathToDeath(radioHidl);
 
-    auto responseCb = sp<compat::RadioResponse>::make();
-    auto indicationCb = sp<compat::RadioIndication>::make();
-    radioHidl->setResponseFunctions(responseCb, indicationCb).assertOk();
+    auto context = std::make_shared<compat::DriverContext>();
+    auto callbackMgr = std::make_shared<compat::CallbackManager>(context, radioHidl);
 
-    publishRadioHal<compat::RadioData>(radioHidl, responseCb, indicationCb, slot);
-    publishRadioHal<compat::RadioMessaging>(radioHidl, responseCb, indicationCb, slot);
-    publishRadioHal<compat::RadioModem>(radioHidl, responseCb, indicationCb, slot);
-    publishRadioHal<compat::RadioNetwork>(radioHidl, responseCb, indicationCb, slot);
-    publishRadioHal<compat::RadioSim>(radioHidl, responseCb, indicationCb, slot);
-    publishRadioHal<compat::RadioVoice>(radioHidl, responseCb, indicationCb, slot);
+    publishRadioHal<compat::RadioData>(context, radioHidl, callbackMgr, slot);
+    publishRadioHal<compat::RadioMessaging>(context, radioHidl, callbackMgr, slot);
+    publishRadioHal<compat::RadioModem>(context, radioHidl, callbackMgr, slot);
+    publishRadioHal<compat::RadioNetwork>(context, radioHidl, callbackMgr, slot);
+    publishRadioHal<compat::RadioSim>(context, radioHidl, callbackMgr, slot);
+    publishRadioHal<compat::RadioVoice>(context, radioHidl, callbackMgr, slot);
 }
 
 static void publishRadioConfig() {
@@ -83,6 +81,7 @@
 }
 
 static void main() {
+    base::InitLogging(nullptr, base::LogdLogger(base::RADIO));
     base::SetDefaultTag("radiocompat");
     base::SetMinimumLogSeverity(base::VERBOSE);
     LOG(DEBUG) << "Radio HAL compat service starting...";
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
new file mode 100644
index 0000000..8060e4b
--- /dev/null
+++ b/radio/aidl/vts/Android.bp
@@ -0,0 +1,74 @@
+// Copyright 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalRadioTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "radio_aidl_hal_utils.cpp",
+        "radio_config_indication.cpp",
+        "radio_config_response.cpp",
+        "radio_config_test.cpp",
+        "radio_data_indication.cpp",
+        "radio_data_response.cpp",
+        "radio_data_test.cpp",
+        "radio_messaging_indication.cpp",
+        "radio_messaging_response.cpp",
+        "radio_messaging_test.cpp",
+        "radio_modem_indication.cpp",
+        "radio_modem_response.cpp",
+        "radio_modem_test.cpp",
+        "radio_network_indication.cpp",
+        "radio_network_response.cpp",
+        "radio_network_test.cpp",
+        "radio_sim_indication.cpp",
+        "radio_sim_response.cpp",
+        "radio_sim_test.cpp",
+        "radio_voice_indication.cpp",
+        "radio_voice_response.cpp",
+        "radio_voice_test.cpp",
+        "VtsHalRadioTargetTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libvintf",
+    ],
+    static_libs: [
+        "android.hardware.radio-V1-ndk",
+        "android.hardware.radio.config-V1-ndk",
+        "android.hardware.radio.data-V1-ndk",
+        "android.hardware.radio.messaging-V1-ndk",
+        "android.hardware.radio.modem-V1-ndk",
+        "android.hardware.radio.network-V1-ndk",
+        "android.hardware.radio.sim-V1-ndk",
+        "android.hardware.radio.voice-V1-ndk",
+    ],
+    // TODO(b/210712359): enable after b/207695009 is resolved.
+    //test_suites: [
+    //    "general-tests",
+    //    "vts",
+    //],
+}
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
new file mode 100644
index 0000000..1ebc6af
--- /dev/null
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_process.h>
+
+#include "radio_config_utils.h"
+#include "radio_data_utils.h"
+#include "radio_messaging_utils.h"
+#include "radio_modem_utils.h"
+#include "radio_network_utils.h"
+#include "radio_sim_utils.h"
+#include "radio_voice_utils.h"
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioConfigTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioConfigTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRadioConfig::descriptor)),
+        android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioDataTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioDataTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRadioData::descriptor)),
+        android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioMessagingTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioMessagingTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRadioMessaging::descriptor)),
+        android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioModemTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioModemTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRadioModem::descriptor)),
+        android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioNetworkTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioNetworkTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRadioNetwork::descriptor)),
+        android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSimTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, RadioSimTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IRadioSim::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioVoiceTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioVoiceTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRadioVoice::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
new file mode 100644
index 0000000..dc61a3c
--- /dev/null
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "RadioTest"
+
+#include "radio_aidl_hal_utils.h"
+#include <iostream>
+#include "VtsCoreUtil.h"
+#include "radio_config_utils.h"
+#include "radio_sim_utils.h"
+
+#define WAIT_TIMEOUT_PERIOD 75
+
+sim::CardStatus cardStatus = {};
+int serial = 0;
+int count_ = 0;
+
+int GetRandomSerialNumber() {
+    return rand();
+}
+
+::testing::AssertionResult CheckAnyOfErrors(RadioError err, std::vector<RadioError> errors,
+                                            CheckFlag flag) {
+    const static std::vector<RadioError> generalErrors = {
+            RadioError::RADIO_NOT_AVAILABLE,   RadioError::NO_MEMORY,
+            RadioError::INTERNAL_ERR,          RadioError::SYSTEM_ERR,
+            RadioError::REQUEST_NOT_SUPPORTED, RadioError::CANCELLED};
+    if (flag == CHECK_GENERAL_ERROR || flag == CHECK_OEM_AND_GENERAL_ERROR) {
+        for (size_t i = 0; i < generalErrors.size(); i++) {
+            if (err == generalErrors[i]) {
+                return testing::AssertionSuccess();
+            }
+        }
+    }
+    if (flag == CHECK_OEM_ERROR || flag == CHECK_OEM_AND_GENERAL_ERROR) {
+        if (err >= RadioError::OEM_ERROR_1 && err <= RadioError::OEM_ERROR_25) {
+            return testing::AssertionSuccess();
+        }
+    }
+    for (size_t i = 0; i < errors.size(); i++) {
+        if (err == errors[i]) {
+            return testing::AssertionSuccess();
+        }
+    }
+    return testing::AssertionFailure() << "RadioError:" + toString(err) + " is returned";
+}
+
+// Runs "pm list features" and attempts to find the specified feature in its output.
+bool deviceSupportsFeature(const char* feature) {
+    bool hasFeature = false;
+    FILE* p = popen("/system/bin/pm list features", "re");
+    if (p) {
+        char* line = NULL;
+        size_t len = 0;
+        while (getline(&line, &len, p) > 0) {
+            if (strstr(line, feature)) {
+                hasFeature = true;
+                break;
+            }
+        }
+        pclose(p);
+    } else {
+        __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "popen failed: %d", errno);
+        _exit(EXIT_FAILURE);
+    }
+    __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Feature %s: %ssupported", feature,
+                        hasFeature ? "" : "not ");
+    return hasFeature;
+}
+
+bool isSsSsEnabled() {
+    // 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();
+}
+
+bool isDsDsEnabled() {
+    return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsds");
+}
+
+bool isTsTsEnabled() {
+    return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "tsts");
+}
+
+bool isVoiceInService(RegState state) {
+    return RegState::REG_HOME == state || RegState::REG_ROAMING == state;
+}
+
+bool isVoiceEmergencyOnly(RegState state) {
+    return RegState::NOT_REG_MT_NOT_SEARCHING_OP_EM == state ||
+           RegState::NOT_REG_MT_SEARCHING_OP_EM == state || RegState::REG_DENIED_EM == state ||
+           RegState::UNKNOWN_EM == state;
+}
+
+bool stringEndsWith(std::string const& string, std::string const& end) {
+    if (string.size() >= end.size()) {
+        return (0 == string.compare(string.size() - end.size() - 1, end.size(), end));
+    } else {
+        return false;
+    }
+}
+
+bool isServiceValidForDeviceConfiguration(std::string& serviceName) {
+    if (isSsSsEnabled()) {
+        // Device is configured as SSSS.
+        if (stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME)) {
+            ALOGI("%s instance is not valid for SSSS device.", serviceName.c_str());
+            return false;
+        }
+    } else if (isDsDsEnabled()) {
+        // Device is configured as DSDS.
+        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());
+            return false;
+        }
+    } else if (isTsTsEnabled()) {
+        // Device is configured as TSTS.
+        if (!stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME) &&
+            !stringEndsWith(serviceName, RADIO_SERVICE_SLOT2_NAME) &&
+            !stringEndsWith(serviceName, RADIO_SERVICE_SLOT3_NAME)) {
+            ALOGI("%s instance is not valid for TSTS device.", serviceName.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioServiceTest::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx_);
+    if (serial == receivedSerial) {
+        count_++;
+        cv_.notify_one();
+    }
+}
+
+/*
+ * Wait till the response message is notified or till WAIT_TIMEOUT_PERIOD.
+ */
+std::cv_status RadioServiceTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(WAIT_TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count_--;
+    return status;
+}
+
+/**
+ * Specific features on the Radio HAL rely on Radio HAL Capabilities.
+ * The VTS test related to those features must not run if the related capability is disabled.
+ * Typical usage within VTS:
+ * if (getRadioHalCapabilities()) return;
+ */
+bool RadioServiceTest::getRadioHalCapabilities() {
+    // Get HalDeviceCapabilities from RadioConfig
+    std::shared_ptr<RadioConfigResponse> radioConfigRsp =
+            ndk::SharedRefBase::make<RadioConfigResponse>(*this);
+    std::shared_ptr<RadioConfigIndication> radioConfigInd =
+            ndk::SharedRefBase::make<RadioConfigIndication>(*this);
+    radio_config->setResponseFunctions(radioConfigRsp, radioConfigInd);
+    serial = GetRandomSerialNumber();
+    radio_config->getHalDeviceCapabilities(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    return radioConfigRsp->modemReducedFeatureSet1;
+}
+
+/**
+ * Some VTS tests require the SIM card status to be present before running.
+ * Update the SIM card status, which can be accessed via the extern cardStatus.
+ */
+void RadioServiceTest::updateSimCardStatus() {
+    // Update CardStatus from RadioSim
+    std::shared_ptr<RadioSimResponse> radioSimRsp =
+            ndk::SharedRefBase::make<RadioSimResponse>(*this);
+    std::shared_ptr<RadioSimIndication> radioSimInd =
+            ndk::SharedRefBase::make<RadioSimIndication>(*this);
+    radio_sim->setResponseFunctions(radioSimRsp, radioSimInd);
+    serial = GetRandomSerialNumber();
+    radio_sim->getIccCardStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioSimRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioSimRsp->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioSimRsp->rspInfo.error);
+}
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
new file mode 100644
index 0000000..414ffbc
--- /dev/null
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/radio/RadioError.h>
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <aidl/android/hardware/radio/network/RegState.h>
+#include <aidl/android/hardware/radio/sim/CardStatus.h>
+#include <aidl/android/hardware/radio/sim/IRadioSim.h>
+#include <utils/Log.h>
+#include <vector>
+
+using namespace aidl::android::hardware::radio;
+using aidl::android::hardware::radio::network::RegState;
+using aidl::android::hardware::radio::sim::CardStatus;
+
+extern CardStatus cardStatus;
+extern int serial;
+extern int count_;
+
+/*
+ * MACRO used to skip test case when radio response return error REQUEST_NOT_SUPPORTED
+ * on HAL versions which has deprecated the request interfaces. The MACRO can only be used
+ * AFTER receiving radio response.
+ */
+#define SKIP_TEST_IF_REQUEST_NOT_SUPPORTED_WITH_HAL(__ver__, __radio__, __radioRsp__)      \
+    do {                                                                                   \
+        sp<::android::hardware::radio::V##__ver__::IRadio> __radio =                       \
+                ::android::hardware::radio::V##__ver__::IRadio::castFrom(__radio__);       \
+        if (__radio && __radioRsp__->rspInfo.error == RadioError::REQUEST_NOT_SUPPORTED) { \
+            GTEST_SKIP() << "REQUEST_NOT_SUPPORTED";                                       \
+        }                                                                                  \
+    } while (0)
+
+enum CheckFlag {
+    CHECK_DEFAULT = 0,
+    CHECK_GENERAL_ERROR = 1,
+    CHECK_OEM_ERROR = 2,
+    CHECK_OEM_AND_GENERAL_ERROR = 3,
+    CHECK_SAP_ERROR = 4,
+};
+
+static constexpr const char* FEATURE_VOICE_CALL = "android.software.connectionservice";
+
+static constexpr const char* FEATURE_TELEPHONY = "android.hardware.telephony";
+
+static constexpr const char* FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
+
+static constexpr const char* FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
+
+#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
+#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
+#define MODEM_SET_SIM_POWER_DELAY_IN_SECONDS 2
+
+#define RADIO_SERVICE_SLOT1_NAME "slot1"  // HAL instance name for SIM slot 1 or single SIM device
+#define RADIO_SERVICE_SLOT2_NAME "slot2"  // HAL instance name for SIM slot 2 on dual SIM device
+#define RADIO_SERVICE_SLOT3_NAME "slot3"  // HAL instance name for SIM slot 3 on triple SIM device
+
+/*
+ * Generate random serial number for radio test
+ */
+int GetRandomSerialNumber();
+
+/*
+ * Check multiple radio error codes which are possibly returned because of the different
+ * vendor/devices implementations. It allows optional checks for general errors or/and oem errors.
+ */
+::testing::AssertionResult CheckAnyOfErrors(RadioError err, std::vector<RadioError> generalError,
+                                            CheckFlag flag = CHECK_DEFAULT);
+
+/*
+ * Check if device supports feature.
+ */
+bool deviceSupportsFeature(const char* feature);
+
+/*
+ * Check if device is in SsSs (Single SIM Single Standby).
+ */
+bool isSsSsEnabled();
+
+/*
+ * Check if device is in DSDS (Dual SIM Dual Standby).
+ */
+bool isDsDsEnabled();
+
+/*
+ * Check if device is in TSTS (Triple SIM Triple Standby).
+ */
+bool isTsTsEnabled();
+
+/*
+ * Check if voice status is in emergency only.
+ */
+bool isVoiceEmergencyOnly(RegState state);
+
+/*
+ * Check if voice status is in service.
+ */
+bool isVoiceInService(RegState state);
+
+/*
+ * Check if service is valid for device configuration
+ */
+bool isServiceValidForDeviceConfiguration(std::string& serviceName);
+
+/**
+ * RadioServiceTest base class
+ */
+class RadioServiceTest {
+  protected:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    std::shared_ptr<config::IRadioConfig> radio_config;
+    std::shared_ptr<sim::IRadioSim> radio_sim;
+
+  public:
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    /* Get the radio HAL capabilities */
+    bool getRadioHalCapabilities();
+
+    /* Update SIM card status */
+    void updateSimCardStatus();
+};
diff --git a/radio/aidl/vts/radio_config_indication.cpp b/radio/aidl/vts/radio_config_indication.cpp
new file mode 100644
index 0000000..a84c20b
--- /dev/null
+++ b/radio/aidl/vts/radio_config_indication.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_config_utils.h"
+
+RadioConfigIndication::RadioConfigIndication(RadioServiceTest& parent) : parent_config(parent) {}
+
+ndk::ScopedAStatus RadioConfigIndication::simSlotsStatusChanged(
+        RadioIndicationType /*type*/, const std::vector<SimSlotStatus>& /*slotStatus*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_config_response.cpp b/radio/aidl/vts/radio_config_response.cpp
new file mode 100644
index 0000000..1a152fb
--- /dev/null
+++ b/radio/aidl/vts/radio_config_response.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_config_utils.h"
+
+RadioConfigResponse::RadioConfigResponse(RadioServiceTest& parent) : parent_config(parent) {}
+
+ndk::ScopedAStatus RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */, const std::vector<SimSlotStatus>& /* slotStatus */) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioConfigResponse::setSimSlotsMappingResponse(
+        const RadioResponseInfo& /* info */) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& info, const PhoneCapability& phoneCapability) {
+    rspInfo = info;
+    phoneCap = phoneCapability;
+    parent_config.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioConfigResponse::getNumOfLiveModemsResponse(
+        const RadioResponseInfo& /* info */, const int8_t /* numOfLiveModems */) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioConfigResponse::setNumOfLiveModemsResponse(
+        const RadioResponseInfo& /* info */) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioConfigResponse::getHalDeviceCapabilitiesResponse(
+        const RadioResponseInfo& info, bool modemReducedFeatures) {
+    modemReducedFeatureSet1 = modemReducedFeatures;
+    parent_config.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
new file mode 100644
index 0000000..2d7fe01
--- /dev/null
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_config_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioConfigTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_config = IRadioConfig::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_config.get());
+
+    radioRsp_config = ndk::SharedRefBase::make<RadioConfigResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_config.get());
+
+    count_ = 0;
+
+    radioInd_config = ndk::SharedRefBase::make<RadioConfigIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_config.get());
+
+    radio_config->setResponseFunctions(radioRsp_config, radioInd_config);
+}
+
+/*
+ * Test IRadioConfig.getHalDeviceCapabilities() for the response returned.
+ */
+TEST_P(RadioConfigTest, getHalDeviceCapabilities) {
+    serial = GetRandomSerialNumber();
+    ndk::ScopedAStatus res = radio_config->getHalDeviceCapabilities(serial);
+    ASSERT_OK(res);
+    ALOGI("getHalDeviceCapabilities, rspInfo.error = %s\n",
+          toString(radioRsp_config->rspInfo.error).c_str());
+}
diff --git a/radio/aidl/vts/radio_config_utils.h b/radio/aidl/vts/radio_config_utils.h
new file mode 100644
index 0000000..465c106
--- /dev/null
+++ b/radio/aidl/vts/radio_config_utils.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/config/BnRadioConfigIndication.h>
+#include <aidl/android/hardware/radio/config/BnRadioConfigResponse.h>
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::config;
+
+class RadioConfigTest;
+
+/* Callback class for radio config response */
+class RadioConfigResponse : public BnRadioConfigResponse {
+  protected:
+    RadioServiceTest& parent_config;
+
+  public:
+    RadioConfigResponse(RadioServiceTest& parent_config);
+    virtual ~RadioConfigResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    PhoneCapability phoneCap;
+    bool modemReducedFeatureSet1;
+
+    virtual ndk::ScopedAStatus getSimSlotsStatusResponse(
+            const RadioResponseInfo& info, const std::vector<SimSlotStatus>& slotStatus) override;
+
+    virtual ndk::ScopedAStatus setSimSlotsMappingResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getPhoneCapabilityResponse(
+            const RadioResponseInfo& info, const PhoneCapability& phoneCapability) override;
+
+    virtual ndk::ScopedAStatus setPreferredDataModemResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getNumOfLiveModemsResponse(const RadioResponseInfo& info,
+                                                          const int8_t numOfLiveModems) override;
+
+    virtual ndk::ScopedAStatus setNumOfLiveModemsResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getHalDeviceCapabilitiesResponse(
+            const RadioResponseInfo& info, bool modemReducedFeatureSet1) override;
+};
+
+/* Callback class for radio config indication */
+class RadioConfigIndication : public BnRadioConfigIndication {
+  protected:
+    RadioServiceTest& parent_config;
+
+  public:
+    RadioConfigIndication(RadioServiceTest& parent_config);
+    virtual ~RadioConfigIndication() = default;
+
+    virtual ndk::ScopedAStatus simSlotsStatusChanged(
+            RadioIndicationType type, const std::vector<SimSlotStatus>& slotStatus) override;
+};
+
+// The main test class for Radio AIDL Config.
+class RadioConfigTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  public:
+    virtual void SetUp() override;
+    ndk::ScopedAStatus updateSimCardStatus();
+
+    /* radio config service handle in RadioServiceTest */
+    /* radio config response handle */
+    std::shared_ptr<RadioConfigResponse> radioRsp_config;
+    /* radio config indication handle */
+    std::shared_ptr<RadioConfigIndication> radioInd_config;
+};
diff --git a/radio/aidl/vts/radio_data_indication.cpp b/radio/aidl/vts/radio_data_indication.cpp
new file mode 100644
index 0000000..61e079e
--- /dev/null
+++ b/radio/aidl/vts/radio_data_indication.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_data_utils.h"
+
+RadioDataIndication::RadioDataIndication(RadioServiceTest& parent) : parent_data(parent) {}
+
+ndk::ScopedAStatus RadioDataIndication::dataCallListChanged(
+        RadioIndicationType /*type*/, const std::vector<SetupDataCallResult>& /*dcList*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataIndication::keepaliveStatus(RadioIndicationType /*type*/,
+                                                        const KeepaliveStatus& /*status*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataIndication::pcoData(RadioIndicationType /*type*/,
+                                                const PcoDataInfo& /*pco*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataIndication::unthrottleApn(RadioIndicationType /*type*/,
+                                                      const DataProfileInfo& /*dataProfileInfo*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataIndication::slicingConfigChanged(
+        RadioIndicationType /*type*/, const SlicingConfig& /*slicingConfig*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_data_response.cpp b/radio/aidl/vts/radio_data_response.cpp
new file mode 100644
index 0000000..9b17bfb
--- /dev/null
+++ b/radio/aidl/vts/radio_data_response.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_data_utils.h"
+
+RadioDataResponse::RadioDataResponse(RadioServiceTest& parent) : parent_data(parent) {}
+
+ndk::ScopedAStatus RadioDataResponse::acknowledgeRequest(int32_t /*serial*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::allocatePduSessionIdResponse(const RadioResponseInfo& info,
+                                                                   int32_t id) {
+    rspInfo = info;
+    allocatedPduSessionId = id;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::cancelHandoverResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::deactivateDataCallResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::getDataCallListResponse(
+        const RadioResponseInfo& info, const std::vector<SetupDataCallResult>& /*dcResponse*/) {
+    rspInfo = info;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::getSlicingConfigResponse(
+        const RadioResponseInfo& info, const SlicingConfig& /*slicingConfig*/) {
+    rspInfo = info;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::releasePduSessionIdResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::setDataAllowedResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::setDataProfileResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::setDataThrottlingResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::setInitialAttachApnResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::setupDataCallResponse(const RadioResponseInfo& info,
+                                                            const SetupDataCallResult& dcResponse) {
+    rspInfo = info;
+    setupDataCallResult = dcResponse;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::startHandoverResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_data.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::startKeepaliveResponse(const RadioResponseInfo& /*info*/,
+                                                             const KeepaliveStatus& /*status*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioDataResponse::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_data_test.cpp b/radio/aidl/vts/radio_data_test.cpp
new file mode 100644
index 0000000..8547e9d
--- /dev/null
+++ b/radio/aidl/vts/radio_data_test.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/radio/RadioAccessFamily.h>
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <aidl/android/hardware/radio/data/ApnTypes.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_data_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioDataTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_data = IRadioData::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_data.get());
+
+    radioRsp_data = ndk::SharedRefBase::make<RadioDataResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_data.get());
+
+    count_ = 0;
+
+    radioInd_data = ndk::SharedRefBase::make<RadioDataIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_data.get());
+
+    radio_data->setResponseFunctions(radioRsp_data, radioInd_data);
+
+    // Assert IRadioSim exists and SIM is present before testing
+    radio_sim = sim::IRadioSim::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.sim.IRadioSim/slot1")));
+    ASSERT_NE(nullptr, radio_sim.get());
+    updateSimCardStatus();
+    EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+
+    // Assert IRadioConfig exists before testing
+    radio_config = config::IRadioConfig::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.config.IRadioConfig/default")));
+    ASSERT_NE(nullptr, radio_config.get());
+}
+
+ndk::ScopedAStatus RadioDataTest::getDataCallList() {
+    serial = GetRandomSerialNumber();
+    radio_data->getDataCallList(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    return ndk::ScopedAStatus::ok();
+}
+
+/*
+ * Test IRadioData.setupDataCall() for the response returned.
+ */
+TEST_P(RadioDataTest, setupDataCall) {
+    serial = GetRandomSerialNumber();
+
+    AccessNetwork accessNetwork = AccessNetwork::EUTRAN;
+
+    DataProfileInfo dataProfileInfo;
+    memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+    dataProfileInfo.profileId = DataProfileInfo::ID_DEFAULT;
+    dataProfileInfo.apn = std::string("internet");
+    dataProfileInfo.protocol = PdpProtocolType::IP;
+    dataProfileInfo.roamingProtocol = PdpProtocolType::IP;
+    dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+    dataProfileInfo.user = std::string("username");
+    dataProfileInfo.password = std::string("password");
+    dataProfileInfo.type = DataProfileInfo::TYPE_THREE_GPP;
+    dataProfileInfo.maxConnsTime = 300;
+    dataProfileInfo.maxConns = 20;
+    dataProfileInfo.waitTime = 0;
+    dataProfileInfo.enabled = true;
+    dataProfileInfo.supportedApnTypesBitmap =
+            static_cast<int32_t>(ApnTypes::IMS) | static_cast<int32_t>(ApnTypes::IA);
+    dataProfileInfo.bearerBitmap = static_cast<int32_t>(RadioAccessFamily::GPRS) |
+                                   static_cast<int32_t>(RadioAccessFamily::EDGE) |
+                                   static_cast<int32_t>(RadioAccessFamily::UMTS) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSDPA) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSUPA) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSPA) |
+                                   static_cast<int32_t>(RadioAccessFamily::EHRPD) |
+                                   static_cast<int32_t>(RadioAccessFamily::LTE) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSPAP) |
+                                   static_cast<int32_t>(RadioAccessFamily::IWLAN);
+    dataProfileInfo.mtuV4 = 0;
+    dataProfileInfo.mtuV6 = 0;
+    dataProfileInfo.preferred = true;
+    dataProfileInfo.persistent = false;
+
+    bool roamingAllowed = false;
+
+    std::vector<LinkAddress> addresses = {};
+    std::vector<std::string> dnses = {};
+
+    DataRequestReason reason = DataRequestReason::NORMAL;
+    SliceInfo sliceInfo;
+    bool matchAllRuleAllowed = true;
+
+    ndk::ScopedAStatus res =
+            radio_data->setupDataCall(serial, accessNetwork, dataProfileInfo, roamingAllowed,
+                                      reason, addresses, dnses, -1, sliceInfo, matchAllRuleAllowed);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_data->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_data->rspInfo.serial);
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+    } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+    }
+}
+
+/*
+ * Test IRadioData.setupDataCall() with osAppId for the response returned.
+ */
+TEST_P(RadioDataTest, setupDataCall_osAppId) {
+    serial = GetRandomSerialNumber();
+
+    AccessNetwork accessNetwork = AccessNetwork::EUTRAN;
+
+    TrafficDescriptor trafficDescriptor;
+    OsAppId osAppId;
+    std::string osAppIdString("osAppId");
+    std::vector<unsigned char> osAppIdVec(osAppIdString.begin(), osAppIdString.end());
+    osAppId.osAppId = osAppIdVec;
+    trafficDescriptor.osAppId = osAppId;
+
+    DataProfileInfo dataProfileInfo;
+    memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+    dataProfileInfo.profileId = DataProfileInfo::ID_DEFAULT;
+    dataProfileInfo.apn = std::string("internet");
+    dataProfileInfo.protocol = PdpProtocolType::IP;
+    dataProfileInfo.roamingProtocol = PdpProtocolType::IP;
+    dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+    dataProfileInfo.user = std::string("username");
+    dataProfileInfo.password = std::string("password");
+    dataProfileInfo.type = DataProfileInfo::TYPE_THREE_GPP;
+    dataProfileInfo.maxConnsTime = 300;
+    dataProfileInfo.maxConns = 20;
+    dataProfileInfo.waitTime = 0;
+    dataProfileInfo.enabled = true;
+    dataProfileInfo.supportedApnTypesBitmap =
+            static_cast<int32_t>(ApnTypes::IMS) | static_cast<int32_t>(ApnTypes::IA);
+    dataProfileInfo.bearerBitmap = static_cast<int32_t>(RadioAccessFamily::GPRS) |
+                                   static_cast<int32_t>(RadioAccessFamily::EDGE) |
+                                   static_cast<int32_t>(RadioAccessFamily::UMTS) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSDPA) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSUPA) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSPA) |
+                                   static_cast<int32_t>(RadioAccessFamily::EHRPD) |
+                                   static_cast<int32_t>(RadioAccessFamily::LTE) |
+                                   static_cast<int32_t>(RadioAccessFamily::HSPAP) |
+                                   static_cast<int32_t>(RadioAccessFamily::IWLAN);
+    dataProfileInfo.mtuV4 = 0;
+    dataProfileInfo.mtuV6 = 0;
+    dataProfileInfo.preferred = true;
+    dataProfileInfo.persistent = false;
+    dataProfileInfo.trafficDescriptor = trafficDescriptor;
+
+    bool roamingAllowed = false;
+
+    std::vector<LinkAddress> addresses = {};
+    std::vector<std::string> dnses = {};
+
+    DataRequestReason reason = DataRequestReason::NORMAL;
+    SliceInfo sliceInfo;
+    bool matchAllRuleAllowed = true;
+
+    ndk::ScopedAStatus res =
+            radio_data->setupDataCall(serial, accessNetwork, dataProfileInfo, roamingAllowed,
+                                      reason, addresses, dnses, -1, sliceInfo, matchAllRuleAllowed);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_data->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_data->rspInfo.serial);
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+    } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+        if (radioRsp_data->setupDataCallResult.trafficDescriptors.size() <= 0) {
+            return;
+        }
+        EXPECT_EQ(trafficDescriptor.osAppId.value().osAppId,
+                  radioRsp_data->setupDataCallResult.trafficDescriptors[0].osAppId.value().osAppId);
+    }
+}
+
+/*
+ * Test IRadioData.getSlicingConfig() for the response returned.
+ */
+TEST_P(RadioDataTest, getSlicingConfig) {
+    serial = GetRandomSerialNumber();
+    radio_data->getSlicingConfig(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_data->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_data->rspInfo.serial);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::INTERNAL_ERR, RadioError::MODEM_ERR}));
+    }
+}
+
+/*
+ * Test IRadioData.setDataThrottling() for the response returned.
+ */
+TEST_P(RadioDataTest, setDataThrottling) {
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = radio_data->setDataThrottling(
+            serial, DataThrottlingAction::THROTTLE_SECONDARY_CARRIER, 60000);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_data->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_data->rspInfo.serial);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR,
+                                      RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+    }
+
+    sleep(1);
+    serial = GetRandomSerialNumber();
+
+    res = radio_data->setDataThrottling(serial, DataThrottlingAction::THROTTLE_ANCHOR_CARRIER,
+                                        60000);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_data->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_data->rspInfo.serial);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR,
+                                      RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+    }
+
+    sleep(1);
+    serial = GetRandomSerialNumber();
+
+    res = radio_data->setDataThrottling(serial, DataThrottlingAction::HOLD, 60000);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_data->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_data->rspInfo.serial);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR,
+                                      RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+    }
+
+    sleep(1);
+    serial = GetRandomSerialNumber();
+
+    res = radio_data->setDataThrottling(serial, DataThrottlingAction::NO_DATA_THROTTLING, 60000);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_data->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_data->rspInfo.serial);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
+                                     {RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR,
+                                      RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+    }
+
+    sleep(1);
+}
diff --git a/radio/aidl/vts/radio_data_utils.h b/radio/aidl/vts/radio_data_utils.h
new file mode 100644
index 0000000..fb91ef6
--- /dev/null
+++ b/radio/aidl/vts/radio_data_utils.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/data/BnRadioDataIndication.h>
+#include <aidl/android/hardware/radio/data/BnRadioDataResponse.h>
+#include <aidl/android/hardware/radio/data/IRadioData.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::data;
+
+class RadioDataTest;
+
+/* Callback class for radio data response */
+class RadioDataResponse : public BnRadioDataResponse {
+  protected:
+    RadioServiceTest& parent_data;
+
+  public:
+    RadioDataResponse(RadioServiceTest& parent_data);
+    virtual ~RadioDataResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    int32_t allocatedPduSessionId;
+    SetupDataCallResult setupDataCallResult;
+
+    virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
+
+    virtual ndk::ScopedAStatus allocatePduSessionIdResponse(const RadioResponseInfo& info,
+                                                            int32_t id) override;
+
+    virtual ndk::ScopedAStatus cancelHandoverResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus deactivateDataCallResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getDataCallListResponse(
+            const RadioResponseInfo& info,
+            const std::vector<SetupDataCallResult>& dcResponse) override;
+
+    virtual ndk::ScopedAStatus getSlicingConfigResponse(
+            const RadioResponseInfo& info, const SlicingConfig& slicingConfig) override;
+
+    virtual ndk::ScopedAStatus releasePduSessionIdResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setDataAllowedResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setDataProfileResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setDataThrottlingResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setInitialAttachApnResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setupDataCallResponse(
+            const RadioResponseInfo& info, const SetupDataCallResult& dcResponse) override;
+
+    virtual ndk::ScopedAStatus startHandoverResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus startKeepaliveResponse(const RadioResponseInfo& info,
+                                                      const KeepaliveStatus& status) override;
+
+    virtual ndk::ScopedAStatus stopKeepaliveResponse(const RadioResponseInfo& info) override;
+};
+
+/* Callback class for radio data indication */
+class RadioDataIndication : public BnRadioDataIndication {
+  protected:
+    RadioServiceTest& parent_data;
+
+  public:
+    RadioDataIndication(RadioServiceTest& parent_data);
+    virtual ~RadioDataIndication() = default;
+
+    virtual ndk::ScopedAStatus dataCallListChanged(
+            RadioIndicationType type, const std::vector<SetupDataCallResult>& dcList) override;
+
+    virtual ndk::ScopedAStatus keepaliveStatus(RadioIndicationType type,
+                                               const KeepaliveStatus& status) override;
+
+    virtual ndk::ScopedAStatus pcoData(RadioIndicationType type, const PcoDataInfo& pco) override;
+
+    virtual ndk::ScopedAStatus unthrottleApn(RadioIndicationType type,
+                                             const DataProfileInfo& dataProfile) override;
+    virtual ndk::ScopedAStatus slicingConfigChanged(RadioIndicationType type,
+                                                    const SlicingConfig& slicingConfig) override;
+};
+
+// The main test class for Radio AIDL Data.
+class RadioDataTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  protected:
+    /* Get current data call list */
+    ndk::ScopedAStatus getDataCallList();
+
+  public:
+    virtual void SetUp() override;
+
+    /* radio data service handle */
+    std::shared_ptr<IRadioData> radio_data;
+    /* radio data response handle */
+    std::shared_ptr<RadioDataResponse> radioRsp_data;
+    /* radio data indication handle */
+    std::shared_ptr<RadioDataIndication> radioInd_data;
+};
diff --git a/radio/aidl/vts/radio_messaging_indication.cpp b/radio/aidl/vts/radio_messaging_indication.cpp
new file mode 100644
index 0000000..c69611f
--- /dev/null
+++ b/radio/aidl/vts/radio_messaging_indication.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_messaging_utils.h"
+
+RadioMessagingIndication::RadioMessagingIndication(RadioServiceTest& parent)
+    : parent_messaging(parent) {}
+
+ndk::ScopedAStatus RadioMessagingIndication::cdmaNewSms(RadioIndicationType /*type*/,
+                                                        const CdmaSmsMessage& /*msg*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingIndication::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingIndication::newBroadcastSms(RadioIndicationType /*type*/,
+                                                             const std::vector<uint8_t>& /*data*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingIndication::newSms(RadioIndicationType /*type*/,
+                                                    const std::vector<uint8_t>& /*pdu*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingIndication::newSmsOnSim(RadioIndicationType /*type*/,
+                                                         int32_t /*recordNumber*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingIndication::newSmsStatusReport(
+        RadioIndicationType /*type*/, const std::vector<uint8_t>& /*pdu*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingIndication::onUssd(RadioIndicationType /*type*/,
+                                                    UssdModeType /*modeType*/,
+                                                    const std::string& /*msg*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingIndication::simSmsStorageFull(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_messaging_response.cpp b/radio/aidl/vts/radio_messaging_response.cpp
new file mode 100644
index 0000000..718df7e
--- /dev/null
+++ b/radio/aidl/vts/radio_messaging_response.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_messaging_utils.h"
+
+RadioMessagingResponse::RadioMessagingResponse(RadioServiceTest& parent)
+    : parent_messaging(parent) {}
+
+ndk::ScopedAStatus RadioMessagingResponse::acknowledgeIncomingGsmSmsWithPduResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::acknowledgeLastIncomingCdmaSmsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::acknowledgeLastIncomingGsmSmsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::acknowledgeRequest(int32_t /*serial*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::cancelPendingUssdResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::deleteSmsOnRuimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::deleteSmsOnSimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::getCdmaBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const std::vector<CdmaBroadcastSmsConfigInfo>& /*configs*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::getGsmBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const std::vector<GsmBroadcastSmsConfigInfo>& /*configs*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::getSmscAddressResponse(const RadioResponseInfo& /*info*/,
+                                                                  const std::string& /*smsc*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::reportSmsMemoryStatusResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::sendCdmaSmsExpectMoreResponse(
+        const RadioResponseInfo& info, const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_messaging.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::sendCdmaSmsResponse(const RadioResponseInfo& info,
+                                                               const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_messaging.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::sendImsSmsResponse(const RadioResponseInfo& /*info*/,
+                                                              const SendSmsResult& /*sms*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::sendSmsExpectMoreResponse(const RadioResponseInfo& info,
+                                                                     const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_messaging.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::sendSmsResponse(const RadioResponseInfo& info,
+                                                           const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_messaging.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::sendUssdResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::setCdmaBroadcastActivationResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::setCdmaBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::setGsmBroadcastActivationResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::setGsmBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::setSmscAddressResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/,
+                                                                  int32_t /*index*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioMessagingResponse::writeSmsToSimResponse(const RadioResponseInfo& /*info*/,
+                                                                 int32_t /*index*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_messaging_test.cpp b/radio/aidl/vts/radio_messaging_test.cpp
new file mode 100644
index 0000000..8abd91d
--- /dev/null
+++ b/radio/aidl/vts/radio_messaging_test.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_messaging_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioMessagingTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_messaging = IRadioMessaging::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_messaging.get());
+
+    radioRsp_messaging = ndk::SharedRefBase::make<RadioMessagingResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_messaging.get());
+
+    count_ = 0;
+
+    radioInd_messaging = ndk::SharedRefBase::make<RadioMessagingIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_messaging.get());
+
+    radio_messaging->setResponseFunctions(radioRsp_messaging, radioInd_messaging);
+
+    // Assert IRadioSim exists and SIM is present before testing
+    radio_sim = sim::IRadioSim::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.sim.IRadioSim/slot1")));
+    ASSERT_NE(nullptr, radio_sim.get());
+    updateSimCardStatus();
+    EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+
+    // Assert IRadioConfig exists before testing
+    radio_config = config::IRadioConfig::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.config.IRadioConfig/default")));
+    ASSERT_NE(nullptr, radio_config.get());
+}
+
+/*
+ * Test IRadioMessaging.sendSms() for the response returned.
+ */
+TEST_P(RadioMessagingTest, sendSms) {
+    LOG(DEBUG) << "sendSms";
+    serial = GetRandomSerialNumber();
+    GsmSmsMessage msg;
+    msg.smscPdu = "";
+    msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
+
+    radio_messaging->sendSms(serial, msg);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
+
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_messaging->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
+                CHECK_GENERAL_ERROR));
+        EXPECT_EQ(0, radioRsp_messaging->sendSmsResult.errorCode);
+    }
+    LOG(DEBUG) << "sendSms finished";
+}
+
+/*
+ * Test IRadioMessaging.sendSmsExpectMore() for the response returned.
+ */
+TEST_P(RadioMessagingTest, sendSmsExpectMore) {
+    LOG(DEBUG) << "sendSmsExpectMore";
+    serial = GetRandomSerialNumber();
+    GsmSmsMessage msg;
+    msg.smscPdu = "";
+    msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
+
+    radio_messaging->sendSmsExpectMore(serial, msg);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
+
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_messaging->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
+                CHECK_GENERAL_ERROR));
+    }
+    LOG(DEBUG) << "sendSmsExpectMore finished";
+}
+
+/*
+ * Test IRadioMessaging.sendCdmaSms() for the response returned.
+ */
+TEST_P(RadioMessagingTest, sendCdmaSms) {
+    LOG(DEBUG) << "sendCdmaSms";
+    serial = GetRandomSerialNumber();
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsAddress::DIGIT_MODE_FOUR_BIT;
+    cdmaSmsAddress.isNumberModeDataNetwork = false;
+    cdmaSmsAddress.numberType = CdmaSmsAddress::NUMBER_TYPE_UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsAddress::NUMBER_PLAN_UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddress::SUBADDRESS_TYPE_NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
+
+    // Create a CdmaSmsMessage
+    CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData =
+            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    radio_messaging->sendCdmaSms(serial, cdmaSmsMessage);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
+
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_messaging->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
+                CHECK_GENERAL_ERROR));
+    }
+    LOG(DEBUG) << "sendCdmaSms finished";
+}
+
+/*
+ * Test IRadioMessaging.sendCdmaSmsExpectMore() for the response returned.
+ */
+TEST_P(RadioMessagingTest, sendCdmaSmsExpectMore) {
+    serial = GetRandomSerialNumber();
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsAddress::DIGIT_MODE_FOUR_BIT;
+    cdmaSmsAddress.isNumberModeDataNetwork = false;
+    cdmaSmsAddress.numberType = CdmaSmsAddress::NUMBER_TYPE_UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsAddress::NUMBER_PLAN_UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddress::SUBADDRESS_TYPE_NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
+
+    // Create a CdmaSmsMessage
+    CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData =
+            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    radio_messaging->sendCdmaSmsExpectMore(serial, cdmaSmsMessage);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_messaging->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_messaging->rspInfo.serial);
+
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_messaging->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
+                CHECK_GENERAL_ERROR));
+    }
+}
diff --git a/radio/aidl/vts/radio_messaging_utils.h b/radio/aidl/vts/radio_messaging_utils.h
new file mode 100644
index 0000000..7bb99cd
--- /dev/null
+++ b/radio/aidl/vts/radio_messaging_utils.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/messaging/BnRadioMessagingIndication.h>
+#include <aidl/android/hardware/radio/messaging/BnRadioMessagingResponse.h>
+#include <aidl/android/hardware/radio/messaging/IRadioMessaging.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::messaging;
+
+class RadioMessagingTest;
+
+/* Callback class for radio messaging response */
+class RadioMessagingResponse : public BnRadioMessagingResponse {
+  protected:
+    RadioServiceTest& parent_messaging;
+
+  public:
+    RadioMessagingResponse(RadioServiceTest& parent_messaging);
+    virtual ~RadioMessagingResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    SendSmsResult sendSmsResult;
+
+    virtual ndk::ScopedAStatus acknowledgeIncomingGsmSmsWithPduResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus acknowledgeLastIncomingCdmaSmsResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus acknowledgeLastIncomingGsmSmsResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
+
+    virtual ndk::ScopedAStatus cancelPendingUssdResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus deleteSmsOnRuimResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus deleteSmsOnSimResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getCdmaBroadcastConfigResponse(
+            const RadioResponseInfo& info,
+            const std::vector<CdmaBroadcastSmsConfigInfo>& configs) override;
+
+    virtual ndk::ScopedAStatus getGsmBroadcastConfigResponse(
+            const RadioResponseInfo& info,
+            const std::vector<GsmBroadcastSmsConfigInfo>& configs) override;
+
+    virtual ndk::ScopedAStatus getSmscAddressResponse(const RadioResponseInfo& info,
+                                                      const std::string& smsc) override;
+
+    virtual ndk::ScopedAStatus reportSmsMemoryStatusResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
+                                                             const SendSmsResult& sms) override;
+
+    virtual ndk::ScopedAStatus sendCdmaSmsResponse(const RadioResponseInfo& info,
+                                                   const SendSmsResult& sms) override;
+
+    virtual ndk::ScopedAStatus sendImsSmsResponse(const RadioResponseInfo& info,
+                                                  const SendSmsResult& sms) override;
+
+    virtual ndk::ScopedAStatus sendSmsExpectMoreResponse(const RadioResponseInfo& info,
+                                                         const SendSmsResult& sms) override;
+
+    virtual ndk::ScopedAStatus sendSmsResponse(const RadioResponseInfo& info,
+                                               const SendSmsResult& sms) override;
+
+    virtual ndk::ScopedAStatus sendUssdResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCdmaBroadcastActivationResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCdmaBroadcastConfigResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setGsmBroadcastActivationResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setGsmBroadcastConfigResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setSmscAddressResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus writeSmsToRuimResponse(const RadioResponseInfo& info,
+                                                      int32_t index) override;
+
+    virtual ndk::ScopedAStatus writeSmsToSimResponse(const RadioResponseInfo& info,
+                                                     int32_t index) override;
+};
+
+/* Callback class for radio messaging indication */
+class RadioMessagingIndication : public BnRadioMessagingIndication {
+  protected:
+    RadioServiceTest& parent_messaging;
+
+  public:
+    RadioMessagingIndication(RadioServiceTest& parent_messaging);
+    virtual ~RadioMessagingIndication() = default;
+
+    virtual ndk::ScopedAStatus cdmaNewSms(RadioIndicationType type,
+                                          const CdmaSmsMessage& msg) override;
+
+    virtual ndk::ScopedAStatus cdmaRuimSmsStorageFull(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus newBroadcastSms(RadioIndicationType type,
+                                               const std::vector<uint8_t>& data) override;
+
+    virtual ndk::ScopedAStatus newSms(RadioIndicationType type,
+                                      const std::vector<uint8_t>& pdu) override;
+
+    virtual ndk::ScopedAStatus newSmsOnSim(RadioIndicationType type, int32_t recordNumber) override;
+
+    virtual ndk::ScopedAStatus newSmsStatusReport(RadioIndicationType type,
+                                                  const std::vector<uint8_t>& pdu) override;
+
+    virtual ndk::ScopedAStatus onUssd(RadioIndicationType type, UssdModeType modeType,
+                                      const std::string& msg) override;
+
+    virtual ndk::ScopedAStatus simSmsStorageFull(RadioIndicationType type) override;
+};
+
+// The main test class for Radio AIDL Messaging.
+class RadioMessagingTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  public:
+    virtual void SetUp() override;
+
+    /* radio messaging service handle */
+    std::shared_ptr<IRadioMessaging> radio_messaging;
+    /* radio messaging response handle */
+    std::shared_ptr<RadioMessagingResponse> radioRsp_messaging;
+    /* radio messaging indication handle */
+    std::shared_ptr<RadioMessagingIndication> radioInd_messaging;
+};
diff --git a/radio/aidl/vts/radio_modem_indication.cpp b/radio/aidl/vts/radio_modem_indication.cpp
new file mode 100644
index 0000000..0bfcd66
--- /dev/null
+++ b/radio/aidl/vts/radio_modem_indication.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_modem_utils.h"
+
+RadioModemIndication::RadioModemIndication(RadioServiceTest& parent) : parent_modem(parent) {}
+
+ndk::ScopedAStatus RadioModemIndication::hardwareConfigChanged(
+        RadioIndicationType /*type*/, const std::vector<HardwareConfig>& /*configs*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemIndication::modemReset(RadioIndicationType /*type*/,
+                                                    const std::string& /*reason*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemIndication::radioCapabilityIndication(RadioIndicationType /*type*/,
+                                                                   const RadioCapability& /*rc*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemIndication::radioStateChanged(RadioIndicationType /*type*/,
+                                                           RadioState /*radioState*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemIndication::rilConnected(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_modem_response.cpp b/radio/aidl/vts/radio_modem_response.cpp
new file mode 100644
index 0000000..53bfab4
--- /dev/null
+++ b/radio/aidl/vts/radio_modem_response.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_modem_utils.h"
+
+RadioModemResponse::RadioModemResponse(RadioServiceTest& parent) : parent_modem(parent) {}
+
+ndk::ScopedAStatus RadioModemResponse::acknowledgeRequest(int32_t /*serial*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::enableModemResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::getBasebandVersionResponse(const RadioResponseInfo& /*info*/,
+                                                                  const std::string& /*version*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::getDeviceIdentityResponse(const RadioResponseInfo& /*info*/,
+                                                                 const std::string& /*imei*/,
+                                                                 const std::string& /*imeisv*/,
+                                                                 const std::string& /*esn*/,
+                                                                 const std::string& /*meid*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::getHardwareConfigResponse(
+        const RadioResponseInfo& /*info*/, const std::vector<HardwareConfig>& /*config*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::getModemActivityInfoResponse(
+        const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::getModemStackStatusResponse(
+        const RadioResponseInfo& /*info*/, const bool /*enabled*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::getRadioCapabilityResponse(const RadioResponseInfo& /*info*/,
+                                                                  const RadioCapability& /*rc*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::nvReadItemResponse(const RadioResponseInfo& /*info*/,
+                                                          const std::string& /*result*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::nvResetConfigResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::nvWriteItemResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::requestShutdownResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::setRadioCapabilityResponse(const RadioResponseInfo& /*info*/,
+                                                                  const RadioCapability& /*rc*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioModemResponse::setRadioPowerResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_modem.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_modem_test.cpp b/radio/aidl/vts/radio_modem_test.cpp
new file mode 100644
index 0000000..b40bb7b
--- /dev/null
+++ b/radio/aidl/vts/radio_modem_test.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_modem_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioModemTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_modem = IRadioModem::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_modem.get());
+
+    radioRsp_modem = ndk::SharedRefBase::make<RadioModemResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_modem.get());
+
+    count_ = 0;
+
+    radioInd_modem = ndk::SharedRefBase::make<RadioModemIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_modem.get());
+
+    radio_modem->setResponseFunctions(radioRsp_modem, radioInd_modem);
+
+    // Assert IRadioSim exists and SIM is present before testing
+    radio_sim = sim::IRadioSim::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.sim.IRadioSim/slot1")));
+    ASSERT_NE(nullptr, radio_sim.get());
+    updateSimCardStatus();
+    EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+
+    // Assert IRadioConfig exists before testing
+    radio_config = config::IRadioConfig::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.config.IRadioConfig/default")));
+    ASSERT_NE(nullptr, radio_config.get());
+}
+
+/*
+ * Test IRadioModem.setRadioPower() for the response returned.
+ */
+TEST_P(RadioModemTest, setRadioPower_emergencyCall_cancelled) {
+    // Set radio power to off.
+    serial = GetRandomSerialNumber();
+    radio_modem->setRadioPower(serial, false, false, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_modem->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_modem->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_modem->rspInfo.error);
+
+    // Set radio power to on with forEmergencyCall being true. This should put modem to only scan
+    // emergency call bands.
+    serial = GetRandomSerialNumber();
+    radio_modem->setRadioPower(serial, true, true, true);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_modem->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_modem->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_modem->rspInfo.error);
+
+    // Set radio power to on with forEmergencyCall being false. This should put modem in regular
+    // operation modem.
+    serial = GetRandomSerialNumber();
+    radio_modem->setRadioPower(serial, true, false, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_modem->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_modem->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_modem->rspInfo.error);
+}
diff --git a/radio/aidl/vts/radio_modem_utils.h b/radio/aidl/vts/radio_modem_utils.h
new file mode 100644
index 0000000..8779e0c
--- /dev/null
+++ b/radio/aidl/vts/radio_modem_utils.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/modem/BnRadioModemIndication.h>
+#include <aidl/android/hardware/radio/modem/BnRadioModemResponse.h>
+#include <aidl/android/hardware/radio/modem/IRadioModem.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::modem;
+
+class RadioModemTest;
+
+/* Callback class for radio modem response */
+class RadioModemResponse : public BnRadioModemResponse {
+  protected:
+    RadioServiceTest& parent_modem;
+
+  public:
+    RadioModemResponse(RadioServiceTest& parent_modem);
+    virtual ~RadioModemResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    bool isModemEnabled;
+    bool enableModemResponseToggle;
+
+    virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
+
+    virtual ndk::ScopedAStatus enableModemResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getBasebandVersionResponse(const RadioResponseInfo& info,
+                                                          const std::string& version) override;
+
+    virtual ndk::ScopedAStatus getDeviceIdentityResponse(const RadioResponseInfo& info,
+                                                         const std::string& imei,
+                                                         const std::string& imeisv,
+                                                         const std::string& esn,
+                                                         const std::string& meid) override;
+
+    virtual ndk::ScopedAStatus getHardwareConfigResponse(
+            const RadioResponseInfo& info, const std::vector<HardwareConfig>& config) override;
+
+    virtual ndk::ScopedAStatus getModemActivityInfoResponse(
+            const RadioResponseInfo& info, const ActivityStatsInfo& activityInfo) override;
+
+    virtual ndk::ScopedAStatus getModemStackStatusResponse(const RadioResponseInfo& info,
+                                                           const bool enabled) override;
+
+    virtual ndk::ScopedAStatus getRadioCapabilityResponse(const RadioResponseInfo& info,
+                                                          const RadioCapability& rc) override;
+
+    virtual ndk::ScopedAStatus nvReadItemResponse(const RadioResponseInfo& info,
+                                                  const std::string& result) override;
+
+    virtual ndk::ScopedAStatus nvResetConfigResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus nvWriteCdmaPrlResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus nvWriteItemResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus requestShutdownResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus sendDeviceStateResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setRadioCapabilityResponse(const RadioResponseInfo& info,
+                                                          const RadioCapability& rc) override;
+
+    virtual ndk::ScopedAStatus setRadioPowerResponse(const RadioResponseInfo& info) override;
+};
+
+/* Callback class for radio modem indication */
+class RadioModemIndication : public BnRadioModemIndication {
+  protected:
+    RadioServiceTest& parent_modem;
+
+  public:
+    RadioModemIndication(RadioServiceTest& parent_modem);
+    virtual ~RadioModemIndication() = default;
+
+    virtual ndk::ScopedAStatus hardwareConfigChanged(
+            RadioIndicationType type, const std::vector<HardwareConfig>& configs) override;
+
+    virtual ndk::ScopedAStatus modemReset(RadioIndicationType type,
+                                          const std::string& reason) override;
+
+    virtual ndk::ScopedAStatus radioCapabilityIndication(RadioIndicationType type,
+                                                         const RadioCapability& rc) override;
+
+    virtual ndk::ScopedAStatus radioStateChanged(RadioIndicationType type,
+                                                 RadioState radioState) override;
+
+    virtual ndk::ScopedAStatus rilConnected(RadioIndicationType type) override;
+};
+
+// The main test class for Radio AIDL Modem.
+class RadioModemTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  public:
+    virtual void SetUp() override;
+
+    /* radio modem service handle */
+    std::shared_ptr<IRadioModem> radio_modem;
+    /* radio modem response handle */
+    std::shared_ptr<RadioModemResponse> radioRsp_modem;
+    /* radio modem indication handle */
+    std::shared_ptr<RadioModemIndication> radioInd_modem;
+};
diff --git a/radio/aidl/vts/radio_network_indication.cpp b/radio/aidl/vts/radio_network_indication.cpp
new file mode 100644
index 0000000..7acbff4
--- /dev/null
+++ b/radio/aidl/vts/radio_network_indication.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_network_utils.h"
+
+RadioNetworkIndication::RadioNetworkIndication(RadioServiceTest& parent) : parent_network(parent) {}
+
+ndk::ScopedAStatus RadioNetworkIndication::barringInfoChanged(
+        RadioIndicationType /*type*/, const CellIdentity& /*cellIdentity*/,
+        const std::vector<BarringInfo>& /*barringInfos*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::cdmaPrlChanged(RadioIndicationType /*type*/,
+                                                          int32_t /*version*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::cellInfoList(RadioIndicationType /*type*/,
+                                                        const std::vector<CellInfo>& /*records*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::currentLinkCapacityEstimate(
+        RadioIndicationType /*type*/, const LinkCapacityEstimate& /*lce*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::currentPhysicalChannelConfigs(
+        RadioIndicationType /*type*/, const std::vector<PhysicalChannelConfig>& /*configs*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::currentSignalStrength(
+        RadioIndicationType /*type*/, const SignalStrength& /*signalStrength*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::imsNetworkStateChanged(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::networkScanResult(RadioIndicationType /*type*/,
+                                                             const NetworkScanResult& /*result*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::networkStateChanged(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::nitzTimeReceived(RadioIndicationType /*type*/,
+                                                            const std::string& /*nitzTime*/,
+                                                            int64_t /*receivedTime*/,
+                                                            int64_t /*age*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::registrationFailed(RadioIndicationType /*type*/,
+                                                              const CellIdentity& /*cellIdentity*/,
+                                                              const std::string& /*chosenPlmn*/,
+                                                              int32_t /*domain*/,
+                                                              int32_t /*causeCode*/,
+                                                              int32_t /*additionalCauseCode*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::restrictedStateChanged(RadioIndicationType /*type*/,
+                                                                  PhoneRestrictedState /*state*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::suppSvcNotify(RadioIndicationType /*type*/,
+                                                         const SuppSvcNotification& /*suppSvc*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::voiceRadioTechChanged(RadioIndicationType /*type*/,
+                                                                 RadioTechnology /*rat*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
new file mode 100644
index 0000000..ccae0f3
--- /dev/null
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_network_utils.h"
+
+RadioNetworkResponse::RadioNetworkResponse(RadioServiceTest& parent) : parent_network(parent) {}
+
+ndk::ScopedAStatus RadioNetworkResponse::acknowledgeRequest(int32_t /*serial*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getAllowedNetworkTypesBitmapResponse(
+        const RadioResponseInfo& info, const int32_t networkTypeBitmap) {
+    rspInfo = info;
+    networkTypeBitmapResponse = networkTypeBitmap;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getAvailableBandModesResponse(
+        const RadioResponseInfo& /*info*/, const std::vector<RadioBandMode>& /*bandModes*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getAvailableNetworksResponse(
+        const RadioResponseInfo& info, const std::vector<OperatorInfo>& operatorInfos) {
+    rspInfo = info;
+    networkInfos = operatorInfos;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getBarringInfoResponse(
+        const RadioResponseInfo& /*info*/, const CellIdentity& /*cellIdentity*/,
+        const std::vector<BarringInfo>& /*barringInfos*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getCdmaRoamingPreferenceResponse(
+        const RadioResponseInfo& /*info*/, CdmaRoamingType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getCellInfoListResponse(
+        const RadioResponseInfo& /*info*/, const std::vector<CellInfo>& /*cellInfo*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getDataRegistrationStateResponse(
+        const RadioResponseInfo& info, const RegStateResult& /*regResponse*/) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getImsRegistrationStateResponse(
+        const RadioResponseInfo& /*info*/, bool /*isRegistered*/,
+        RadioTechnologyFamily /*ratFamily*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getNetworkSelectionModeResponse(
+        const RadioResponseInfo& /*info*/, bool /*manual*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getOperatorResponse(const RadioResponseInfo& /*info*/,
+                                                             const std::string& /*longName*/,
+                                                             const std::string& /*shortName*/,
+                                                             const std::string& /*numeric*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getSignalStrengthResponse(
+        const RadioResponseInfo& /*info*/, const SignalStrength& /*sig_strength*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getSystemSelectionChannelsResponse(
+        const RadioResponseInfo& info, const std::vector<RadioAccessSpecifier>& /*specifier*/) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getUsageSettingResponse(const RadioResponseInfo& info,
+                                                                 const UsageSetting usageSetting) {
+    rspInfo = info;
+    this->usageSetting = usageSetting;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getVoiceRadioTechnologyResponse(
+        const RadioResponseInfo& /*info*/, RadioTechnology /*rat*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getVoiceRegistrationStateResponse(
+        const RadioResponseInfo& info, const RegStateResult& regResponse) {
+    rspInfo = info;
+    voiceRegResp.regState = regResponse.regState;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::isNrDualConnectivityEnabledResponse(
+        const RadioResponseInfo& info, bool isEnabled) {
+    rspInfo = info;
+    isNrDualConnectivityEnabled = isEnabled;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setAllowedNetworkTypesBitmapResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setBandModeResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setBarringPasswordResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setCdmaRoamingPreferenceResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setCellInfoListRateResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setIndicationFilterResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setLinkCapacityReportingCriteriaResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setLocationUpdatesResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setNetworkSelectionModeAutomaticResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setNetworkSelectionModeManualResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setNrDualConnectivityStateResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setSignalStrengthReportingCriteriaResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setSuppServiceNotificationsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setSystemSelectionChannelsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setUsageSettingResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::startNetworkScanResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::stopNetworkScanResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::supplyNetworkDepersonalizationResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
new file mode 100644
index 0000000..93c4c35
--- /dev/null
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/radio/RadioAccessFamily.h>
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_network_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioNetworkTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_network = IRadioNetwork::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_network.get());
+
+    radioRsp_network = ndk::SharedRefBase::make<RadioNetworkResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_network.get());
+
+    count_ = 0;
+
+    radioInd_network = ndk::SharedRefBase::make<RadioNetworkIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_network.get());
+
+    radio_network->setResponseFunctions(radioRsp_network, radioInd_network);
+
+    // Assert IRadioSim exists and SIM is present before testing
+    radio_sim = sim::IRadioSim::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.sim.IRadioSim/slot1")));
+    ASSERT_NE(nullptr, radio_sim.get());
+    updateSimCardStatus();
+    EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+
+    // Assert IRadioConfig exists before testing
+    radio_config = config::IRadioConfig::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.config.IRadioConfig/default")));
+    ASSERT_NE(nullptr, radio_config.get());
+}
+
+/*
+ * Test IRadioNetwork.setAllowedNetworkTypesBitmap for the response returned.
+ */
+TEST_P(RadioNetworkTest, setAllowedNetworkTypesBitmap) {
+    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);
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::OPERATION_NOT_ALLOWED,
+             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
+        serial = GetRandomSerialNumber();
+        radio_network->getAllowedNetworkTypesBitmap(serial);
+
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+                 RadioError::OPERATION_NOT_ALLOWED, RadioError::MODE_NOT_SUPPORTED,
+                 RadioError::INVALID_ARGUMENTS, RadioError::MODEM_ERR,
+                 RadioError::REQUEST_NOT_SUPPORTED, RadioError::NO_RESOURCES}));
+    }
+}
+
+/*
+ * Test IRadioNetwork.setNrDualConnectivityState() for the response returned.
+ */
+TEST_P(RadioNetworkTest, setNrDualConnectivityState) {
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res =
+            radio_network->setNrDualConnectivityState(serial, NrDualConnectivityState::DISABLE);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+                 RadioError::INVALID_STATE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    }
+}
+
+/*
+ * Test IRadioNetwork.isNrDualConnectivityEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, isNrDualConnectivityEnabled) {
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = radio_network->isNrDualConnectivityEnabled(serial);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR, RadioError::NONE}));
+    }
+}
+
+void RadioNetworkTest::invokeAndExpectResponse(
+        std::function<ndk::ScopedAStatus(int32_t serial)> request,
+        std::vector<RadioError> errors_to_check) {
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = request(serial);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, errors_to_check));
+}
+
+/*
+ * Test IRadioNetwork.getUsageSetting()
+ *
+ * Verify that the usage setting can be retrieved.
+ */
+TEST_P(RadioNetworkTest, getUsageSetting) {
+    invokeAndExpectResponse([&](int serial) { return radio_network->getUsageSetting(serial); },
+                            {RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_STATE,
+                             RadioError::SIM_ABSENT, RadioError::INTERNAL_ERR, RadioError::NONE});
+
+    ASSERT_TRUE(radioRsp_network->usageSetting == UsageSetting::VOICE_CENTRIC ||
+                radioRsp_network->usageSetting == UsageSetting::DATA_CENTRIC);
+}
+
+void RadioNetworkTest::testSetUsageSetting_InvalidValues(std::vector<RadioError> errors) {
+    invokeAndExpectResponse(
+            [&](int serial) {
+                return radio_network->setUsageSetting(serial,
+                                                      UsageSetting(0) /*below valid range*/);
+            },
+            errors);
+    invokeAndExpectResponse(
+            [&](int serial) {
+                return radio_network->setUsageSetting(serial, UsageSetting(-1) /*negative*/);
+            },
+            errors);
+    invokeAndExpectResponse(
+            [&](int serial) {
+                return radio_network->setUsageSetting(serial,
+                                                      UsageSetting(3) /*above valid range*/);
+            },
+            errors);
+}
+
+/*
+ * Test IRadioNetwork.setUsageSetting() and IRadioNetwork.getUsageSetting()
+ *
+ * Verify the following:
+ * -That the usage setting can be retrieved.
+ * -That the usage setting can be successfully set to allowed values.
+ * -That the usage setting cannot be set to invalid values.
+ */
+TEST_P(RadioNetworkTest, setUsageSetting) {
+    invokeAndExpectResponse([&](int serial) { return radio_network->getUsageSetting(serial); },
+                            {RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_STATE,
+                             RadioError::SIM_ABSENT, RadioError::INTERNAL_ERR, RadioError::NONE});
+
+    if (radioRsp_network->rspInfo.error != RadioError::NONE) {
+        // Test only for invalid values, with the only allowable response being the same error
+        // that was previously provided, or an error indicating invalid arguments.
+        testSetUsageSetting_InvalidValues(
+                {radioRsp_network->rspInfo.error, RadioError::INVALID_ARGUMENTS});
+        // It is unsafe to proceed with setting valid values without knowing the starting value, but
+        // we expect errors anyway, so not necessary.
+        return;
+    } else {
+        // Because querying succeeded, the device is in a valid state to test for invalid values
+        // and the only thing that can change is that we expect to have an EINVAL return each time.
+        testSetUsageSetting_InvalidValues({RadioError::INVALID_ARGUMENTS});
+    }
+
+    // Store the original setting value to reset later.
+    const UsageSetting originalSetting = radioRsp_network->usageSetting;
+
+    // Choose the "other" value that is not the current value for test.
+    const UsageSetting testSetting = radioRsp_network->usageSetting == UsageSetting::VOICE_CENTRIC
+                                             ? UsageSetting::DATA_CENTRIC
+                                             : UsageSetting::VOICE_CENTRIC;
+
+    // Set an alternative setting; it may either succeed or be disallowed as out of range for
+    // the current device (if the device only supports its current mode).
+    invokeAndExpectResponse(
+            [&](int serial) { return radio_network->setUsageSetting(serial, testSetting); },
+            {RadioError::INVALID_ARGUMENTS, RadioError::NONE});
+
+    // If there was no error, then we expect the test setting to be set, or if there is an error
+    // we expect the original setting to be maintained.
+    const UsageSetting expectedSetting =
+            radioRsp_network->rspInfo.error == RadioError::NONE ? testSetting : originalSetting;
+    invokeAndExpectResponse([&](int serial) { return radio_network->getUsageSetting(serial); },
+                            {RadioError::NONE});
+
+    const UsageSetting updatedSetting = radioRsp_network->usageSetting;
+
+    // Re-set the original setting, which must always succeed.
+    invokeAndExpectResponse(
+            [&](int serial) { return radio_network->setUsageSetting(serial, originalSetting); },
+            {RadioError::NONE});
+
+    // Check that indeed the updated setting was set. We do this after resetting to original
+    // conditions to avoid early-exiting the test and leaving the device in a modified state.
+    ASSERT_TRUE(expectedSetting == updatedSetting);
+    // Check that indeed the original setting was reset.
+    ASSERT_TRUE(originalSetting == radioRsp_network->usageSetting);
+}
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
new file mode 100644
index 0000000..9f76769
--- /dev/null
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/network/BnRadioNetworkIndication.h>
+#include <aidl/android/hardware/radio/network/BnRadioNetworkResponse.h>
+#include <aidl/android/hardware/radio/network/IRadioNetwork.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::network;
+
+class RadioNetworkTest;
+
+/* Callback class for radio network response */
+class RadioNetworkResponse : public BnRadioNetworkResponse {
+  protected:
+    RadioServiceTest& parent_network;
+
+  public:
+    RadioNetworkResponse(RadioServiceTest& parent_network);
+    virtual ~RadioNetworkResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    std::vector<RadioBandMode> radioBandModes;
+    std::vector<OperatorInfo> networkInfos;
+    bool isNrDualConnectivityEnabled;
+    int networkTypeBitmapResponse;
+    RegStateResult voiceRegResp;
+    CellIdentity barringCellIdentity;
+    std::vector<BarringInfo> barringInfos;
+    UsageSetting usageSetting;
+
+    virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
+
+    virtual ndk::ScopedAStatus getAllowedNetworkTypesBitmapResponse(
+            const RadioResponseInfo& info, const int32_t networkTypeBitmap) override;
+
+    virtual ndk::ScopedAStatus getAvailableBandModesResponse(
+            const RadioResponseInfo& info, const std::vector<RadioBandMode>& bandModes) override;
+
+    virtual ndk::ScopedAStatus getAvailableNetworksResponse(
+            const RadioResponseInfo& info, const std::vector<OperatorInfo>& networkInfos) override;
+
+    virtual ndk::ScopedAStatus getBarringInfoResponse(
+            const RadioResponseInfo& info, const CellIdentity& cellIdentity,
+            const std::vector<BarringInfo>& barringInfos) override;
+
+    virtual ndk::ScopedAStatus getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info,
+                                                                CdmaRoamingType type) override;
+
+    virtual ndk::ScopedAStatus getCellInfoListResponse(
+            const RadioResponseInfo& info, const std::vector<CellInfo>& cellInfo) override;
+
+    virtual ndk::ScopedAStatus getDataRegistrationStateResponse(
+            const RadioResponseInfo& info, const RegStateResult& dataRegResponse) override;
+
+    virtual ndk::ScopedAStatus getImsRegistrationStateResponse(
+            const RadioResponseInfo& info, bool isRegistered,
+            RadioTechnologyFamily ratFamily) override;
+
+    virtual ndk::ScopedAStatus getNetworkSelectionModeResponse(const RadioResponseInfo& info,
+                                                               bool manual) override;
+
+    virtual ndk::ScopedAStatus getOperatorResponse(const RadioResponseInfo& info,
+                                                   const std::string& longName,
+                                                   const std::string& shortName,
+                                                   const std::string& numeric) override;
+
+    virtual ndk::ScopedAStatus getSignalStrengthResponse(
+            const RadioResponseInfo& info, const SignalStrength& sigStrength) override;
+
+    virtual ndk::ScopedAStatus getSystemSelectionChannelsResponse(
+            const RadioResponseInfo& info,
+            const std::vector<RadioAccessSpecifier>& specifier) override;
+
+    virtual ndk::ScopedAStatus getUsageSettingResponse(const RadioResponseInfo& info,
+                                                       UsageSetting usageSetting) override;
+
+    virtual ndk::ScopedAStatus getVoiceRadioTechnologyResponse(const RadioResponseInfo& info,
+                                                               RadioTechnology rat) override;
+
+    virtual ndk::ScopedAStatus getVoiceRegistrationStateResponse(
+            const RadioResponseInfo& info, const RegStateResult& voiceRegResponse) override;
+
+    virtual ndk::ScopedAStatus isNrDualConnectivityEnabledResponse(const RadioResponseInfo& info,
+                                                                   bool isEnabled) override;
+
+    virtual ndk::ScopedAStatus setAllowedNetworkTypesBitmapResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setBandModeResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setBarringPasswordResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCdmaRoamingPreferenceResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCellInfoListRateResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setIndicationFilterResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setLinkCapacityReportingCriteriaResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setLocationUpdatesResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setNetworkSelectionModeAutomaticResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setNetworkSelectionModeManualResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setNrDualConnectivityStateResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setSignalStrengthReportingCriteriaResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setSuppServiceNotificationsResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setSystemSelectionChannelsResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setUsageSettingResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus startNetworkScanResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus stopNetworkScanResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus supplyNetworkDepersonalizationResponse(
+            const RadioResponseInfo& info, int32_t remainingRetries) override;
+};
+
+/* Callback class for radio network indication */
+class RadioNetworkIndication : public BnRadioNetworkIndication {
+  protected:
+    RadioServiceTest& parent_network;
+
+  public:
+    RadioNetworkIndication(RadioServiceTest& parent_network);
+    virtual ~RadioNetworkIndication() = default;
+
+    virtual ndk::ScopedAStatus barringInfoChanged(
+            RadioIndicationType type, const CellIdentity& cellIdentity,
+            const std::vector<BarringInfo>& barringInfos) override;
+
+    virtual ndk::ScopedAStatus cdmaPrlChanged(RadioIndicationType type, int32_t version) override;
+
+    virtual ndk::ScopedAStatus cellInfoList(RadioIndicationType type,
+                                            const std::vector<CellInfo>& records) override;
+
+    virtual ndk::ScopedAStatus currentLinkCapacityEstimate(
+            RadioIndicationType type, const LinkCapacityEstimate& lce) override;
+
+    virtual ndk::ScopedAStatus currentPhysicalChannelConfigs(
+            RadioIndicationType type, const std::vector<PhysicalChannelConfig>& configs) override;
+
+    virtual ndk::ScopedAStatus currentSignalStrength(RadioIndicationType type,
+                                                     const SignalStrength& signalStrength) override;
+
+    virtual ndk::ScopedAStatus imsNetworkStateChanged(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus networkScanResult(RadioIndicationType type,
+                                                 const NetworkScanResult& result) override;
+
+    virtual ndk::ScopedAStatus networkStateChanged(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus nitzTimeReceived(RadioIndicationType type,
+                                                const std::string& nitzTime, int64_t receivedTimeMs,
+                                                int64_t ageMs) override;
+
+    virtual ndk::ScopedAStatus registrationFailed(RadioIndicationType type,
+                                                  const CellIdentity& cellIdentity,
+                                                  const std::string& chosenPlmn, int32_t domain,
+                                                  int32_t causeCode,
+                                                  int32_t additionalCauseCode) override;
+
+    virtual ndk::ScopedAStatus restrictedStateChanged(RadioIndicationType type,
+                                                      PhoneRestrictedState state) override;
+
+    virtual ndk::ScopedAStatus suppSvcNotify(RadioIndicationType type,
+                                             const SuppSvcNotification& suppSvc) override;
+
+    virtual ndk::ScopedAStatus voiceRadioTechChanged(RadioIndicationType type,
+                                                     RadioTechnology rat) override;
+};
+
+// The main test class for Radio AIDL Network.
+class RadioNetworkTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  public:
+    virtual void SetUp() override;
+
+    /* radio network service handle */
+    std::shared_ptr<IRadioNetwork> radio_network;
+    /* radio network response handle */
+    std::shared_ptr<RadioNetworkResponse> radioRsp_network;
+    /* radio network indication handle */
+    std::shared_ptr<RadioNetworkIndication> radioInd_network;
+
+    void invokeAndExpectResponse(std::function<ndk::ScopedAStatus(int32_t serial)> request,
+                                 std::vector<RadioError> errors_to_check);
+
+    // Helper function to reduce copy+paste
+    void testSetUsageSetting_InvalidValues(std::vector<RadioError> errors);
+};
diff --git a/radio/aidl/vts/radio_sim_indication.cpp b/radio/aidl/vts/radio_sim_indication.cpp
new file mode 100644
index 0000000..c03d947
--- /dev/null
+++ b/radio/aidl/vts/radio_sim_indication.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_sim_utils.h"
+
+RadioSimIndication::RadioSimIndication(RadioServiceTest& parent) : parent_sim(parent) {}
+
+ndk::ScopedAStatus RadioSimIndication::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::cdmaSubscriptionSourceChanged(
+        RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::simPhonebookChanged(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::simPhonebookRecordsReceived(
+        RadioIndicationType /*type*/, PbReceivedStatus /*status*/,
+        const std::vector<PhonebookRecordInfo>& /*records*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::simRefresh(RadioIndicationType /*type*/,
+                                                  const SimRefreshResult& /*refreshResult*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::simStatusChanged(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::stkEventNotify(RadioIndicationType /*type*/,
+                                                      const std::string& /*cmd*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::stkProactiveCommand(RadioIndicationType /*type*/,
+                                                           const std::string& /*cmd*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::stkSessionEnd(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::subscriptionStatusChanged(RadioIndicationType /*type*/,
+                                                                 bool /*activate*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimIndication::uiccApplicationsEnablementChanged(
+        RadioIndicationType /*type*/, bool /*enabled*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_sim_response.cpp b/radio/aidl/vts/radio_sim_response.cpp
new file mode 100644
index 0000000..a783f43
--- /dev/null
+++ b/radio/aidl/vts/radio_sim_response.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_sim_utils.h"
+
+RadioSimResponse::RadioSimResponse(RadioServiceTest& parent) : parent_sim(parent) {}
+
+ndk::ScopedAStatus RadioSimResponse::acknowledgeRequest(int32_t /*serial*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::areUiccApplicationsEnabledResponse(
+        const RadioResponseInfo& /*info*/, bool /*enabled*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                                 int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+                                                                int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::enableUiccApplicationsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getAllowedCarriersResponse(
+        const RadioResponseInfo& /*info*/, const CarrierRestrictions& /*carriers*/,
+        SimLockMultiSimPolicy /*multiSimPolicy*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getCdmaSubscriptionResponse(
+        const RadioResponseInfo& /*info*/, const std::string& /*mdn*/, const std::string& /*hSid*/,
+        const std::string& /*hNid*/, const std::string& /*min*/, const std::string& /*prl*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getCdmaSubscriptionSourceResponse(
+        const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getFacilityLockForAppResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*response*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getIccCardStatusResponse(const RadioResponseInfo& info,
+                                                              const CardStatus& card_status) {
+    rspInfo = info;
+    cardStatus = card_status;
+    parent_sim.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getImsiForAppResponse(const RadioResponseInfo& /*info*/,
+                                                           const std::string& /*imsi*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getSimPhonebookCapacityResponse(
+        const RadioResponseInfo& info, const PhonebookCapacity& pbCapacity) {
+    rspInfo = info;
+    capacity = pbCapacity;
+    parent_sim.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::getSimPhonebookRecordsResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_sim.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::iccCloseLogicalChannelResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::iccIoForAppResponse(const RadioResponseInfo& /*info*/,
+                                                         const IccIoResult& /*iccIo*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::iccOpenLogicalChannelResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*channelId*/,
+        const std::vector<uint8_t>& /*selectResponse*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::iccTransmitApduBasicChannelResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::iccTransmitApduLogicalChannelResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::reportStkServiceIsRunningResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::requestIccSimAuthenticationResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::sendEnvelopeResponse(const RadioResponseInfo& /*info*/,
+                                                          const std::string& /*commandResponse*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::sendEnvelopeWithStatusResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*iccIo*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::sendTerminalResponseToSimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::setCarrierInfoForImsiEncryptionResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_sim.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::setCdmaSubscriptionSourceResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::setFacilityLockForAppResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*retry*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::setSimCardPowerResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_sim.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::setUiccSubscriptionResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                                 int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+                                                                int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                                 int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/,
+                                                                int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::supplySimDepersonalizationResponse(
+        const RadioResponseInfo& /*info*/, PersoSubstate /*persoType*/,
+        int32_t /*remainingRetries*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioSimResponse::updateSimPhonebookRecordsResponse(
+        const RadioResponseInfo& info, int32_t recordIndex) {
+    rspInfo = info;
+    updatedRecordIndex = recordIndex;
+    parent_sim.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp
new file mode 100644
index 0000000..5db77f6
--- /dev/null
+++ b/radio/aidl/vts/radio_sim_test.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_sim_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioSimTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_sim = IRadioSim::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_sim.get());
+
+    radioRsp_sim = ndk::SharedRefBase::make<RadioSimResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_sim.get());
+
+    count_ = 0;
+
+    radioInd_sim = ndk::SharedRefBase::make<RadioSimIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_sim.get());
+
+    radio_sim->setResponseFunctions(radioRsp_sim, radioInd_sim);
+    // Assert SIM is present before testing
+    updateSimCardStatus();
+    EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+
+    // Assert IRadioConfig exists before testing
+    radio_config = config::IRadioConfig::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.config.IRadioConfig/default")));
+    ASSERT_NE(nullptr, radio_config.get());
+}
+
+void RadioSimTest::updateSimCardStatus() {
+    serial = GetRandomSerialNumber();
+    radio_sim->getIccCardStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_sim->rspInfo.error);
+}
+
+/*
+ * Test IRadioSim.setSimCardPower() for the response returned.
+ */
+TEST_P(RadioSimTest, setSimCardPower) {
+    /* Test setSimCardPower power down */
+    serial = GetRandomSerialNumber();
+    radio_sim->setSimCardPower(serial, CardPowerState::POWER_DOWN);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                 {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+                                  RadioError::RADIO_NOT_AVAILABLE, RadioError::SIM_ERR}));
+
+    // setSimCardPower does not return  until the request is handled, and should not trigger
+    // CardStatus::STATE_ABSENT when turning off power
+    if (radioRsp_sim->rspInfo.error == RadioError::NONE) {
+        /* Wait some time for setting sim power down and then verify it */
+        updateSimCardStatus();
+        // We cannot assert the consistency of CardState here due to b/203031664
+        // EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+        // applications should be an empty vector of AppStatus
+        EXPECT_EQ(0, cardStatus.applications.size());
+    }
+
+    // Give some time for modem to fully power down the SIM card
+    sleep(MODEM_SET_SIM_POWER_DELAY_IN_SECONDS);
+
+    /* Test setSimCardPower power up */
+    serial = GetRandomSerialNumber();
+    radio_sim->setSimCardPower(serial, CardPowerState::POWER_UP);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                 {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+                                  RadioError::RADIO_NOT_AVAILABLE, RadioError::SIM_ERR}));
+
+    // Give some time for modem to fully power up the SIM card
+    sleep(MODEM_SET_SIM_POWER_DELAY_IN_SECONDS);
+
+    // setSimCardPower does not return  until the request is handled. Just verify that we still
+    // have CardStatus::STATE_PRESENT after turning the power back on
+    if (radioRsp_sim->rspInfo.error == RadioError::NONE) {
+        updateSimCardStatus();
+        EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+    }
+}
+
+/*
+ * Test IRadioSim.setCarrierInfoForImsiEncryption() for the response returned.
+ */
+TEST_P(RadioSimTest, setCarrierInfoForImsiEncryption) {
+    serial = GetRandomSerialNumber();
+    ImsiEncryptionInfo imsiInfo;
+    imsiInfo.mcc = "310";
+    imsiInfo.mnc = "004";
+    imsiInfo.carrierKey = (std::vector<uint8_t>){1, 2, 3, 4, 5, 6};
+    imsiInfo.keyIdentifier = "Test";
+    imsiInfo.expirationTime = 20180101;
+    imsiInfo.keyType = ImsiEncryptionInfo::PUBLIC_KEY_TYPE_EPDG;
+
+    radio_sim->setCarrierInfoForImsiEncryption(serial, imsiInfo);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                     {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+/*
+ * Test IRadioSim.getSimPhonebookRecords() for the response returned.
+ */
+TEST_P(RadioSimTest, getSimPhonebookRecords) {
+    serial = GetRandomSerialNumber();
+    radio_sim->getSimPhonebookRecords(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                 {RadioError::INVALID_SIM_STATE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS,
+                                  RadioError::REQUEST_NOT_SUPPORTED},
+                                 CHECK_GENERAL_ERROR));
+    } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                     {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED},
+                                     CHECK_GENERAL_ERROR));
+    }
+}
+
+/*
+ * Test IRadioSim.getSimPhonebookCapacity for the response returned.
+ */
+TEST_P(RadioSimTest, getSimPhonebookCapacity) {
+    serial = GetRandomSerialNumber();
+    radio_sim->getSimPhonebookCapacity(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                 {RadioError::INVALID_SIM_STATE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS,
+                                  RadioError::REQUEST_NOT_SUPPORTED},
+                                 CHECK_GENERAL_ERROR));
+    } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                     {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED},
+                                     CHECK_GENERAL_ERROR));
+
+        PhonebookCapacity pbCapacity = radioRsp_sim->capacity;
+        if (pbCapacity.maxAdnRecords > 0) {
+            EXPECT_TRUE(pbCapacity.maxNameLen > 0 && pbCapacity.maxNumberLen > 0);
+            EXPECT_TRUE(pbCapacity.usedAdnRecords <= pbCapacity.maxAdnRecords);
+        }
+
+        if (pbCapacity.maxEmailRecords > 0) {
+            EXPECT_TRUE(pbCapacity.maxEmailLen > 0);
+            EXPECT_TRUE(pbCapacity.usedEmailRecords <= pbCapacity.maxEmailRecords);
+        }
+
+        if (pbCapacity.maxAdditionalNumberRecords > 0) {
+            EXPECT_TRUE(pbCapacity.maxAdditionalNumberLen > 0);
+            EXPECT_TRUE(pbCapacity.usedAdditionalNumberRecords <=
+                        pbCapacity.maxAdditionalNumberRecords);
+        }
+    }
+}
+
+/*
+ * Test IRadioSim.updateSimPhonebookRecords() for the response returned.
+ */
+TEST_P(RadioSimTest, updateSimPhonebookRecords) {
+    serial = GetRandomSerialNumber();
+    radio_sim->getSimPhonebookCapacity(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                 {RadioError::INVALID_SIM_STATE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS,
+                                  RadioError::REQUEST_NOT_SUPPORTED},
+                                 CHECK_GENERAL_ERROR));
+    } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                     {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED},
+                                     CHECK_GENERAL_ERROR));
+        PhonebookCapacity pbCapacity = radioRsp_sim->capacity;
+
+        serial = GetRandomSerialNumber();
+        radio_sim->getSimPhonebookRecords(serial);
+
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_sim->rspInfo.error,
+                                     {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED},
+                                     CHECK_GENERAL_ERROR));
+
+        if (pbCapacity.maxAdnRecords > 0 && pbCapacity.usedAdnRecords < pbCapacity.maxAdnRecords) {
+            // Add a phonebook record
+            PhonebookRecordInfo recordInfo;
+            recordInfo.recordId = 0;
+            recordInfo.name = "ABC";
+            recordInfo.number = "1234567890";
+            serial = GetRandomSerialNumber();
+            radio_sim->updateSimPhonebookRecords(serial, recordInfo);
+
+            EXPECT_EQ(std::cv_status::no_timeout, wait());
+            EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+            EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+            EXPECT_EQ(RadioError::NONE, radioRsp_sim->rspInfo.error);
+            int index = radioRsp_sim->updatedRecordIndex;
+            EXPECT_TRUE(index > 0);
+
+            // Deleted a phonebook record
+            recordInfo.recordId = index;
+            recordInfo.name = "";
+            recordInfo.number = "";
+            serial = GetRandomSerialNumber();
+            radio_sim->updateSimPhonebookRecords(serial, recordInfo);
+
+            EXPECT_EQ(std::cv_status::no_timeout, wait());
+            EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_sim->rspInfo.type);
+            EXPECT_EQ(serial, radioRsp_sim->rspInfo.serial);
+            EXPECT_EQ(RadioError::NONE, radioRsp_sim->rspInfo.error);
+        }
+    }
+}
diff --git a/radio/aidl/vts/radio_sim_utils.h b/radio/aidl/vts/radio_sim_utils.h
new file mode 100644
index 0000000..b5e365d
--- /dev/null
+++ b/radio/aidl/vts/radio_sim_utils.h
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/sim/BnRadioSimIndication.h>
+#include <aidl/android/hardware/radio/sim/BnRadioSimResponse.h>
+#include <aidl/android/hardware/radio/sim/IRadioSim.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::sim;
+
+class RadioSimTest;
+
+/* Callback class for radio SIM response */
+class RadioSimResponse : public BnRadioSimResponse {
+  protected:
+    RadioServiceTest& parent_sim;
+
+  public:
+    RadioSimResponse(RadioServiceTest& parent_sim);
+    virtual ~RadioSimResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    CarrierRestrictions carrierRestrictionsResp;
+    SimLockMultiSimPolicy multiSimPolicyResp;
+    bool canToggleUiccApplicationsEnablement;
+    bool areUiccApplicationsEnabled;
+    PhonebookCapacity capacity;
+    int32_t updatedRecordIndex;
+
+    virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
+
+    virtual ndk::ScopedAStatus areUiccApplicationsEnabledResponse(const RadioResponseInfo& info,
+                                                                  bool enabled) override;
+
+    virtual ndk::ScopedAStatus changeIccPin2ForAppResponse(const RadioResponseInfo& info,
+                                                           int32_t remainingRetries) override;
+
+    virtual ndk::ScopedAStatus changeIccPinForAppResponse(const RadioResponseInfo& info,
+                                                          int32_t remainingRetries) override;
+
+    virtual ndk::ScopedAStatus enableUiccApplicationsResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getAllowedCarriersResponse(
+            const RadioResponseInfo& info, const CarrierRestrictions& carriers,
+            const SimLockMultiSimPolicy multiSimPolicy) override;
+
+    virtual ndk::ScopedAStatus getCdmaSubscriptionResponse(
+            const RadioResponseInfo& info, const std::string& mdn, const std::string& hSid,
+            const std::string& hNid, const std::string& min, const std::string& prl) override;
+
+    virtual ndk::ScopedAStatus getCdmaSubscriptionSourceResponse(
+            const RadioResponseInfo& info, CdmaSubscriptionSource source) override;
+
+    virtual ndk::ScopedAStatus getFacilityLockForAppResponse(const RadioResponseInfo& info,
+                                                             int32_t response) override;
+
+    virtual ndk::ScopedAStatus getIccCardStatusResponse(const RadioResponseInfo& info,
+                                                        const CardStatus& cardStatus) override;
+
+    virtual ndk::ScopedAStatus getImsiForAppResponse(const RadioResponseInfo& info,
+                                                     const std::string& imsi) override;
+
+    virtual ndk::ScopedAStatus getSimPhonebookCapacityResponse(
+            const RadioResponseInfo& info, const PhonebookCapacity& capacity) override;
+
+    virtual ndk::ScopedAStatus getSimPhonebookRecordsResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus iccCloseLogicalChannelResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus iccIoForAppResponse(const RadioResponseInfo& info,
+                                                   const IccIoResult& iccIo) override;
+
+    virtual ndk::ScopedAStatus iccOpenLogicalChannelResponse(
+            const RadioResponseInfo& info, int32_t channelId,
+            const std::vector<uint8_t>& selectResponse) override;
+
+    virtual ndk::ScopedAStatus iccTransmitApduBasicChannelResponse(
+            const RadioResponseInfo& info, const IccIoResult& result) override;
+
+    virtual ndk::ScopedAStatus iccTransmitApduLogicalChannelResponse(
+            const RadioResponseInfo& info, const IccIoResult& result) override;
+
+    virtual ndk::ScopedAStatus reportStkServiceIsRunningResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus requestIccSimAuthenticationResponse(
+            const RadioResponseInfo& info, const IccIoResult& result) override;
+
+    virtual ndk::ScopedAStatus sendEnvelopeResponse(const RadioResponseInfo& info,
+                                                    const std::string& commandResponse) override;
+
+    virtual ndk::ScopedAStatus sendEnvelopeWithStatusResponse(const RadioResponseInfo& info,
+                                                              const IccIoResult& iccIo) override;
+
+    virtual ndk::ScopedAStatus sendTerminalResponseToSimResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setAllowedCarriersResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCarrierInfoForImsiEncryptionResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCdmaSubscriptionSourceResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setFacilityLockForAppResponse(const RadioResponseInfo& info,
+                                                             int32_t retry) override;
+
+    virtual ndk::ScopedAStatus setSimCardPowerResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setUiccSubscriptionResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus supplyIccPin2ForAppResponse(const RadioResponseInfo& info,
+                                                           int32_t remainingRetries) override;
+
+    virtual ndk::ScopedAStatus supplyIccPinForAppResponse(const RadioResponseInfo& info,
+                                                          int32_t remainingRetries) override;
+
+    virtual ndk::ScopedAStatus supplyIccPuk2ForAppResponse(const RadioResponseInfo& info,
+                                                           int32_t remainingRetries) override;
+
+    virtual ndk::ScopedAStatus supplyIccPukForAppResponse(const RadioResponseInfo& info,
+                                                          int32_t remainingRetries) override;
+
+    virtual ndk::ScopedAStatus supplySimDepersonalizationResponse(
+            const RadioResponseInfo& info, PersoSubstate persoType,
+            int32_t remainingRetries) override;
+
+    virtual ndk::ScopedAStatus updateSimPhonebookRecordsResponse(
+            const RadioResponseInfo& info, int32_t updatedRecordIndex) override;
+};
+
+/* Callback class for radio SIM indication */
+class RadioSimIndication : public BnRadioSimIndication {
+  protected:
+    RadioServiceTest& parent_sim;
+
+  public:
+    RadioSimIndication(RadioServiceTest& parent_sim);
+    virtual ~RadioSimIndication() = default;
+
+    virtual ndk::ScopedAStatus carrierInfoForImsiEncryption(RadioIndicationType info) override;
+
+    virtual ndk::ScopedAStatus cdmaSubscriptionSourceChanged(
+            RadioIndicationType type, CdmaSubscriptionSource cdmaSource) override;
+
+    virtual ndk::ScopedAStatus simPhonebookChanged(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus simPhonebookRecordsReceived(
+            RadioIndicationType type, PbReceivedStatus status,
+            const std::vector<PhonebookRecordInfo>& records) override;
+
+    virtual ndk::ScopedAStatus simRefresh(RadioIndicationType type,
+                                          const SimRefreshResult& refreshResult) override;
+
+    virtual ndk::ScopedAStatus simStatusChanged(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus stkEventNotify(RadioIndicationType type,
+                                              const std::string& cmd) override;
+
+    virtual ndk::ScopedAStatus stkProactiveCommand(RadioIndicationType type,
+                                                   const std::string& cmd) override;
+
+    virtual ndk::ScopedAStatus stkSessionEnd(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus subscriptionStatusChanged(RadioIndicationType type,
+                                                         bool activate) override;
+
+    virtual ndk::ScopedAStatus uiccApplicationsEnablementChanged(RadioIndicationType type,
+                                                                 bool enabled) override;
+};
+
+// The main test class for Radio AIDL SIM.
+class RadioSimTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  public:
+    virtual void SetUp() override;
+
+    /* Override updateSimCardStatus in RadioServiceTest to not call setResponseFunctions */
+    void updateSimCardStatus();
+
+    /* radio SIM service handle in RadioServiceTest */
+    /* radio SIM response handle */
+    std::shared_ptr<RadioSimResponse> radioRsp_sim;
+    /* radio SIM indication handle */
+    std::shared_ptr<RadioSimIndication> radioInd_sim;
+};
diff --git a/radio/aidl/vts/radio_voice_indication.cpp b/radio/aidl/vts/radio_voice_indication.cpp
new file mode 100644
index 0000000..d814c18
--- /dev/null
+++ b/radio/aidl/vts/radio_voice_indication.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_voice_utils.h"
+
+RadioVoiceIndication::RadioVoiceIndication(RadioServiceTest& parent) : parent_voice(parent) {}
+
+ndk::ScopedAStatus RadioVoiceIndication::callRing(RadioIndicationType /*type*/, bool /*isGsm*/,
+                                                  const CdmaSignalInfoRecord& /*record*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::callStateChanged(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::cdmaCallWaiting(
+        RadioIndicationType /*type*/, const CdmaCallWaiting& /*callWaitingRecord*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::cdmaInfoRec(
+        RadioIndicationType /*type*/, const std::vector<CdmaInformationRecord>& /*records*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::cdmaOtaProvisionStatus(RadioIndicationType /*type*/,
+                                                                CdmaOtaProvisionStatus /*status*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::currentEmergencyNumberList(
+        RadioIndicationType /*type*/, const std::vector<EmergencyNumber>& /*emergencyNumberList*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::enterEmergencyCallbackMode(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::exitEmergencyCallbackMode(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::indicateRingbackTone(RadioIndicationType /*type*/,
+                                                              bool /*start*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::onSupplementaryServiceIndication(
+        RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::resendIncallMute(RadioIndicationType /*type*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::srvccStateNotify(RadioIndicationType /*type*/,
+                                                          SrvccState /*state*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::stkCallControlAlphaNotify(RadioIndicationType /*type*/,
+                                                                   const std::string& /*alpha*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceIndication::stkCallSetup(RadioIndicationType /*type*/,
+                                                      int64_t /*timeout*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_voice_response.cpp b/radio/aidl/vts/radio_voice_response.cpp
new file mode 100644
index 0000000..a491613
--- /dev/null
+++ b/radio/aidl/vts/radio_voice_response.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "radio_voice_utils.h"
+
+RadioVoiceResponse::RadioVoiceResponse(RadioServiceTest& parent) : parent_voice(parent) {}
+
+ndk::ScopedAStatus RadioVoiceResponse::acceptCallResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::acknowledgeRequest(int32_t /*serial*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::conferenceResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::dialResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::emergencyDialResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_voice.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::exitEmergencyCallbackModeResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::explicitCallTransferResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getCallForwardStatusResponse(
+        const RadioResponseInfo& /*info*/,
+        const std::vector<CallForwardInfo>& /*callForwardInfos*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getCallWaitingResponse(const RadioResponseInfo& /*info*/,
+                                                              bool /*enable*/,
+                                                              int32_t /*serviceClass*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getClipResponse(const RadioResponseInfo& /*info*/,
+                                                       ClipStatus /*status*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getClirResponse(const RadioResponseInfo& /*info*/,
+                                                       int32_t /*n*/, int32_t /*m*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getCurrentCallsResponse(const RadioResponseInfo& info,
+                                                               const std::vector<Call>& calls) {
+    rspInfo = info;
+    currentCalls = calls;
+    parent_voice.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getLastCallFailCauseResponse(
+        const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getMuteResponse(const RadioResponseInfo& /*info*/,
+                                                       bool /*enable*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getPreferredVoicePrivacyResponse(
+        const RadioResponseInfo& /*info*/, bool /*enable*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::getTtyModeResponse(const RadioResponseInfo& /*info*/,
+                                                          TtyMode /*mode*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::handleStkCallSetupRequestFromSimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::hangupConnectionResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_voice.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::hangupForegroundResumeBackgroundResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::hangupWaitingOrBackgroundResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::isVoNrEnabledResponse(const RadioResponseInfo& /*info*/,
+                                                             bool /*enabled*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::rejectCallResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::sendCdmaFeatureCodeResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::sendDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::separateConnectionResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::setCallForwardResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::setCallWaitingResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::setClirResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::setMuteResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::setPreferredVoicePrivacyResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::setTtyModeResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::setVoNrEnabledResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::startDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::stopDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioVoiceResponse::switchWaitingOrHoldingAndActiveResponse(
+        const RadioResponseInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_voice_test.cpp b/radio/aidl/vts/radio_voice_test.cpp
new file mode 100644
index 0000000..717f3f0
--- /dev/null
+++ b/radio/aidl/vts/radio_voice_test.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <aidl/android/hardware/radio/voice/EmergencyServiceCategory.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_voice_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioVoiceTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_voice = IRadioVoice::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_voice.get());
+
+    radioRsp_voice = ndk::SharedRefBase::make<RadioVoiceResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_voice.get());
+
+    count_ = 0;
+
+    radioInd_voice = ndk::SharedRefBase::make<RadioVoiceIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_voice.get());
+
+    radio_voice->setResponseFunctions(radioRsp_voice, radioInd_voice);
+
+    // Assert IRadioSim exists and SIM is present before testing
+    radio_sim = sim::IRadioSim::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.sim.IRadioSim/slot1")));
+    ASSERT_NE(nullptr, radio_sim.get());
+    updateSimCardStatus();
+    EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+
+    // Assert IRadioConfig exists before testing
+    radio_config = config::IRadioConfig::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.config.IRadioConfig/default")));
+    ASSERT_NE(nullptr, radio_config.get());
+
+    if (isDsDsEnabled() || isTsTsEnabled()) {
+        radio_network = IRadioNetwork::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(
+                "android.hardware.radio.network.IRadioNetwork/slot1")));
+        ASSERT_NE(nullptr, radio_network.get());
+        radioRsp_network = ndk::SharedRefBase::make<RadioNetworkResponse>(*this);
+        radioInd_network = ndk::SharedRefBase::make<RadioNetworkIndication>(*this);
+        radio_network->setResponseFunctions(radioRsp_network, radioInd_network);
+    }
+}
+
+ndk::ScopedAStatus RadioVoiceTest::clearPotentialEstablishedCalls() {
+    // Get the current call Id to hangup the established emergency call.
+    serial = GetRandomSerialNumber();
+    radio_voice->getCurrentCalls(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+
+    // Hang up to disconnect the established call channels.
+    for (const Call& call : radioRsp_voice->currentCalls) {
+        serial = GetRandomSerialNumber();
+        radio_voice->hangup(serial, call.index);
+        ALOGI("Hang up to disconnect the established call channel: %d", call.index);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        // Give some time for modem to disconnect the established call channel.
+        sleep(MODEM_EMERGENCY_CALL_DISCONNECT_TIME);
+    }
+
+    // Verify there are no more current calls.
+    serial = GetRandomSerialNumber();
+    radio_voice->getCurrentCalls(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(0, radioRsp_voice->currentCalls.size());
+    return ndk::ScopedAStatus::ok();
+}
+
+/*
+ * Test IRadioVoice.emergencyDial() for the response returned.
+ */
+TEST_P(RadioVoiceTest, emergencyDial) {
+    if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
+        ALOGI("Skipping emergencyDial because voice call is not supported in device");
+        return;
+    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+        return;
+    } else {
+        ALOGI("Running emergencyDial because voice call is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    Dial dialInfo;
+    dialInfo.address = std::string("911");
+    int32_t categories = static_cast<int32_t>(EmergencyServiceCategory::UNSPECIFIED);
+    std::vector<std::string> urns = {""};
+    EmergencyCallRouting routing = EmergencyCallRouting::UNKNOWN;
+
+    ndk::ScopedAStatus res =
+            radio_voice->emergencyDial(serial, dialInfo, categories, urns, routing, true, true);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_voice->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_voice->rspInfo.serial);
+
+    ALOGI("emergencyDial, rspInfo.error = %s\n", toString(radioRsp_voice->rspInfo.error).c_str());
+
+    RadioError rspEmergencyDial = radioRsp_voice->rspInfo.error;
+    // In DSDS or TSTS, we only check the result if the current slot is IN_SERVICE
+    // or Emergency_Only.
+    if (isDsDsEnabled() || isTsTsEnabled()) {
+        serial = GetRandomSerialNumber();
+        radio_network->getVoiceRegistrationState(serial);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        if (isVoiceEmergencyOnly(radioRsp_network->voiceRegResp.regState) ||
+            isVoiceInService(radioRsp_network->voiceRegResp.regState)) {
+            EXPECT_EQ(RadioError::NONE, rspEmergencyDial);
+        }
+    } else {
+        EXPECT_EQ(RadioError::NONE, rspEmergencyDial);
+    }
+
+    // Give some time for modem to establish the emergency call channel.
+    sleep(MODEM_EMERGENCY_CALL_ESTABLISH_TIME);
+
+    // Disconnect all the potential established calls to prevent them affecting other tests.
+    clearPotentialEstablishedCalls();
+}
+
+/*
+ * Test IRadioVoice.emergencyDial() with specified service and its response returned.
+ */
+TEST_P(RadioVoiceTest, emergencyDial_withServices) {
+    if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
+        ALOGI("Skipping emergencyDial because voice call is not supported in device");
+        return;
+    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+        return;
+    } else {
+        ALOGI("Running emergencyDial because voice call is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    Dial dialInfo;
+    dialInfo.address = std::string("911");
+    int32_t categories = static_cast<int32_t>(EmergencyServiceCategory::AMBULANCE);
+    std::vector<std::string> urns = {"urn:service:sos.ambulance"};
+    EmergencyCallRouting routing = EmergencyCallRouting::UNKNOWN;
+
+    ndk::ScopedAStatus res =
+            radio_voice->emergencyDial(serial, dialInfo, categories, urns, routing, true, true);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_voice->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_voice->rspInfo.serial);
+
+    ALOGI("emergencyDial_withServices, rspInfo.error = %s\n",
+          toString(radioRsp_voice->rspInfo.error).c_str());
+    RadioError rspEmergencyDial = radioRsp_voice->rspInfo.error;
+
+    // In DSDS or TSTS, we only check the result if the current slot is IN_SERVICE
+    // or Emergency_Only.
+    if (isDsDsEnabled() || isTsTsEnabled()) {
+        serial = GetRandomSerialNumber();
+        radio_network->getVoiceRegistrationState(serial);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        if (isVoiceEmergencyOnly(radioRsp_network->voiceRegResp.regState) ||
+            isVoiceInService(radioRsp_network->voiceRegResp.regState)) {
+            EXPECT_EQ(RadioError::NONE, rspEmergencyDial);
+        }
+    } else {
+        EXPECT_EQ(RadioError::NONE, rspEmergencyDial);
+    }
+    // Give some time for modem to establish the emergency call channel.
+    sleep(MODEM_EMERGENCY_CALL_ESTABLISH_TIME);
+
+    // Disconnect all the potential established calls to prevent them affecting other tests.
+    clearPotentialEstablishedCalls();
+}
+
+/*
+ * Test IRadioVoice.emergencyDial() with known emergency call routing and its response returned.
+ */
+TEST_P(RadioVoiceTest, emergencyDial_withEmergencyRouting) {
+    if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
+        ALOGI("Skipping emergencyDial because voice call is not supported in device");
+        return;
+    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+        return;
+    } else {
+        ALOGI("Running emergencyDial because voice call is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    Dial dialInfo;
+    dialInfo.address = std::string("911");
+    int32_t categories = static_cast<int32_t>(EmergencyServiceCategory::UNSPECIFIED);
+    std::vector<std::string> urns = {""};
+    EmergencyCallRouting routing = EmergencyCallRouting::EMERGENCY;
+
+    ndk::ScopedAStatus res =
+            radio_voice->emergencyDial(serial, dialInfo, categories, urns, routing, true, true);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_voice->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_voice->rspInfo.serial);
+
+    ALOGI("emergencyDial_withEmergencyRouting, rspInfo.error = %s\n",
+          toString(radioRsp_voice->rspInfo.error).c_str());
+    RadioError rspEmergencyDial = radioRsp_voice->rspInfo.error;
+
+    // In DSDS or TSTS, we only check the result if the current slot is IN_SERVICE
+    // or Emergency_Only.
+    if (isDsDsEnabled() || isTsTsEnabled()) {
+        serial = GetRandomSerialNumber();
+        radio_network->getVoiceRegistrationState(serial);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        if (isVoiceEmergencyOnly(radioRsp_network->voiceRegResp.regState) ||
+            isVoiceInService(radioRsp_network->voiceRegResp.regState)) {
+            EXPECT_EQ(RadioError::NONE, rspEmergencyDial);
+        }
+    } else {
+        EXPECT_EQ(RadioError::NONE, rspEmergencyDial);
+    }
+
+    // Give some time for modem to establish the emergency call channel.
+    sleep(MODEM_EMERGENCY_CALL_ESTABLISH_TIME);
+
+    // Disconnect all the potential established calls to prevent them affecting other tests.
+    clearPotentialEstablishedCalls();
+}
+
+/*
+ * Test IRadioVoice.getCurrentCalls() for the response returned.
+ */
+TEST_P(RadioVoiceTest, getCurrentCalls) {
+    serial = GetRandomSerialNumber();
+    radio_voice->getCurrentCalls(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_voice->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_voice->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_voice->rspInfo.error);
+}
diff --git a/radio/aidl/vts/radio_voice_utils.h b/radio/aidl/vts/radio_voice_utils.h
new file mode 100644
index 0000000..d61bf1e
--- /dev/null
+++ b/radio/aidl/vts/radio_voice_utils.h
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/voice/BnRadioVoiceIndication.h>
+#include <aidl/android/hardware/radio/voice/BnRadioVoiceResponse.h>
+#include <aidl/android/hardware/radio/voice/IRadioVoice.h>
+
+#include "radio_aidl_hal_utils.h"
+#include "radio_network_utils.h"
+
+using namespace aidl::android::hardware::radio::voice;
+
+class RadioVoiceTest;
+
+/* Callback class for radio voice response */
+class RadioVoiceResponse : public BnRadioVoiceResponse {
+  protected:
+    RadioServiceTest& parent_voice;
+
+  public:
+    RadioVoiceResponse(RadioServiceTest& parent_voice);
+    virtual ~RadioVoiceResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    std::vector<Call> currentCalls;
+
+    virtual ndk::ScopedAStatus acceptCallResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
+
+    virtual ndk::ScopedAStatus conferenceResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus dialResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus emergencyDialResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus exitEmergencyCallbackModeResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus explicitCallTransferResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getCallForwardStatusResponse(
+            const RadioResponseInfo& info,
+            const std::vector<CallForwardInfo>& call_forwardInfos) override;
+
+    virtual ndk::ScopedAStatus getCallWaitingResponse(const RadioResponseInfo& info, bool enable,
+                                                      int32_t serviceClass) override;
+
+    virtual ndk::ScopedAStatus getClipResponse(const RadioResponseInfo& info,
+                                               ClipStatus status) override;
+
+    virtual ndk::ScopedAStatus getClirResponse(const RadioResponseInfo& info, int32_t n,
+                                               int32_t m) override;
+
+    virtual ndk::ScopedAStatus getCurrentCallsResponse(const RadioResponseInfo& info,
+                                                       const std::vector<Call>& calls) override;
+
+    virtual ndk::ScopedAStatus getLastCallFailCauseResponse(
+            const RadioResponseInfo& info, const LastCallFailCauseInfo& failCauseInfo) override;
+
+    virtual ndk::ScopedAStatus getMuteResponse(const RadioResponseInfo& info, bool enable) override;
+
+    virtual ndk::ScopedAStatus getPreferredVoicePrivacyResponse(const RadioResponseInfo& info,
+                                                                bool enable) override;
+
+    virtual ndk::ScopedAStatus getTtyModeResponse(const RadioResponseInfo& info,
+                                                  TtyMode mode) override;
+
+    virtual ndk::ScopedAStatus handleStkCallSetupRequestFromSimResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus hangupConnectionResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus hangupForegroundResumeBackgroundResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus hangupWaitingOrBackgroundResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus isVoNrEnabledResponse(const RadioResponseInfo& info,
+                                                     bool enable) override;
+
+    virtual ndk::ScopedAStatus rejectCallResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus sendBurstDtmfResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus sendCdmaFeatureCodeResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus sendDtmfResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus separateConnectionResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCallForwardResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCallWaitingResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setClirResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setMuteResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setPreferredVoicePrivacyResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setTtyModeResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setVoNrEnabledResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus startDtmfResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus stopDtmfResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus switchWaitingOrHoldingAndActiveResponse(
+            const RadioResponseInfo& info) override;
+};
+
+/* Callback class for radio voice indication */
+class RadioVoiceIndication : public BnRadioVoiceIndication {
+  protected:
+    RadioServiceTest& parent_voice;
+
+  public:
+    RadioVoiceIndication(RadioServiceTest& parent_voice);
+    virtual ~RadioVoiceIndication() = default;
+
+    virtual ndk::ScopedAStatus callRing(RadioIndicationType type, bool isGsm,
+                                        const CdmaSignalInfoRecord& record) override;
+
+    virtual ndk::ScopedAStatus callStateChanged(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus cdmaCallWaiting(RadioIndicationType type,
+                                               const CdmaCallWaiting& callWaitingRecord) override;
+
+    virtual ndk::ScopedAStatus cdmaInfoRec(
+            RadioIndicationType type, const std::vector<CdmaInformationRecord>& records) override;
+
+    virtual ndk::ScopedAStatus cdmaOtaProvisionStatus(RadioIndicationType type,
+                                                      CdmaOtaProvisionStatus status) override;
+
+    virtual ndk::ScopedAStatus currentEmergencyNumberList(
+            RadioIndicationType type,
+            const std::vector<EmergencyNumber>& emergencyNumberList) override;
+
+    virtual ndk::ScopedAStatus enterEmergencyCallbackMode(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus exitEmergencyCallbackMode(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus indicateRingbackTone(RadioIndicationType type, bool start) override;
+
+    virtual ndk::ScopedAStatus onSupplementaryServiceIndication(
+            RadioIndicationType type, const StkCcUnsolSsResult& ss) override;
+
+    virtual ndk::ScopedAStatus resendIncallMute(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus srvccStateNotify(RadioIndicationType type,
+                                                SrvccState state) override;
+
+    virtual ndk::ScopedAStatus stkCallControlAlphaNotify(RadioIndicationType type,
+                                                         const std::string& alpha) override;
+
+    virtual ndk::ScopedAStatus stkCallSetup(RadioIndicationType type, int64_t timeout) override;
+};
+
+// The main test class for Radio AIDL Voice.
+class RadioVoiceTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  protected:
+    /* Clear Potential Established Calls */
+    virtual ndk::ScopedAStatus clearPotentialEstablishedCalls();
+    std::shared_ptr<network::IRadioNetwork> radio_network;
+    std::shared_ptr<RadioNetworkResponse> radioRsp_network;
+    std::shared_ptr<RadioNetworkIndication> radioInd_network;
+
+  public:
+    virtual void SetUp() override;
+
+    /* radio voice service handle */
+    std::shared_ptr<IRadioVoice> radio_voice;
+    /* radio voice response handle */
+    std::shared_ptr<RadioVoiceResponse> radioRsp_voice;
+    /* radio voice indication handle */
+    std::shared_ptr<RadioVoiceIndication> radioInd_voice;
+};
diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp
index 8a8086b..dc06c71 100644
--- a/rebootescrow/aidl/default/service.cpp
+++ b/rebootescrow/aidl/default/service.cpp
@@ -34,7 +34,7 @@
     auto re = ndk::SharedRefBase::make<RebootEscrow>(rebootEscrowDevicePath);
     const std::string instance = std::string() + RebootEscrow::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;
diff --git a/security/dice/aidl/Android.bp b/security/dice/aidl/Android.bp
new file mode 100644
index 0000000..01bc91e
--- /dev/null
+++ b/security/dice/aidl/Android.bp
@@ -0,0 +1,51 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.security.dice",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/security/dice/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+            platform_apis: false,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+            apps_enabled: false,
+        },
+        rust: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.compos",
+            ],
+        },
+    },
+    //     versions: ["1"],
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Bcc.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Bcc.aidl
new file mode 100644
index 0000000..5af7358
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Bcc.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.dice;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable Bcc {
+  byte[] data;
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/BccHandover.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/BccHandover.aidl
new file mode 100644
index 0000000..8baca94
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/BccHandover.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.dice;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable BccHandover {
+  byte[32] cdiAttest;
+  byte[32] cdiSeal;
+  android.hardware.security.dice.Bcc bcc;
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Config.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Config.aidl
new file mode 100644
index 0000000..78dd2f8
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Config.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.dice;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable Config {
+  byte[] desc;
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/IDiceDevice.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/IDiceDevice.aidl
new file mode 100644
index 0000000..383f4d1
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/IDiceDevice.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.dice;
+/* @hide */
+@SensitiveData @VintfStability
+interface IDiceDevice {
+  android.hardware.security.dice.Signature sign(in android.hardware.security.dice.InputValues[] id, in byte[] payload);
+  android.hardware.security.dice.Bcc getAttestationChain(in android.hardware.security.dice.InputValues[] inputValues);
+  android.hardware.security.dice.BccHandover derive(in android.hardware.security.dice.InputValues[] inputValues);
+  void demote(in android.hardware.security.dice.InputValues[] inputValues);
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/InputValues.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/InputValues.aidl
new file mode 100644
index 0000000..e43c429
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/InputValues.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.dice;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable InputValues {
+  byte[64] codeHash;
+  android.hardware.security.dice.Config config;
+  byte[64] authorityHash;
+  @nullable byte[] authorityDescriptor;
+  android.hardware.security.dice.Mode mode = android.hardware.security.dice.Mode.NOT_INITIALIZED;
+  byte[64] hidden;
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Mode.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Mode.aidl
new file mode 100644
index 0000000..295c32e
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Mode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.dice;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum Mode {
+  NOT_INITIALIZED = 0,
+  NORMAL = 1,
+  DEBUG = 2,
+  RECOVERY = 3,
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/ResponseCode.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/ResponseCode.aidl
new file mode 100644
index 0000000..c13afa6
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/ResponseCode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.dice;
+@Backing(type="int") @VintfStability
+enum ResponseCode {
+  PERMISSION_DENIED = 1,
+  SYSTEM_ERROR = 2,
+  NOT_IMPLEMENTED = 3,
+  DEMOTION_FAILED = 4,
+}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Signature.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Signature.aidl
new file mode 100644
index 0000000..294170d
--- /dev/null
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/Signature.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.dice;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable Signature {
+  byte[] data;
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/Bcc.aidl b/security/dice/aidl/android/hardware/security/dice/Bcc.aidl
new file mode 100644
index 0000000..983915e
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/Bcc.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+/**
+ * A DICE certificate chain following the Boot Certificate Chain (BCC) specification.
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable Bcc {
+    /**
+     * The DICE certificate chain CBOR encoded following the BCC specification. The CDDL
+     * specification for BCC can be found here [1].
+     *
+     * @see <a
+     *         href="https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl">
+     *    BCC CDDL specification
+     * </a>
+     */
+    byte[] data;
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/BccHandover.aidl b/security/dice/aidl/android/hardware/security/dice/BccHandover.aidl
new file mode 100644
index 0000000..6ca862c
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/BccHandover.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+import android.hardware.security.dice.Bcc;
+
+/**
+ * Represents one set of DICE artifacts.
+ *
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable BccHandover {
+    /**
+     * CDI_attest. Must be exactly 32 bytes of data.
+     */
+    byte[32] cdiAttest;
+    /**
+     * CDI_seal. Must be exactly 32 bytes of data.
+     */
+    byte[32] cdiSeal;
+    /**
+     * CBOR encoded BCC.
+     *
+     * @see <a
+     *         href="https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl">
+     *    BCC CDDL specification
+     * </a>
+     */
+    Bcc bcc;
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/Config.aidl b/security/dice/aidl/android/hardware/security/dice/Config.aidl
new file mode 100644
index 0000000..6decfc5
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/Config.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+/**
+ * DICE config descriptor as described in at
+ * <a
+ * href="https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#input-values">
+ *     input-values
+ * </a>
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable Config {
+    /**
+     * A free form descriptor. This should follow the BCC Configuration Descriptor.
+     * @see <a
+     *         href="https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl">
+     *     BccPayload field -4670548
+     * </a>
+     */
+    byte[] desc;
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/IDiceDevice.aidl b/security/dice/aidl/android/hardware/security/dice/IDiceDevice.aidl
new file mode 100644
index 0000000..709aede
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/IDiceDevice.aidl
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+import android.hardware.security.dice.Bcc;
+import android.hardware.security.dice.BccHandover;
+import android.hardware.security.dice.InputValues;
+import android.hardware.security.dice.Signature;
+
+/**
+ * IDiceDevice specifies an interface that allows access to the Android instance's DICE artifacts.
+ *
+ * <h2>Features</h2>
+ *
+ * The dice device provides access to the component's CDI_SEAL and CDI_ATTEST secrets as well
+ * as to its attestation certificate chain. The "component" is the Android instance running this
+ * HAL service and the secrets and attestation chain must include all boot stage components,
+ * the kernel, and the verified boot information (VBA).
+ *
+ * Implementations provide the following operations:
+ * <li> sign - Signing a payload with a key derived from CDI_ATTEST.
+ * <li> getAttestationChain - Retrieve the component's attestation certificate chain.
+ * <li> derive - Retrieve the component's DICE artifacts.
+ *
+ * @see <a
+ *         href="https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md">
+ *     Open-dice Specification
+ * </a>
+ * @see <a
+ *         href="https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl">
+ *     Boot Certificate Chain (BCC) CDDL specification
+ * </a>
+ * @hide
+ */
+@SensitiveData
+@VintfStability
+interface IDiceDevice {
+    /**
+     * Uses the a key derived from the component's, or a child's given by <code>inputValues</code>,
+     * attestation secret to sign the payload using RFC 8032 Pure Ed25519 and returns the
+     * signature. The payload is limited to 1024 bytes.
+     *
+     * @see <a href="https://datatracker.ietf.org/doc/html/rfc8032">RFC 8032</a>
+     */
+    Signature sign(in InputValues[] id, in byte[] payload);
+
+    /**
+     * Returns the attestation chain of the component if <code>inputValues</code> is empty or the
+     * chain to the given child of the component identified by the <code>inputValues</code> vector.
+     *
+     * ## Error as service specific exception:
+     *     ResponseCode::PERMISSION_DENIED if the caller is not sufficiently privileged.
+     */
+    Bcc getAttestationChain(in InputValues[] inputValues);
+
+    /**
+     * This function allows a client to become a resident node. A resident node is a node that
+     * manages its own dice secrets as opposed to using them by proxy, i.e., by calling sign
+     * and getAttestationChain. Called with empty <code>inputValues</code> vectors, an
+     * implementation returns the component's DICE secrets. If the <code>inputValues</code> vector
+     * is given the appropriate derivations are performed starting from the component's level.
+     *
+     * ## Error as service specific exception:
+     *     ResponseCode::PERMISSION_DENIED if the implementation does not allow resident nodes
+     *     at the client's level.
+     */
+    BccHandover derive(in InputValues[] inputValues);
+
+    /**
+     * This demotes the implementation of this interface.
+     * When called, the implementation performs appropriate derivation steps using
+     * <code>inputValues</code>, traversing the vector in ascending order. Then it replaces its
+     * stored DICE artifacts with the newly derived ones.
+     *
+     * IMPORTANT: When the function returns, all remnants of the previous DICE artifacts must
+     * have been purged from memory.
+     *
+     * This operation is not reversible until the next reboot. Further demotion is always
+     * possible.
+     *
+     * ## Error as service specific exception:
+     *     ResponseCode::DEMOTION_FAILED if the implementation failed to demote itself
+     *     or was unable to purge previous DICE artifacts from memory.
+     */
+    void demote(in InputValues[] inputValues);
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/InputValues.aidl b/security/dice/aidl/android/hardware/security/dice/InputValues.aidl
new file mode 100644
index 0000000..711d523
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/InputValues.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+import android.hardware.security.dice.Config;
+import android.hardware.security.dice.Mode;
+
+/**
+ * DICE input values for certificate and CDI generation.
+ *
+ * @see <a
+ *         href="https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#input-values">
+ *     Open-dice input-values
+ * </a>
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+@VintfStability
+parcelable InputValues {
+    /**
+     * The target code hash. Must be exactly 64 bytes.
+     */
+    byte[64] codeHash;
+    /**
+     * The configuration data.
+     */
+    Config config;
+    /**
+     * The authority hash. Must be exactly 64 bytes. Must be all zero if unused.
+     */
+    byte[64] authorityHash;
+    /**
+     * Optional free form authorityDescriptor.
+     */
+    @nullable byte[] authorityDescriptor;
+    /**
+     * The mode of operation. Normal, Debug, Maintenance, or not initialized.
+     */
+    Mode mode = Mode.NOT_INITIALIZED;
+    /**
+     * Optional hidden values. Must be exactly 64 bytes. Must be all zero if unused.
+     */
+    byte[64] hidden;
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/Mode.aidl b/security/dice/aidl/android/hardware/security/dice/Mode.aidl
new file mode 100644
index 0000000..3b3bfdc
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/Mode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+/**
+ * DICE mode values as defined at
+ *
+ * @see <a
+ *         href="https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#mode-value-details">
+ *     open-dice mode-value-details
+ * </a>
+ * @hide
+ */
+@Backing(type="int")
+@VintfStability
+enum Mode {
+    NOT_INITIALIZED = 0,
+    NORMAL = 1,
+    DEBUG = 2,
+    /**
+     * The recovery mode is also referred to as "maintenance" mode.
+     */
+    RECOVERY = 3,
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/ResponseCode.aidl b/security/dice/aidl/android/hardware/security/dice/ResponseCode.aidl
new file mode 100644
index 0000000..3e77cf7
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/ResponseCode.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+@Backing(type="int")
+/**
+ * These response codes are used as service specific exception codes by
+ * IDiceDevice.
+ * @hide
+ */
+@VintfStability
+enum ResponseCode {
+    /**
+     * The caller has insufficient privilege to access the DICE API.
+     */
+    PERMISSION_DENIED = 1,
+    /**
+     * An unexpected error occurred, likely with IO or IPC.
+     */
+    SYSTEM_ERROR = 2,
+    /**
+     * Returned if the called function is not implemented.
+     */
+    NOT_IMPLEMENTED = 3,
+    /**
+     * An attempt to demote the implementation failed.
+     */
+    DEMOTION_FAILED = 4,
+}
diff --git a/security/dice/aidl/android/hardware/security/dice/Signature.aidl b/security/dice/aidl/android/hardware/security/dice/Signature.aidl
new file mode 100644
index 0000000..ea3594f
--- /dev/null
+++ b/security/dice/aidl/android/hardware/security/dice/Signature.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.dice;
+
+/**
+ * This parcelable represents a Signature. It is used as return value of IDiceNode::sign.
+ *
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+@VintfStability
+parcelable Signature {
+    /**
+     * The RFC 8032 PureEd25519 signature.
+     * @see <a href="https://datatracker.ietf.org/doc/html/rfc8032">RFC 8032</a>
+     */
+    byte[] data;
+}
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 028d297..dcbe9c1 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -38,3 +38,30 @@
     },
     versions: ["1"],
 }
+
+// cc_defaults that includes the latest KeyMint AIDL library.
+// Modules that depend on KeyMint directly can include this cc_defaults to avoid
+// managing dependency versions explicitly.
+cc_defaults {
+    name: "keymint_use_latest_hal_aidl_ndk_static",
+    static_libs: [
+        "android.hardware.security.keymint-V2-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "keymint_use_latest_hal_aidl_ndk_shared",
+    shared_libs: [
+        "android.hardware.security.keymint-V2-ndk",
+    ],
+}
+
+// A rust_defaults that includes the latest KeyMint AIDL library.
+// Modules that depend on KeyMint directly can include this cc_defaults to avoid
+// managing dependency versions explicitly.
+rust_defaults {
+    name: "keymint_use_latest_hal_aidl_rust",
+    rustlibs: [
+        "android.hardware.security.keymint-V2-rust",
+    ],
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/EcCurve.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/EcCurve.aidl
index 6b4a9ae..ffc7efe 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/EcCurve.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/EcCurve.aidl
@@ -39,4 +39,5 @@
   P_256 = 1,
   P_384 = 2,
   P_521 = 3,
+  CURVE_25519 = 4,
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 06bce19..5ff45f8 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -38,6 +38,7 @@
   int versionNumber;
   @utf8InCpp String rpcAuthorName;
   int supportedEekCurve = 0;
+  @nullable @utf8InCpp String uniqueId;
   const int CURVE_NONE = 0;
   const int CURVE_P256 = 1;
   const int CURVE_25519 = 2;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/EcCurve.aidl b/security/keymint/aidl/android/hardware/security/keymint/EcCurve.aidl
index 5b1c10c..e9f81d8 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/EcCurve.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/EcCurve.aidl
@@ -27,4 +27,5 @@
     P_256 = 1,
     P_384 = 2,
     P_521 = 3,
+    CURVE_25519 = 4,
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index cd8cfc5..4b63799 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -93,6 +93,13 @@
  *        P-521.  STRONGBOX IKeyMintDevices must support NIST curve P-256.
  *      - TRUSTED_ENVIRONMENT IKeyMintDevices must support SHA1, SHA-2 224, SHA-2 256, SHA-2
  *        384 and SHA-2 512 digest modes.  STRONGBOX IKeyMintDevices must support SHA-2 256.
+ *      - TRUSTED_ENVRIONMENT IKeyMintDevices must support curve 25519 for Purpose::SIGN (Ed25519,
+ *        as specified in RFC 8032), Purpose::ATTEST_KEY (Ed25519) or for KeyPurpose::AGREE_KEY
+ *        (X25519, as specified in RFC 7748).  However, a key must have exactly one of these
+ *        purpose values; the same key cannot be used for multiple purposes. Signing operations
+ *        (Purpose::SIGN) have a message size limit of 16 KiB; operations on messages longer than
+ *        this limit must fail with ErrorCode::INVALID_INPUT_LENGTH.
+ *        STRONGBOX IKeyMintDevices do not support curve 25519.
  *
  * o   AES
  *
@@ -287,7 +294,7 @@
      *   except AGREE_KEY must be supported for RSA keys.
      *
      * o Tag::DIGEST specifies digest algorithms that may be used with the new key.  TEE
-     *   IKeyMintDevice implementations must support all Digest values (see digest.aidl) for RSA
+     *   IKeyMintDevice implementations must support all Digest values (see Digest.aidl) for RSA
      *   keys.  StrongBox IKeyMintDevice implementations must support SHA_2_256.
      *
      * o Tag::PADDING specifies the padding modes that may be used with the new
@@ -298,13 +305,24 @@
      * == ECDSA Keys ==
      *
      * Tag::EC_CURVE must be provided to generate an ECDSA key.  If it is not provided, generateKey
-     * must return ErrorCode::UNSUPPORTED_KEY_SIZE. TEE IKeyMintDevice implementations must support
-     * all curves.  StrongBox implementations must support P_256.
-
+     * must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE. TEE
+     * IKeyMintDevice implementations must support all required curves.  StrongBox implementations
+     * must support P_256 and no other curves.
+     *
      * Tag::CERTIFICATE_NOT_BEFORE and Tag::CERTIFICATE_NOT_AFTER must be provided to specify the
      * valid date range for the returned X.509 certificate holding the public key. If omitted,
      * generateKey must return ErrorCode::MISSING_NOT_BEFORE or ErrorCode::MISSING_NOT_AFTER.
      *
+     * Keys with EC_CURVE of EcCurve::CURVE_25519 must have exactly one purpose in the set
+     * {KeyPurpose::SIGN, KeyPurpose::ATTEST_KEY, KeyPurpose::AGREE_KEY}.  Key generation with more
+     * than one purpose should be rejected with ErrorCode::INCOMPATIBLE_PURPOSE.
+     * StrongBox implementation do not support CURVE_25519.
+     *
+     * Tag::DIGEST specifies digest algorithms that may be used with the new key.  TEE
+     * IKeyMintDevice implementations must support all Digest values (see Digest.aidl) for ECDSA
+     * keys; Ed25519 keys only support Digest::NONE. StrongBox IKeyMintDevice implementations must
+     * support SHA_2_256.
+     *
      * == AES Keys ==
      *
      * Only Tag::KEY_SIZE is required to generate an AES key.  If omitted, generateKey must return
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index ce83044..ca89555 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -227,7 +227,8 @@
      * o PaddingMode::RSA_PSS.  For PSS-padded signature operations, the PSS salt length must match
      *   the size of the PSS digest selected.  The digest specified with Tag::DIGEST in params
      *   on begin() must be used as the PSS digest algorithm, MGF1 must be used as the mask
-     *   generation function and SHA1 must be used as the MGF1 digest algorithm.
+     *   generation function and the digest specified with Tag:DIGEST in params on begin() must also
+     *   be used as the MGF1 digest algorithm.
      *
      * -- ECDSA keys --
      *
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index fd6bf65..16bbc5c 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -122,9 +122,9 @@
      * straightforward translation of the KeyMint tag/value parameter lists to ASN.1.
      *
      * KeyDescription ::= SEQUENCE {
-     *     attestationVersion         INTEGER, # Value 100
+     *     attestationVersion         INTEGER, # Value 200
      *     attestationSecurityLevel   SecurityLevel, # See below
-     *     keyMintVersion             INTEGER, # Value 100
+     *     keyMintVersion             INTEGER, # Value 200
      *     keymintSecurityLevel       SecurityLevel, # See below
      *     attestationChallenge       OCTET_STRING, # Tag::ATTESTATION_CHALLENGE from attestParams
      *     uniqueId                   OCTET_STRING, # Empty unless key has Tag::INCLUDE_UNIQUE_ID
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyFormat.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyFormat.aidl
index da3d521..3faef38 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyFormat.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyFormat.aidl
@@ -25,8 +25,10 @@
 enum KeyFormat {
     /** X.509 certificate format, for public key export. */
     X509 = 0,
-    /** PCKS#8 format, asymmetric key pair import. */
+    /** PKCS#8 format, asymmetric key pair import. */
     PKCS8 = 1,
-    /** Raw bytes, for symmetric key import. */
+    /**
+     * Raw bytes, for symmetric key import, and for import of raw asymmetric keys for curve 25519.
+     */
     RAW = 3,
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index e141e55..fd103ef 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -44,6 +44,10 @@
     AGREE_KEY = 6,
 
     /* Usable as an attestation signing key.  Keys with this purpose must not have any other
-     * purpose. */
+     * purpose; if they do, key generation/import must be rejected with
+     * ErrorCode::INCOMPATIBLE_PURPOSE. (Rationale: If key also included KeyPurpose::SIGN, then
+     * it could be used to sign arbitrary data, including any tbsCertificate, and so an
+     * attestation produced by the key would have no security properties.)
+     */
     ATTEST_KEY = 7,
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
index d297f87..3a4c233 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -53,4 +53,21 @@
      * a passing implementation does not provide CURVE_NONE.
      */
     int supportedEekCurve = CURVE_NONE;
+
+    /**
+     * uniqueId is an opaque identifier for this IRemotelyProvisionedComponent implementation. The
+     * client should NOT interpret the content of the identifier in any way. The client can only
+     * compare identifiers to determine if two IRemotelyProvisionedComponents share the same
+     * implementation. Each IRemotelyProvisionedComponent implementation must have a distinct
+     * identifier from all other implementations on the same device.
+     *
+     * This identifier must be consistent across reboots, as it is used to store and track
+     * provisioned keys in a persistent, on-device database.
+     *
+     * uniqueId may not be empty, and must not be any longer than 32 characters.
+     *
+     * This field was added in API version 2.
+     *
+     */
+    @nullable @utf8InCpp String uniqueId;
 }
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index c2918ef..1a17fd4 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -21,8 +21,10 @@
         "-Wall",
         "-Wextra",
     ],
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
     shared_libs: [
-        "android.hardware.security.keymint-V1-ndk",
         "android.hardware.security.sharedsecret-V1-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libbase",
diff --git a/security/keymint/aidl/default/service.cpp b/security/keymint/aidl/default/service.cpp
index 8092e34..dc0c618 100644
--- a/security/keymint/aidl/default/service.cpp
+++ b/security/keymint/aidl/default/service.cpp
@@ -39,7 +39,7 @@
     LOG(INFO) << "adding keymint service instance: " << instanceName;
     binder_status_t status =
             AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
     return ser;
 }
 
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index ff6a6f8..2d2d701 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_defaults {
     name: "keymint_vts_defaults",
     defaults: [
+        "keymint_use_latest_hal_aidl_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
         "VtsHalTargetTestDefaults",
     ],
@@ -34,7 +35,6 @@
         "libcrypto",
     ],
     static_libs: [
-        "android.hardware.security.keymint-V1-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libcppbor_external",
         "libcppcose_rkp",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 64550ef..727c6b7 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -81,7 +81,8 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+                                              SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
         // Attestation by itself is not valid (last entry is not self-signed).
@@ -113,7 +114,8 @@
 
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record("foo2", "bar2", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo2", "bar2", sw_enforced,
+                                              hw_enforced, SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
         // Attestation by itself is not valid (last entry is not self-signed).
@@ -154,12 +156,13 @@
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
 
         // The client-specified CREATION_DATETIME should be in sw_enforced.
-        // Its presence will also trigger verify_attestation_record() to check that it
-        // is in the attestation extension with a matching value.
+        // Its presence will also trigger verify_attestation_record() to check that
+        // it is in the attestation extension with a matching value.
         EXPECT_TRUE(sw_enforced.Contains(TAG_CREATION_DATETIME, timestamp))
                 << "expected CREATION_TIMESTAMP in sw_enforced:" << sw_enforced
                 << " not in hw_enforced:" << hw_enforced;
-        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+                                              SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
         // Attestation by itself is not valid (last entry is not self-signed).
@@ -175,6 +178,24 @@
 }
 
 /*
+ * AttestKeyTest.RsaAttestKeyMultiPurposeFail
+ *
+ * This test attempts to create an RSA attestation key that also allows signing.
+ */
+TEST_P(AttestKeyTest, RsaAttestKeyMultiPurposeFail) {
+    vector<uint8_t> attest_key_blob;
+    vector<KeyCharacteristics> attest_key_characteristics;
+    vector<Certificate> attest_key_cert_chain;
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .RsaSigningKey(2048, 65537)
+                                  .AttestKey()
+                                  .SetDefaultValidity(),
+                          {} /* attestation signing key */, &attest_key_blob,
+                          &attest_key_characteristics, &attest_key_cert_chain));
+}
+
+/*
  * AttestKeyTest.RsaAttestedAttestKeys
  *
  * This test creates an RSA attestation key signed by factory keys, and varifies it can be
@@ -217,7 +238,7 @@
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attest_key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attest_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(challenge, app_id,  //
+    EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                           sw_enforced, hw_enforced, SecLevel(),
                                           attest_key_cert_chain[0].encodedCertificate));
 
@@ -252,7 +273,8 @@
 
     AuthorizationSet hw_enforced2 = HwEnforcedAuthorizations(attested_key_characteristics);
     AuthorizationSet sw_enforced2 = SwEnforcedAuthorizations(attested_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced2, hw_enforced2, SecLevel(),
+    EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced2, hw_enforced2,
+                                          SecLevel(),
                                           attested_key_cert_chain[0].encodedCertificate));
 
     // Attestation by itself is not valid (last entry is not self-signed).
@@ -313,7 +335,8 @@
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+                                              SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
         if (i > 0) {
@@ -385,7 +408,8 @@
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+                                              SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
         if (i > 0) {
@@ -412,6 +436,24 @@
 }
 
 /*
+ * AttestKeyTest.EcAttestKeyMultiPurposeFail
+ *
+ * This test attempts to create an EC attestation key that also allows signing.
+ */
+TEST_P(AttestKeyTest, EcAttestKeyMultiPurposeFail) {
+    vector<uint8_t> attest_key_blob;
+    vector<KeyCharacteristics> attest_key_characteristics;
+    vector<Certificate> attest_key_cert_chain;
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .EcdsaSigningKey(EcCurve::P_256)
+                                  .AttestKey()
+                                  .SetDefaultValidity(),
+                          {} /* attestation signing key */, &attest_key_blob,
+                          &attest_key_characteristics, &attest_key_cert_chain));
+}
+
+/*
  * AttestKeyTest.AlternateAttestKeyChaining
  *
  * This test creates a chain of multiple attest keys, in the order Ec - RSA - Ec - RSA ....
@@ -474,7 +516,8 @@
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+                                              SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
         if (i > 0) {
@@ -583,11 +626,13 @@
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
 
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
         CheckedDeleteKey(&attested_key_blob);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+                                              SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
         // Attestation by itself is not valid (last entry is not self-signed).
@@ -612,12 +657,14 @@
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
 
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
         CheckedDeleteKey(&attested_key_blob);
         CheckedDeleteKey(&attest_key.keyBlob);
 
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+                                              SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
         // Attestation by itself is not valid (last entry is not self-signed).
@@ -722,8 +769,8 @@
         // attestation extension should contain them, so make sure the extra tag is added.
         hw_enforced.push_back(tag);
 
-        EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,
-                                              SecLevel(),
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+                                              hw_enforced, SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
     }
     CheckedDeleteKey(&attest_key.keyBlob);
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index 3cbffbf..d4bbd69 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -52,8 +52,9 @@
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_, /* strict_issuer_check= */ false));
 
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-        EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,
-                                              SecLevel(), cert_chain_[0].encodedCertificate));
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+                                              hw_enforced, SecLevel(),
+                                              cert_chain_[0].encodedCertificate));
     }
 };
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 12ce859..146a527 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -25,6 +25,7 @@
 #include <cppbor_parse.h>
 #include <cutils/properties.h>
 #include <gmock/gmock.h>
+#include <openssl/evp.h>
 #include <openssl/mem.h>
 #include <remote_prov/remote_prov_utils.h>
 
@@ -127,6 +128,16 @@
     return attest_rec;
 }
 
+void check_attestation_version(uint32_t attestation_version, int32_t aidl_version) {
+    // Version numbers in attestation extensions should be a multiple of 100.
+    EXPECT_EQ(attestation_version % 100, 0);
+
+    // The multiplier should never be higher than the AIDL version, but can be less
+    // (for example, if the implementation is from an earlier version but the HAL service
+    // uses the default libraries and so reports the current AIDL version).
+    EXPECT_TRUE((attestation_version / 100) <= aidl_version);
+}
+
 bool avb_verification_enabled() {
     char value[PROPERTY_VALUE_MAX];
     return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
@@ -196,6 +207,21 @@
     return boot_patch_level(key_characteristics_);
 }
 
+bool KeyMintAidlTestBase::Curve25519Supported() {
+    // Strongbox never supports curve 25519.
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        return false;
+    }
+
+    // Curve 25519 was included in version 2 of the KeyMint interface.
+    int32_t version = 0;
+    auto status = keymint_->getInterfaceVersion(&version);
+    if (!status.isOk()) {
+        ADD_FAILURE() << "Failed to determine interface version";
+    }
+    return version >= 2;
+}
+
 ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
     if (result.isOk()) return ErrorCode::OK;
 
@@ -223,6 +249,15 @@
     vendor_patch_level_ = getVendorPatchlevel();
 }
 
+int32_t KeyMintAidlTestBase::AidlVersion() {
+    int32_t version = 0;
+    auto status = keymint_->getInterfaceVersion(&version);
+    if (!status.isOk()) {
+        ADD_FAILURE() << "Failed to determine interface version";
+    }
+    return version;
+}
+
 void KeyMintAidlTestBase::SetUp() {
     if (AServiceManager_isDeclared(GetParam().c_str())) {
         ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
@@ -518,10 +553,18 @@
     Status result;
     if (!output) return ErrorCode::UNEXPECTED_NULL_POINTER;
 
+    EXPECT_NE(op_, nullptr);
+    if (!op_) return ErrorCode::UNEXPECTED_NULL_POINTER;
+
     std::vector<uint8_t> o_put;
     result = op_->update(vector<uint8_t>(input.begin(), input.end()), {}, {}, &o_put);
 
-    if (result.isOk()) output->append(o_put.begin(), o_put.end());
+    if (result.isOk()) {
+        output->append(o_put.begin(), o_put.end());
+    } else {
+        // Failure always terminates the operation.
+        op_ = {};
+    }
 
     return GetReturnErrorCode(result);
 }
@@ -718,6 +761,19 @@
 
     if (digest == Digest::NONE) {
         switch (EVP_PKEY_id(pub_key.get())) {
+            case EVP_PKEY_ED25519: {
+                ASSERT_EQ(64, signature.size());
+                uint8_t pub_keydata[32];
+                size_t pub_len = sizeof(pub_keydata);
+                ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(pub_key.get(), pub_keydata, &pub_len));
+                ASSERT_EQ(sizeof(pub_keydata), pub_len);
+                ASSERT_EQ(1, ED25519_verify(reinterpret_cast<const uint8_t*>(message.data()),
+                                            message.size(),
+                                            reinterpret_cast<const uint8_t*>(signature.data()),
+                                            pub_keydata));
+                break;
+            }
+
             case EVP_PKEY_EC: {
                 vector<uint8_t> data((EVP_PKEY_bits(pub_key.get()) + 7) / 8);
                 size_t data_size = std::min(data.size(), message.size());
@@ -790,6 +846,7 @@
         if (padding == PaddingMode::RSA_PSS) {
             EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING), 0);
             EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, EVP_MD_size(md)), 0);
+            EXPECT_GT(EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, md), 0);
         }
 
         ASSERT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx,
@@ -1067,6 +1124,8 @@
         }
     } else {
         switch (algorithm) {
+            case Algorithm::AES:
+                return {64, 96, 131, 512};
             case Algorithm::TRIPLE_DES:
                 return {56};
             default:
@@ -1141,16 +1200,31 @@
 vector<EcCurve> KeyMintAidlTestBase::ValidCurves() {
     if (securityLevel_ == SecurityLevel::STRONGBOX) {
         return {EcCurve::P_256};
+    } else if (Curve25519Supported()) {
+        return {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521,
+                EcCurve::CURVE_25519};
     } else {
-        return {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+        return {
+                EcCurve::P_224,
+                EcCurve::P_256,
+                EcCurve::P_384,
+                EcCurve::P_521,
+        };
     }
 }
 
 vector<EcCurve> KeyMintAidlTestBase::InvalidCurves() {
     if (SecLevel() == SecurityLevel::STRONGBOX) {
-        return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521};
+        // Curve 25519 is not supported, either because:
+        // - KeyMint v1: it's an unknown enum value
+        // - KeyMint v2+: it's not supported by StrongBox.
+        return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521, EcCurve::CURVE_25519};
     } else {
-        return {};
+        if (Curve25519Supported()) {
+            return {};
+        } else {
+            return {EcCurve::CURVE_25519};
+        }
     }
 }
 
@@ -1302,7 +1376,8 @@
     verify_subject(cert.get(), subject, self_signed);
 }
 
-bool verify_attestation_record(const string& challenge,                //
+bool verify_attestation_record(int32_t aidl_version,                   //
+                               const string& challenge,                //
                                const string& app_id,                   //
                                AuthorizationSet expected_sw_enforced,  //
                                AuthorizationSet expected_hw_enforced,  //
@@ -1340,7 +1415,7 @@
     EXPECT_EQ(ErrorCode::OK, error);
     if (error != ErrorCode::OK) return false;
 
-    EXPECT_EQ(att_attestation_version, 100U);
+    check_attestation_version(att_attestation_version, aidl_version);
     vector<uint8_t> appId(app_id.begin(), app_id.end());
 
     // check challenge and app id only if we expects a non-fake certificate
@@ -1351,7 +1426,7 @@
         expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, appId);
     }
 
-    EXPECT_EQ(att_keymint_version, 100U);
+    check_attestation_version(att_keymint_version, aidl_version);
     EXPECT_EQ(security_level, att_keymint_security_level);
     EXPECT_EQ(security_level, att_attestation_security_level);
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 7b3b9d4..27cb99c 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -73,12 +73,15 @@
 
     void InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyMint);
     IKeyMintDevice& keyMint() { return *keymint_; }
+    int32_t AidlVersion();
     uint32_t os_version() { return os_version_; }
     uint32_t os_patch_level() { return os_patch_level_; }
     uint32_t vendor_patch_level() { return vendor_patch_level_; }
     uint32_t boot_patch_level(const vector<KeyCharacteristics>& key_characteristics);
     uint32_t boot_patch_level();
 
+    bool Curve25519Supported();
+
     ErrorCode GetReturnErrorCode(const Status& result);
 
     ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
@@ -333,7 +336,8 @@
                                const uint64_t expected_serial,  //
                                const string& subject, bool self_signed);
 
-bool verify_attestation_record(const string& challenge,                //
+bool verify_attestation_record(int aidl_version,                       //
+                               const string& challenge,                //
                                const string& app_id,                   //
                                AuthorizationSet expected_sw_enforced,  //
                                AuthorizationSet expected_hw_enforced,  //
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 919d79f..7357ac7 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -22,6 +22,7 @@
 #include <algorithm>
 #include <iostream>
 
+#include <openssl/curve25519.h>
 #include <openssl/ec.h>
 #include <openssl/evp.h>
 #include <openssl/mem.h>
@@ -69,8 +70,14 @@
 
 namespace {
 
+// Maximum supported Ed25519 message size.
+const size_t MAX_ED25519_MSG_SIZE = 16 * 1024;
+
+// Whether to check that BOOT_PATCHLEVEL is populated.
+bool check_boot_pl = true;
+
 // The maximum number of times we'll attempt to verify that corruption
-// of an ecrypted blob results in an error. Retries are necessary as there
+// of an encrypted blob results in an error. Retries are necessary as there
 // is a small (roughly 1/256) chance that corrupting ciphertext still results
 // in valid PKCS7 padding.
 constexpr size_t kMaxPaddingCorruptionRetries = 8;
@@ -412,6 +419,126 @@
         // } end SEQUENCE (PrivateKeyInfo)
 );
 
+/**
+ * Ed25519 key pair generated as follows:
+ * ```
+ * % openssl req -x509 -newkey ED25519 -days 700 -nodes \
+ *  -keyout ed25519_priv.key -out ed25519.pem * -subj "/CN=fake.ed25519.com"
+ * Generating a ED25519 private key writing new private key to
+ * 'ed25519_priv.key'
+ * -----
+ * % cat ed25519_priv.key
+ * -----BEGIN PRIVATE KEY-----
+ * MC4CAQAwBQYDK2VwBCIEIKl3A5quNywcj1P+0XI9SBalFPIvO52NxceMLRH6dVmR
+ * -----END PRIVATE KEY-----
+ * % der2ascii -pem -i ed25519_priv.key
+ * SEQUENCE {
+ *   INTEGER { 0 }
+ *   SEQUENCE {
+ *     # ed25519
+ *     OBJECT_IDENTIFIER { 1.3.101.112 }
+ *   }
+ *   OCTET_STRING {
+ *     OCTET_STRING { `a977039aae372c1c8f53fed1723d4816a514f22f3b9d8dc5c78c2d11fa755991` }
+ *   }
+ * }
+ * % cat ed25519.pem
+ * -----BEGIN CERTIFICATE-----
+ * MIIBSjCB/aADAgECAhR0Jron3eKcdgqyecv/eEfGWAzn8DAFBgMrZXAwGzEZMBcG
+ * A1UEAwwQZmFrZS5lZDI1NTE5LmNvbTAeFw0yMTEwMjAwODI3NDJaFw0yMzA5MjAw
+ * ODI3NDJaMBsxGTAXBgNVBAMMEGZha2UuZWQyNTUxOS5jb20wKjAFBgMrZXADIQDv
+ * uwHz+3TaQ69D2digxlz0fFfsZg0rPqgQae3jBPRWkaNTMFEwHQYDVR0OBBYEFN9O
+ * od30SY4JTs66ZR403UPya+iXMB8GA1UdIwQYMBaAFN9Ood30SY4JTs66ZR403UPy
+ * a+iXMA8GA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAKjVrYQjuE/gEL2j/ABpDbFjV
+ * Ilg5tJ6MN/P3psAv3Cs7f0X1lFqdlt15nJ/6aj2cmGCwNRXt5wcyYDKNu+v2Dw==
+ * -----END CERTIFICATE-----
+ * % openssl x509 -in ed25519.pem -text -noout
+ * Certificate:
+ *     Data:
+ *         Version: 3 (0x2)
+ *         Serial Number:
+ *             74:26:ba:27:dd:e2:9c:76:0a:b2:79:cb:ff:78:47:c6:58:0c:e7:f0
+ *         Signature Algorithm: ED25519
+ *         Issuer: CN = fake.ed25519.com
+ *         Validity
+ *             Not Before: Oct 20 08:27:42 2021 GMT
+ *             Not After : Sep 20 08:27:42 2023 GMT
+ *         Subject: CN = fake.ed25519.com
+ *         Subject Public Key Info:
+ *             Public Key Algorithm: ED25519
+ *                 ED25519 Public-Key:
+ *                 pub:
+ *                     ef:bb:01:f3:fb:74:da:43:af:43:d9:d8:a0:c6:5c:
+ *                     f4:7c:57:ec:66:0d:2b:3e:a8:10:69:ed:e3:04:f4:
+ *                     56:91
+ *         X509v3 extensions:
+ *             X509v3 Subject Key Identifier:
+ *                 DF:4E:A1:DD:F4:49:8E:09:4E:CE:BA:65:1E:34:DD:43:F2:6B:E8:97
+ *             X509v3 Authority Key Identifier:
+ *                 keyid:DF:4E:A1:DD:F4:49:8E:09:4E:CE:BA:65:1E:34:DD:43:F2:6B:E8:97
+ *
+ *             X509v3 Basic Constraints: critical
+ *                 CA:TRUE
+ *     Signature Algorithm: ED25519
+ *          2a:35:6b:61:08:ee:13:f8:04:2f:68:ff:00:1a:43:6c:58:d5:
+ *          22:58:39:b4:9e:8c:37:f3:f7:a6:c0:2f:dc:2b:3b:7f:45:f5:
+ *          94:5a:9d:96:dd:79:9c:9f:fa:6a:3d:9c:98:60:b0:35:15:ed:
+ *          e7:07:32:60:32:8d:bb:eb:f6:0f
+ * ```
+ */
+string ed25519_key = hex2str("a977039aae372c1c8f53fed1723d4816a514f22f3b9d8dc5c78c2d11fa755991");
+string ed25519_pkcs8_key = hex2str(
+        // RFC 5208 s5
+        "302e"    // SEQUENCE length 0x2e (PrivateKeyInfo) {
+        "0201"    // INTEGER length 1 (Version)
+        "00"      // version 0
+        "3005"    // SEQUENCE length 05 (AlgorithmIdentifier) {
+        "0603"    // OBJECT IDENTIFIER length 3 (algorithm)
+        "2b6570"  // 1.3.101.112 (id-Ed125519 RFC 8410 s3)
+        // } end SEQUENCE (AlgorithmIdentifier)
+        "0422"  // OCTET STRING length 0x22 (PrivateKey)
+        "0420"  // OCTET STRING length 0x20 (RFC 8410 s7)
+        "a977039aae372c1c8f53fed1723d4816a514f22f3b9d8dc5c78c2d11fa755991"
+        // } end SEQUENCE (PrivateKeyInfo)
+);
+string ed25519_pubkey = hex2str("efbb01f3fb74da43af43d9d8a0c65cf47c57ec660d2b3ea81069ede304f45691");
+
+/**
+ * X25519 key pair generated as follows:
+ * ```
+ * % openssl genpkey -algorithm X25519 > x25519_priv.key
+ * % cat x25519_priv.key
+ * -----BEGIN PRIVATE KEY-----
+ * MC4CAQAwBQYDK2VuBCIEIGgPwF3NLwQx/Sfwr2nfJvXitwlDNh3Skzh+TISN/y1C
+ * -----END PRIVATE KEY-----
+ * % der2ascii -pem -i x25519_priv.key
+ * SEQUENCE {
+ *   INTEGER { 0 }
+ *   SEQUENCE {
+ *     # x25519
+ *     OBJECT_IDENTIFIER { 1.3.101.110 }
+ *   }
+ *   OCTET_STRING {
+ *     OCTET_STRING { `680fc05dcd2f0431fd27f0af69df26f5e2b70943361dd293387e4c848dff2d42` }
+ *   }
+ * }
+ * ```
+ */
+
+string x25519_key = hex2str("680fc05dcd2f0431fd27f0af69df26f5e2b70943361dd293387e4c848dff2d42");
+string x25519_pkcs8_key = hex2str(
+        // RFC 5208 s5
+        "302e"    // SEQUENCE length 0x2e (PrivateKeyInfo) {
+        "0201"    // INTEGER length 1 (Version)
+        "00"      // version 0
+        "3005"    // SEQUENCE length 05 (AlgorithmIdentifier) {
+        "0603"    // OBJECT IDENTIFIER length 3 (algorithm)
+        "2b656e"  // 1.3.101.110 (id-X125519 RFC 8410 s3)
+        "0422"    // OCTET STRING length 0x22 (PrivateKey)
+        "0420"    // OCTET STRING length 0x20 (RFC 8410 s7)
+        "680fc05dcd2f0431fd27f0af69df26f5e2b70943361dd293387e4c848dff2d42");
+string x25519_pubkey = hex2str("be46925a857f17831d6d454b9d3d36a4a30166edf80eb82b684661c3e258f768");
+
 struct RSA_Delete {
     void operator()(RSA* p) { RSA_free(p); }
 };
@@ -527,12 +654,17 @@
         EXPECT_TRUE(os_pl);
         EXPECT_EQ(*os_pl, os_patch_level());
 
-        // Should include vendor and boot patchlevels.
+        // Should include vendor patchlevel.
         auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
         EXPECT_TRUE(vendor_pl);
         EXPECT_EQ(*vendor_pl, vendor_patch_level());
-        auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
-        EXPECT_TRUE(boot_pl);
+
+        // Should include boot patchlevel (but there are some test scenarios where this is not
+        // possible).
+        if (check_boot_pl) {
+            auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+            EXPECT_TRUE(boot_pl);
+        }
 
         return auths;
     }
@@ -934,7 +1066,7 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(challenge, app_id,  //
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
 
@@ -1085,7 +1217,7 @@
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(challenge, app_id,  //
+    EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                           sw_enforced, hw_enforced, SecLevel(),
                                           cert_chain_[0].encodedCertificate));
 
@@ -1307,7 +1439,7 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(challenge, app_id,  //
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
 
@@ -1366,7 +1498,7 @@
 /*
  * NewKeyGenerationTest.Ecdsa
  *
- * Verifies that keymint can generate all required EC key sizes, and that the resulting keys
+ * Verifies that keymint can generate all required EC curves, and that the resulting keys
  * have correct characteristics.
  */
 TEST_P(NewKeyGenerationTest, Ecdsa) {
@@ -1392,6 +1524,65 @@
 }
 
 /*
+ * NewKeyGenerationTest.EcdsaCurve25519
+ *
+ * Verifies that keymint can generate a curve25519 key, and that the resulting key
+ * has correct characteristics.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaCurve25519) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    EcCurve curve = EcCurve::CURVE_25519;
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+    ErrorCode result = GenerateKey(AuthorizationSetBuilder()
+                                           .EcdsaSigningKey(curve)
+                                           .Digest(Digest::NONE)
+                                           .SetDefaultValidity(),
+                                   &key_blob, &key_characteristics);
+    ASSERT_EQ(result, ErrorCode::OK);
+    ASSERT_GT(key_blob.size(), 0U);
+
+    EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+    ASSERT_GT(cert_chain_.size(), 0);
+
+    CheckBaseParams(key_characteristics);
+    CheckCharacteristics(key_blob, key_characteristics);
+
+    AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+    EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+    EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
+
+    CheckedDeleteKey(&key_blob);
+}
+
+/*
+ * NewKeyGenerationTest.EcCurve25519MultiPurposeFail
+ *
+ * Verifies that KeyMint rejects an attempt to generate a curve 25519 key for both
+ * SIGN and AGREE_KEY.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaCurve25519MultiPurposeFail) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    EcCurve curve = EcCurve::CURVE_25519;
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+    ErrorCode result = GenerateKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                           .EcdsaSigningKey(curve)
+                                           .Digest(Digest::NONE)
+                                           .SetDefaultValidity(),
+                                   &key_blob, &key_characteristics);
+    ASSERT_EQ(result, ErrorCode::INCOMPATIBLE_PURPOSE);
+}
+
+/*
  * NewKeyGenerationTest.EcdsaAttestation
  *
  * Verifies that for all Ecdsa key sizes, if challenge and app id is provided,
@@ -1436,7 +1627,7 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(challenge, app_id,  //
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
 
@@ -1445,6 +1636,62 @@
 }
 
 /*
+ * NewKeyGenerationTest.EcdsaAttestationCurve25519
+ *
+ * Verifies that for a curve 25519 key, if challenge and app id is provided,
+ * an attestation will be generated.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationCurve25519) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    EcCurve curve = EcCurve::CURVE_25519;
+    auto challenge = "hello";
+    auto app_id = "foo";
+
+    auto subject = "cert subj 2";
+    vector<uint8_t> subject_der(make_name_from_str(subject));
+
+    uint64_t serial_int = 0xFFFFFFFFFFFFFFFF;
+    vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+    ErrorCode result = GenerateKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .EcdsaSigningKey(curve)
+                                           .Digest(Digest::NONE)
+                                           .AttestationChallenge(challenge)
+                                           .AttestationApplicationId(app_id)
+                                           .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                           .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                           .SetDefaultValidity(),
+                                   &key_blob, &key_characteristics);
+    ASSERT_EQ(ErrorCode::OK, result);
+    ASSERT_GT(key_blob.size(), 0U);
+    CheckBaseParams(key_characteristics);
+    CheckCharacteristics(key_blob, key_characteristics);
+
+    AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+    EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+    EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
+
+    EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+    ASSERT_GT(cert_chain_.size(), 0);
+    verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
+
+    AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+    AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+    EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
+                                          sw_enforced, hw_enforced, SecLevel(),
+                                          cert_chain_[0].encodedCertificate));
+
+    CheckedDeleteKey(&key_blob);
+}
+
+/*
  * NewKeyGenerationTest.EcdsaAttestationTags
  *
  * Verifies that creation of an attested ECDSA key includes various tags in the
@@ -1515,8 +1762,9 @@
 
         // Verifying the attestation record will check for the specific tag because
         // it's included in the authorizations.
-        EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced,
-                                              SecLevel(), cert_chain_[0].encodedCertificate));
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, sw_enforced,
+                                              hw_enforced, SecLevel(),
+                                              cert_chain_[0].encodedCertificate));
 
         CheckedDeleteKey(&key_blob);
     }
@@ -1613,8 +1861,9 @@
 
         // Verifying the attestation record will check for the specific tag because
         // it's included in the authorizations.
-        EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced,
-                                              SecLevel(), cert_chain_[0].encodedCertificate));
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, sw_enforced,
+                                              hw_enforced, SecLevel(),
+                                              cert_chain_[0].encodedCertificate));
 
         CheckedDeleteKey(&key_blob);
     }
@@ -1660,9 +1909,9 @@
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics_);
 
         // Check that the unique ID field in the extension is non-empty.
-        EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced,
-                                              SecLevel(), cert_chain_[0].encodedCertificate,
-                                              unique_id));
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, sw_enforced,
+                                              hw_enforced, SecLevel(),
+                                              cert_chain_[0].encodedCertificate, unique_id));
         EXPECT_GT(unique_id->size(), 0);
         CheckedDeleteKey();
     };
@@ -1757,8 +2006,9 @@
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(challenge, attest_app_id, sw_enforced, hw_enforced,
-                                          SecLevel(), cert_chain_[0].encodedCertificate));
+    EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, attest_app_id, sw_enforced,
+                                          hw_enforced, SecLevel(),
+                                          cert_chain_[0].encodedCertificate));
 
     // Check that the app id is not in the cert.
     string app_id = "clientid";
@@ -1911,7 +2161,7 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(challenge, app_id,  //
+        EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
 
@@ -1973,20 +2223,22 @@
 }
 
 /*
- * NewKeyGenerationTest.EcdsaInvalidSize
+ * NewKeyGenerationTest.EcdsaInvalidCurve
  *
- * Verifies that specifying an invalid key size for EC key generation returns
+ * Verifies that specifying an invalid curve for EC key generation returns
  * UNSUPPORTED_KEY_SIZE.
  */
-TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
+TEST_P(NewKeyGenerationTest, EcdsaInvalidCurve) {
     for (auto curve : InvalidCurves()) {
         vector<uint8_t> key_blob;
         vector<KeyCharacteristics> key_characteristics;
-        ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, GenerateKey(AuthorizationSetBuilder()
-                                                                       .EcdsaSigningKey(curve)
-                                                                       .Digest(Digest::NONE)
-                                                                       .SetDefaultValidity(),
-                                                               &key_blob, &key_characteristics));
+        auto result = GenerateKey(AuthorizationSetBuilder()
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(Digest::NONE)
+                                          .SetDefaultValidity(),
+                                  &key_blob, &key_characteristics);
+        ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
+                    result == ErrorCode::UNSUPPORTED_EC_CURVE);
     }
 
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
@@ -2797,15 +3049,19 @@
 /*
  * SigningOperationsTest.EcdsaAllDigestsAndCurves
  *
- * Verifies ECDSA signature/verification for all digests and curves.
+ * Verifies ECDSA signature/verification for all digests and required curves.
  */
 TEST_P(SigningOperationsTest, EcdsaAllDigestsAndCurves) {
-    auto digests = ValidDigests(true /* withNone */, false /* withMD5 */);
 
     string message = "1234567890";
     string corrupt_message = "2234567890";
     for (auto curve : ValidCurves()) {
         SCOPED_TRACE(testing::Message() << "Curve::" << curve);
+        // Ed25519 only allows Digest::NONE.
+        auto digests = (curve == EcCurve::CURVE_25519)
+                               ? std::vector<Digest>(1, Digest::NONE)
+                               : ValidDigests(true /* withNone */, false /* withMD5 */);
+
         ErrorCode error = GenerateKey(AuthorizationSetBuilder()
                                               .Authorization(TAG_NO_AUTH_REQUIRED)
                                               .EcdsaSigningKey(curve)
@@ -2830,25 +3086,141 @@
 /*
  * SigningOperationsTest.EcdsaAllCurves
  *
- * Verifies that ECDSA operations succeed with all possible curves.
+ * Verifies that ECDSA operations succeed with all required curves.
  */
 TEST_P(SigningOperationsTest, EcdsaAllCurves) {
     for (auto curve : ValidCurves()) {
+        Digest digest = (curve == EcCurve::CURVE_25519 ? Digest::NONE : Digest::SHA_2_256);
+        SCOPED_TRACE(testing::Message() << "Curve::" << curve);
         ErrorCode error = GenerateKey(AuthorizationSetBuilder()
                                               .Authorization(TAG_NO_AUTH_REQUIRED)
                                               .EcdsaSigningKey(curve)
-                                              .Digest(Digest::SHA_2_256)
+                                              .Digest(digest)
                                               .SetDefaultValidity());
         EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
         if (error != ErrorCode::OK) continue;
 
         string message(1024, 'a');
-        SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+        SignMessage(message, AuthorizationSetBuilder().Digest(digest));
         CheckedDeleteKey();
     }
 }
 
 /*
+ * SigningOperationsTest.EcdsaCurve25519
+ *
+ * Verifies that ECDSA operations succeed with curve25519.
+ */
+TEST_P(SigningOperationsTest, EcdsaCurve25519) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    EcCurve curve = EcCurve::CURVE_25519;
+    ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(Digest::NONE)
+                                          .SetDefaultValidity());
+    ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+
+    string message(1024, 'a');
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE));
+    CheckedDeleteKey();
+}
+
+/*
+ * SigningOperationsTest.EcdsaCurve25519MaxSize
+ *
+ * Verifies that EDDSA operations with curve25519 under the maximum message size succeed.
+ */
+TEST_P(SigningOperationsTest, EcdsaCurve25519MaxSize) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    EcCurve curve = EcCurve::CURVE_25519;
+    ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(Digest::NONE)
+                                          .SetDefaultValidity());
+    ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+
+    auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+
+    for (size_t msg_size : {MAX_ED25519_MSG_SIZE - 1, MAX_ED25519_MSG_SIZE}) {
+        SCOPED_TRACE(testing::Message() << "-msg-size=" << msg_size);
+        string message(msg_size, 'a');
+
+        // Attempt to sign via Begin+Finish.
+        AuthorizationSet out_params;
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+        EXPECT_TRUE(out_params.empty());
+        string signature;
+        auto result = Finish(message, &signature);
+        EXPECT_EQ(result, ErrorCode::OK);
+        LocalVerifyMessage(message, signature, params);
+
+        // Attempt to sign via Begin+Update+Finish
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+        EXPECT_TRUE(out_params.empty());
+        string output;
+        result = Update(message, &output);
+        EXPECT_EQ(result, ErrorCode::OK);
+        EXPECT_EQ(output.size(), 0);
+        string signature2;
+        EXPECT_EQ(ErrorCode::OK, Finish({}, &signature2));
+        LocalVerifyMessage(message, signature2, params);
+    }
+
+    CheckedDeleteKey();
+}
+
+/*
+ * SigningOperationsTest.EcdsaCurve25519MaxSizeFail
+ *
+ * Verifies that EDDSA operations with curve25519 fail when message size is too large.
+ */
+TEST_P(SigningOperationsTest, EcdsaCurve25519MaxSizeFail) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    EcCurve curve = EcCurve::CURVE_25519;
+    ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(Digest::NONE)
+                                          .SetDefaultValidity());
+    ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+
+    auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+
+    for (size_t msg_size : {MAX_ED25519_MSG_SIZE + 1, MAX_ED25519_MSG_SIZE * 2}) {
+        SCOPED_TRACE(testing::Message() << "-msg-size=" << msg_size);
+        string message(msg_size, 'a');
+
+        // Attempt to sign via Begin+Finish.
+        AuthorizationSet out_params;
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+        EXPECT_TRUE(out_params.empty());
+        string signature;
+        auto result = Finish(message, &signature);
+        EXPECT_EQ(result, ErrorCode::INVALID_INPUT_LENGTH);
+
+        // Attempt to sign via Begin+Update (but never get to Finish)
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+        EXPECT_TRUE(out_params.empty());
+        string output;
+        result = Update(message, &output);
+        EXPECT_EQ(result, ErrorCode::INVALID_INPUT_LENGTH);
+    }
+
+    CheckedDeleteKey();
+}
+
+/*
  * SigningOperationsTest.EcdsaNoDigestHugeData
  *
  * Verifies that ECDSA operations support very large messages, even without digesting.  This
@@ -3143,6 +3515,58 @@
     CheckedDeleteKey(&verification_key);
 }
 
+/*
+ * VerificationOperationsTest.HmacVerificationFailsForCorruptSignature
+ *
+ * Verifies HMAC signature verification should fails if message or signature is corrupted.
+ */
+TEST_P(VerificationOperationsTest, HmacVerificationFailsForCorruptSignature) {
+    string key_material = "HelloThisIsAKey";
+
+    vector<uint8_t> signing_key, verification_key;
+    vector<KeyCharacteristics> signing_key_chars, verification_key_chars;
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                                .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                                .Digest(Digest::SHA_2_256)
+                                .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                                .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+                                .Digest(Digest::SHA_2_256)
+                                .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+
+    string message = "This is a message.";
+    string signature = SignMessage(
+            signing_key, message,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 160));
+
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::VERIFY, verification_key,
+                    AuthorizationSetBuilder().Digest(Digest::SHA_2_256), &begin_out_params));
+
+    string corruptMessage = "This is b message.";  // Corrupted message
+    string output;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corruptMessage, signature, &output));
+
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::VERIFY, verification_key,
+                    AuthorizationSetBuilder().Digest(Digest::SHA_2_256), &begin_out_params));
+
+    signature[0] += 1;  // Corrupt a signature
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, signature, &output));
+
+    CheckedDeleteKey(&signing_key);
+    CheckedDeleteKey(&verification_key);
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(VerificationOperationsTest);
 
 typedef KeyMintAidlTestBase ExportKeyTest;
@@ -3292,6 +3716,26 @@
 }
 
 /*
+ * ImportKeyTest.RsaAttestMultiPurposeFail
+ *
+ * Verifies that importing an RSA key pair with purpose ATTEST_KEY+SIGN fails.
+ */
+TEST_P(ImportKeyTest, RsaAttestMultiPurposeFail) {
+    uint32_t key_size = 2048;
+    string key = rsa_2048_key;
+
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .RsaSigningKey(key_size, 65537)
+                                .AttestKey()
+                                .Digest(Digest::SHA_2_256)
+                                .Padding(PaddingMode::RSA_PSS)
+                                .SetDefaultValidity(),
+                        KeyFormat::PKCS8, key));
+}
+
+/*
  * ImportKeyTest.EcdsaSuccess
  *
  * Verifies that importing and using an ECDSA P-256 key pair works correctly.
@@ -3410,6 +3854,271 @@
 }
 
 /*
+ * ImportKeyTest.EcdsaAttestMultiPurposeFail
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair with purpose ATTEST_KEY+SIGN fails.
+ */
+TEST_P(ImportKeyTest, EcdsaAttestMultiPurposeFail) {
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .EcdsaSigningKey(EcCurve::P_256)
+                                .AttestKey()
+                                .Digest(Digest::SHA_2_256)
+                                .SetDefaultValidity(),
+                        KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.Ed25519RawSuccess
+ *
+ * Verifies that importing and using a raw Ed25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, Ed25519RawSuccess) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(EcCurve::CURVE_25519)
+                                               .Digest(Digest::NONE)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::RAW, ed25519_key));
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+    CheckOrigin();
+
+    // The returned cert should hold the correct public key.
+    ASSERT_GT(cert_chain_.size(), 0);
+    X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+    ASSERT_NE(kmKeyCert, nullptr);
+    EVP_PKEY_Ptr kmPubKey(X509_get_pubkey(kmKeyCert.get()));
+    ASSERT_NE(kmPubKey.get(), nullptr);
+    size_t kmPubKeySize = 32;
+    uint8_t kmPubKeyData[32];
+    ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+    ASSERT_EQ(kmPubKeySize, 32);
+    EXPECT_EQ(string(kmPubKeyData, kmPubKeyData + 32), ed25519_pubkey);
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+    string signature = SignMessage(message, params);
+    LocalVerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ed25519Pkcs8Success
+ *
+ * Verifies that importing and using a PKCS#8-encoded Ed25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, Ed25519Pkcs8Success) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(EcCurve::CURVE_25519)
+                                               .Digest(Digest::NONE)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, ed25519_pkcs8_key));
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+    CheckOrigin();
+
+    // The returned cert should hold the correct public key.
+    ASSERT_GT(cert_chain_.size(), 0);
+    X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+    ASSERT_NE(kmKeyCert, nullptr);
+    EVP_PKEY_Ptr kmPubKey(X509_get_pubkey(kmKeyCert.get()));
+    ASSERT_NE(kmPubKey.get(), nullptr);
+    size_t kmPubKeySize = 32;
+    uint8_t kmPubKeyData[32];
+    ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+    ASSERT_EQ(kmPubKeySize, 32);
+    EXPECT_EQ(string(kmPubKeyData, kmPubKeyData + 32), ed25519_pubkey);
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+    string signature = SignMessage(message, params);
+    LocalVerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ed25519CurveMismatch
+ *
+ * Verifies that importing an Ed25519 key pair with a curve that doesn't match the key fails in
+ * the correct way.
+ */
+TEST_P(ImportKeyTest, Ed25519CurveMismatch) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_NE(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                                .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
+                                .Digest(Digest::NONE)
+                                .SetDefaultValidity(),
+                        KeyFormat::RAW, ed25519_key));
+}
+
+/*
+ * ImportKeyTest.Ed25519FormatMismatch
+ *
+ * Verifies that importing an Ed25519 key pair with an invalid format fails.
+ */
+TEST_P(ImportKeyTest, Ed25519FormatMismatch) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaSigningKey(EcCurve::CURVE_25519)
+                                               .Digest(Digest::NONE)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, ed25519_key));
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaSigningKey(EcCurve::CURVE_25519)
+                                               .Digest(Digest::NONE)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::RAW, ed25519_pkcs8_key));
+}
+
+/*
+ * ImportKeyTest.Ed25519PurposeMismatch
+ *
+ * Verifies that importing an Ed25519 key pair with an invalid purpose fails.
+ */
+TEST_P(ImportKeyTest, Ed25519PurposeMismatch) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    // Can't have both SIGN and ATTEST_KEY
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaSigningKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY)
+                                               .Digest(Digest::NONE)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::RAW, ed25519_key));
+    // AGREE_KEY is for X25519 (but can only tell the difference if the import key is in
+    // PKCS#8 format and so includes an OID).
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                               .Digest(Digest::NONE)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, ed25519_pkcs8_key));
+}
+
+/*
+ * ImportKeyTest.X25519RawSuccess
+ *
+ * Verifies that importing and using a raw X25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, X25519RawSuccess) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::RAW, x25519_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+    CheckOrigin();
+}
+
+/*
+ * ImportKeyTest.X25519Pkcs8Success
+ *
+ * Verifies that importing and using a PKCS#8-encoded X25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, X25519Pkcs8Success) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, x25519_pkcs8_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+    CheckOrigin();
+}
+
+/*
+ * ImportKeyTest.X25519CurveMismatch
+ *
+ * Verifies that importing an X25519 key with a curve that doesn't match the key fails in
+ * the correct way.
+ */
+TEST_P(ImportKeyTest, X25519CurveMismatch) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaKey(EcCurve::P_224 /* Doesn't match key */)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::RAW, x25519_key));
+}
+
+/*
+ * ImportKeyTest.X25519FormatMismatch
+ *
+ * Verifies that importing an X25519 key with an invalid format fails.
+ */
+TEST_P(ImportKeyTest, X25519FormatMismatch) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, x25519_key));
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::RAW, x25519_pkcs8_key));
+}
+
+/*
+ * ImportKeyTest.X25519PurposeMismatch
+ *
+ * Verifies that importing an X25519 key pair with an invalid format fails.
+ */
+TEST_P(ImportKeyTest, X25519PurposeMismatch) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, x25519_pkcs8_key));
+    ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .EcdsaSigningKey(EcCurve::CURVE_25519)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, x25519_pkcs8_key));
+}
+
+/*
  * ImportKeyTest.AesSuccess
  *
  * Verifies that importing and using an AES key works.
@@ -4509,8 +5218,10 @@
     auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
 
     // Try various message lengths; all should work.
-    for (size_t i = 0; i < 32; ++i) {
-        string message(i, 'a');
+    for (size_t i = 0; i <= 48; i++) {
+        SCOPED_TRACE(testing::Message() << "i = " << i);
+        // Edge case: '\t' (0x09) is also a valid PKCS7 padding character.
+        string message(i, '\t');
         string ciphertext = EncryptMessage(message, params);
         EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
         string plaintext = DecryptMessage(ciphertext, params);
@@ -4534,7 +5245,7 @@
     auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
 
     // Try various message lengths; all should fail
-    for (size_t i = 0; i < 32; ++i) {
+    for (size_t i = 0; i <= 48; i++) {
         string message(i, 'a');
         EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
     }
@@ -5719,8 +6430,8 @@
 
     ASSERT_GT(key_blob_.size(), 0U);
 
-    // Two-block message.
-    string message = "1234567890123456";
+    // Four-block message.
+    string message = "12345678901234561234567890123456";
     vector<uint8_t> iv1;
     string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv1);
     EXPECT_EQ(message.size(), ciphertext1.size());
@@ -5880,8 +6591,10 @@
                                                  .Padding(PaddingMode::PKCS7)));
 
     // Try various message lengths; all should work.
-    for (size_t i = 0; i < 32; ++i) {
-        string message(i, 'a');
+    for (size_t i = 0; i <= 32; i++) {
+        SCOPED_TRACE(testing::Message() << "i = " << i);
+        // Edge case: '\t' (0x09) is also a valid PKCS7 padding character, albeit not for 3DES.
+        string message(i, '\t');
         vector<uint8_t> iv;
         string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
         EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
@@ -5903,7 +6616,7 @@
                                                  .Padding(PaddingMode::NONE)));
 
     // Try various message lengths; all should fail.
-    for (size_t i = 0; i < 32; ++i) {
+    for (size_t i = 0; i <= 32; i++) {
         auto begin_params =
                 AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7);
         EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
@@ -5934,6 +6647,7 @@
                                 .Authorization(TAG_NONCE, iv);
 
     for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
+        SCOPED_TRACE(testing::Message() << "i = " << i);
         ++ciphertext[ciphertext.size() / 2];
         EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
         string plaintext;
@@ -6599,9 +7313,7 @@
 
 INSTANTIATE_KEYMINT_AIDL_TEST(TransportLimitTest);
 
-typedef KeyMintAidlTestBase KeyAgreementTest;
-
-int CurveToOpenSslCurveName(EcCurve curve) {
+static int EcdhCurveToOpenSslCurveName(EcCurve curve) {
     switch (curve) {
         case EcCurve::P_224:
             return NID_secp224r1;
@@ -6611,13 +7323,113 @@
             return NID_secp384r1;
         case EcCurve::P_521:
             return NID_secp521r1;
+        case EcCurve::CURVE_25519:
+            return NID_X25519;
     }
 }
 
+class KeyAgreementTest : public KeyMintAidlTestBase {
+  protected:
+    void GenerateLocalEcKey(EcCurve localCurve, EVP_PKEY_Ptr* localPrivKey,
+                            std::vector<uint8_t>* localPublicKey) {
+        // Generate EC key locally (with access to private key material)
+        if (localCurve == EcCurve::CURVE_25519) {
+            uint8_t privKeyData[32];
+            uint8_t pubKeyData[32];
+            X25519_keypair(pubKeyData, privKeyData);
+            *localPublicKey = vector<uint8_t>(pubKeyData, pubKeyData + 32);
+            *localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new_raw_private_key(
+                    EVP_PKEY_X25519, nullptr, privKeyData, sizeof(privKeyData)));
+        } else {
+            auto ecKey = EC_KEY_Ptr(EC_KEY_new());
+            int curveName = EcdhCurveToOpenSslCurveName(localCurve);
+            auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curveName));
+            ASSERT_NE(group, nullptr);
+            ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
+            ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1);
+            *localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new());
+            ASSERT_EQ(EVP_PKEY_set1_EC_KEY(localPrivKey->get(), ecKey.get()), 1);
+
+            // Get encoded form of the public part of the locally generated key...
+            unsigned char* p = nullptr;
+            int localPublicKeySize = i2d_PUBKEY(localPrivKey->get(), &p);
+            ASSERT_GT(localPublicKeySize, 0);
+            *localPublicKey =
+                    vector<uint8_t>(reinterpret_cast<const uint8_t*>(p),
+                                    reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
+            OPENSSL_free(p);
+        }
+    }
+
+    void GenerateKeyMintEcKey(EcCurve curve, EVP_PKEY_Ptr* kmPubKey) {
+        vector<uint8_t> challenge = {0x41, 0x42};
+        ErrorCode result =
+                GenerateKey(AuthorizationSetBuilder()
+                                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                                    .Authorization(TAG_EC_CURVE, curve)
+                                    .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                    .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                    .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62})
+                                    .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+                                    .SetDefaultValidity());
+        ASSERT_EQ(ErrorCode::OK, result) << "Failed to generate key";
+        ASSERT_GT(cert_chain_.size(), 0);
+        X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+        ASSERT_NE(kmKeyCert, nullptr);
+        // Check that keyAgreement (bit 4) is set in KeyUsage
+        EXPECT_TRUE((X509_get_key_usage(kmKeyCert.get()) & X509v3_KU_KEY_AGREEMENT) != 0);
+        *kmPubKey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get()));
+        ASSERT_NE(*kmPubKey, nullptr);
+        if (dump_Attestations) {
+            for (size_t n = 0; n < cert_chain_.size(); n++) {
+                std::cout << bin2hex(cert_chain_[n].encodedCertificate) << std::endl;
+            }
+        }
+    }
+
+    void CheckAgreement(EVP_PKEY_Ptr kmPubKey, EVP_PKEY_Ptr localPrivKey,
+                        const std::vector<uint8_t>& localPublicKey) {
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+        string ZabFromKeyMintStr;
+        ASSERT_EQ(ErrorCode::OK,
+                  Finish(string(localPublicKey.begin(), localPublicKey.end()), &ZabFromKeyMintStr));
+        vector<uint8_t> ZabFromKeyMint(ZabFromKeyMintStr.begin(), ZabFromKeyMintStr.end());
+        vector<uint8_t> ZabFromTest;
+
+        if (EVP_PKEY_id(kmPubKey.get()) == EVP_PKEY_X25519) {
+            size_t kmPubKeySize = 32;
+            uint8_t kmPubKeyData[32];
+            ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+            ASSERT_EQ(kmPubKeySize, 32);
+
+            uint8_t localPrivKeyData[32];
+            size_t localPrivKeySize = 32;
+            ASSERT_EQ(1, EVP_PKEY_get_raw_private_key(localPrivKey.get(), localPrivKeyData,
+                                                      &localPrivKeySize));
+            ASSERT_EQ(localPrivKeySize, 32);
+
+            uint8_t sharedKey[32];
+            ASSERT_EQ(1, X25519(sharedKey, localPrivKeyData, kmPubKeyData));
+            ZabFromTest = std::vector<uint8_t>(sharedKey, sharedKey + 32);
+        } else {
+            // Perform local ECDH between the two keys so we can check if we get the same Zab..
+            auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(localPrivKey.get(), nullptr));
+            ASSERT_NE(ctx, nullptr);
+            ASSERT_EQ(EVP_PKEY_derive_init(ctx.get()), 1);
+            ASSERT_EQ(EVP_PKEY_derive_set_peer(ctx.get(), kmPubKey.get()), 1);
+            size_t ZabFromTestLen = 0;
+            ASSERT_EQ(EVP_PKEY_derive(ctx.get(), nullptr, &ZabFromTestLen), 1);
+            ZabFromTest.resize(ZabFromTestLen);
+            ASSERT_EQ(EVP_PKEY_derive(ctx.get(), ZabFromTest.data(), &ZabFromTestLen), 1);
+        }
+        EXPECT_EQ(ZabFromKeyMint, ZabFromTest);
+    }
+};
+
 /*
  * KeyAgreementTest.Ecdh
  *
- * Verifies that ECDH works for all curves
+ * Verifies that ECDH works for all required curves
  */
 TEST_P(KeyAgreementTest, Ecdh) {
     // Because it's possible to use this API with keys on different curves, we
@@ -6631,49 +7443,13 @@
     for (auto curve : ValidCurves()) {
         for (auto localCurve : ValidCurves()) {
             // Generate EC key locally (with access to private key material)
-            auto ecKey = EC_KEY_Ptr(EC_KEY_new());
-            int curveName = CurveToOpenSslCurveName(localCurve);
-            auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curveName));
-            ASSERT_NE(group, nullptr);
-            ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
-            ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1);
-            auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
-            ASSERT_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()), 1);
-
-            // Get encoded form of the public part of the locally generated key...
-            unsigned char* p = nullptr;
-            int encodedPublicKeySize = i2d_PUBKEY(pkey.get(), &p);
-            ASSERT_GT(encodedPublicKeySize, 0);
-            vector<uint8_t> encodedPublicKey(
-                    reinterpret_cast<const uint8_t*>(p),
-                    reinterpret_cast<const uint8_t*>(p + encodedPublicKeySize));
-            OPENSSL_free(p);
+            EVP_PKEY_Ptr localPrivKey;
+            vector<uint8_t> localPublicKey;
+            GenerateLocalEcKey(localCurve, &localPrivKey, &localPublicKey);
 
             // Generate EC key in KeyMint (only access to public key material)
-            vector<uint8_t> challenge = {0x41, 0x42};
-            EXPECT_EQ(
-                    ErrorCode::OK,
-                    GenerateKey(AuthorizationSetBuilder()
-                                        .Authorization(TAG_NO_AUTH_REQUIRED)
-                                        .Authorization(TAG_EC_CURVE, curve)
-                                        .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
-                                        .Authorization(TAG_ALGORITHM, Algorithm::EC)
-                                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62})
-                                        .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
-                                        .SetDefaultValidity()))
-                    << "Failed to generate key";
-            ASSERT_GT(cert_chain_.size(), 0);
-            X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
-            ASSERT_NE(kmKeyCert, nullptr);
-            // Check that keyAgreement (bit 4) is set in KeyUsage
-            EXPECT_TRUE((X509_get_key_usage(kmKeyCert.get()) & X509v3_KU_KEY_AGREEMENT) != 0);
-            auto kmPkey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get()));
-            ASSERT_NE(kmPkey, nullptr);
-            if (dump_Attestations) {
-                for (size_t n = 0; n < cert_chain_.size(); n++) {
-                    std::cout << bin2hex(cert_chain_[n].encodedCertificate) << std::endl;
-                }
-            }
+            EVP_PKEY_Ptr kmPubKey;
+            GenerateKeyMintEcKey(curve, &kmPubKey);
 
             // Now that we have the two keys, we ask KeyMint to perform ECDH...
             if (curve != localCurve) {
@@ -6682,30 +7458,12 @@
                 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
                 string ZabFromKeyMintStr;
                 EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
-                          Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
+                          Finish(string(localPublicKey.begin(), localPublicKey.end()),
                                  &ZabFromKeyMintStr));
 
             } else {
                 // Otherwise if the keys are using the same curve, it should work.
-                EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
-                string ZabFromKeyMintStr;
-                EXPECT_EQ(ErrorCode::OK,
-                          Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
-                                 &ZabFromKeyMintStr));
-                vector<uint8_t> ZabFromKeyMint(ZabFromKeyMintStr.begin(), ZabFromKeyMintStr.end());
-
-                // Perform local ECDH between the two keys so we can check if we get the same Zab..
-                auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(pkey.get(), nullptr));
-                ASSERT_NE(ctx, nullptr);
-                ASSERT_EQ(EVP_PKEY_derive_init(ctx.get()), 1);
-                ASSERT_EQ(EVP_PKEY_derive_set_peer(ctx.get(), kmPkey.get()), 1);
-                size_t ZabFromTestLen = 0;
-                ASSERT_EQ(EVP_PKEY_derive(ctx.get(), nullptr, &ZabFromTestLen), 1);
-                vector<uint8_t> ZabFromTest;
-                ZabFromTest.resize(ZabFromTestLen);
-                ASSERT_EQ(EVP_PKEY_derive(ctx.get(), ZabFromTest.data(), &ZabFromTestLen), 1);
-
-                EXPECT_EQ(ZabFromKeyMint, ZabFromTest);
+                CheckAgreement(std::move(kmPubKey), std::move(localPrivKey), localPublicKey);
             }
 
             CheckedDeleteKey();
@@ -6713,6 +7471,140 @@
     }
 }
 
+/*
+ * KeyAgreementTest.EcdhCurve25519
+ *
+ * Verifies that ECDH works for curve25519. This is also covered by the general
+ * KeyAgreementTest.Ecdh case, but is pulled out separately here because this curve was added after
+ * KeyMint 1.0.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    // Generate EC key in KeyMint (only access to public key material)
+    EcCurve curve = EcCurve::CURVE_25519;
+    EVP_PKEY_Ptr kmPubKey = nullptr;
+    GenerateKeyMintEcKey(curve, &kmPubKey);
+
+    // Generate EC key on same curve locally (with access to private key material).
+    EVP_PKEY_Ptr privKey;
+    vector<uint8_t> encodedPublicKey;
+    GenerateLocalEcKey(curve, &privKey, &encodedPublicKey);
+
+    // Agree on a key between local and KeyMint and check it.
+    CheckAgreement(std::move(kmPubKey), std::move(privKey), encodedPublicKey);
+
+    CheckedDeleteKey();
+}
+
+/*
+ * KeyAgreementTest.EcdhCurve25519Imported
+ *
+ * Verifies that ECDH works for an imported curve25519 key.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519Imported) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    // Import x25519 key into KeyMint.
+    EcCurve curve = EcCurve::CURVE_25519;
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaKey(EcCurve::CURVE_25519)
+                                               .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, x25519_pkcs8_key));
+    ASSERT_GT(cert_chain_.size(), 0);
+    X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+    ASSERT_NE(kmKeyCert, nullptr);
+    EVP_PKEY_Ptr kmPubKey(X509_get_pubkey(kmKeyCert.get()));
+    ASSERT_NE(kmPubKey.get(), nullptr);
+
+    // Expect the import to emit corresponding public key data.
+    size_t kmPubKeySize = 32;
+    uint8_t kmPubKeyData[32];
+    ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+    ASSERT_EQ(kmPubKeySize, 32);
+    EXPECT_EQ(bin2hex(std::vector<uint8_t>(kmPubKeyData, kmPubKeyData + 32)),
+              bin2hex(std::vector<uint8_t>(x25519_pubkey.begin(), x25519_pubkey.end())));
+
+    // Generate EC key on same curve locally (with access to private key material).
+    EVP_PKEY_Ptr privKey;
+    vector<uint8_t> encodedPublicKey;
+    GenerateLocalEcKey(curve, &privKey, &encodedPublicKey);
+
+    // Agree on a key between local and KeyMint and check it.
+    CheckAgreement(std::move(kmPubKey), std::move(privKey), encodedPublicKey);
+
+    CheckedDeleteKey();
+}
+
+/*
+ * KeyAgreementTest.EcdhCurve25519InvalidSize
+ *
+ * Verifies that ECDH fails for curve25519 if the wrong size of public key is provided.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519InvalidSize) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    // Generate EC key in KeyMint (only access to public key material)
+    EcCurve curve = EcCurve::CURVE_25519;
+    EVP_PKEY_Ptr kmPubKey = nullptr;
+    GenerateKeyMintEcKey(curve, &kmPubKey);
+
+    // Generate EC key on same curve locally (with access to private key material).
+    EVP_PKEY_Ptr privKey;
+    vector<uint8_t> encodedPublicKey;
+    GenerateLocalEcKey(curve, &privKey, &encodedPublicKey);
+
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+    string ZabFromKeyMintStr;
+    // Send in an incomplete public key.
+    ASSERT_NE(ErrorCode::OK, Finish(string(encodedPublicKey.begin(), encodedPublicKey.end() - 1),
+                                    &ZabFromKeyMintStr));
+
+    CheckedDeleteKey();
+}
+
+/*
+ * KeyAgreementTest.EcdhCurve25519Mismatch
+ *
+ * Verifies that ECDH fails between curve25519 and other curves.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519Mismatch) {
+    if (!Curve25519Supported()) {
+        GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+    }
+
+    // Generate EC key in KeyMint (only access to public key material)
+    EcCurve curve = EcCurve::CURVE_25519;
+    EVP_PKEY_Ptr kmPubKey = nullptr;
+    GenerateKeyMintEcKey(curve, &kmPubKey);
+
+    for (auto localCurve : ValidCurves()) {
+        if (localCurve == curve) {
+            continue;
+        }
+        // Generate EC key on a different curve locally (with access to private key material).
+        EVP_PKEY_Ptr privKey;
+        vector<uint8_t> encodedPublicKey;
+        GenerateLocalEcKey(localCurve, &privKey, &encodedPublicKey);
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+        string ZabFromKeyMintStr;
+        EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
+                  Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
+                         &ZabFromKeyMintStr));
+    }
+
+    CheckedDeleteKey();
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(KeyAgreementTest);
 
 using DestroyAttestationIdsTest = KeyMintAidlTestBase;
@@ -6914,6 +7806,12 @@
             } else {
                 std::cout << "NOT dumping attestations" << std::endl;
             }
+            if (std::string(argv[i]) == "--skip_boot_pl_check") {
+                // Allow checks of BOOT_PATCHLEVEL to be disabled, so that the tests can
+                // be run in emulated environments that don't have the normal bootloader
+                // interactions.
+                aidl::android::hardware::security::keymint::test::check_boot_pl = false;
+            }
         }
     }
     return RUN_ALL_TESTS();
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 76fb79b..829780d 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -20,6 +20,7 @@
 #include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
 #include <aidl/android/hardware/security/keymint/SecurityLevel.h>
 #include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
 #include <cppbor_parse.h>
 #include <gmock/gmock.h>
 #include <keymaster/cppcose/cppcose.h>
@@ -29,6 +30,7 @@
 #include <openssl/ec_key.h>
 #include <openssl/x509.h>
 #include <remote_prov/remote_prov_utils.h>
+#include <set>
 #include <vector>
 
 #include "KeyMintAidlTestBase.h"
@@ -40,6 +42,8 @@
 
 namespace {
 
+constexpr int32_t VERSION_WITH_UNIQUE_ID_SUPPORT = 2;
+
 #define INSTANTIATE_REM_PROV_AIDL_TEST(name)                                         \
     GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);                             \
     INSTANTIATE_TEST_SUITE_P(                                                        \
@@ -47,6 +51,7 @@
             testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
             ::android::PrintInstanceNameToString)
 
+using ::android::sp;
 using bytevec = std::vector<uint8_t>;
 using testing::MatchesRegex;
 using namespace remote_prov;
@@ -175,6 +180,67 @@
     std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
 };
 
+/**
+ * Verify that every implementation reports a different unique id.
+ */
+TEST(NonParameterizedTests, eachRpcHasAUniqueId) {
+    std::set<std::string> uniqueIds;
+    for (auto hal : ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor)) {
+        ASSERT_TRUE(AServiceManager_isDeclared(hal.c_str()));
+        ::ndk::SpAIBinder binder(AServiceManager_waitForService(hal.c_str()));
+        std::shared_ptr<IRemotelyProvisionedComponent> rpc =
+                IRemotelyProvisionedComponent::fromBinder(binder);
+        ASSERT_NE(rpc, nullptr);
+
+        RpcHardwareInfo hwInfo;
+        ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
+
+        int32_t version;
+        ASSERT_TRUE(rpc->getInterfaceVersion(&version).isOk());
+        if (version >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
+            ASSERT_TRUE(hwInfo.uniqueId);
+            auto [_, wasInserted] = uniqueIds.insert(*hwInfo.uniqueId);
+            EXPECT_TRUE(wasInserted);
+        } else {
+            ASSERT_FALSE(hwInfo.uniqueId);
+        }
+    }
+}
+
+using GetHardwareInfoTests = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(GetHardwareInfoTests);
+
+/**
+ * Verify that a valid curve is reported by the implementation.
+ */
+TEST_P(GetHardwareInfoTests, supportsValidCurve) {
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+
+    const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
+    ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
+            << "Invalid curve: " << hwInfo.supportedEekCurve;
+}
+
+/**
+ * Verify that the unique id is within the length limits as described in RpcHardwareInfo.aidl.
+ */
+TEST_P(GetHardwareInfoTests, uniqueId) {
+    int32_t version;
+    ASSERT_TRUE(provisionable_->getInterfaceVersion(&version).isOk());
+
+    if (version < VERSION_WITH_UNIQUE_ID_SUPPORT) {
+        return;
+    }
+
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+    ASSERT_TRUE(hwInfo.uniqueId);
+    EXPECT_GE(hwInfo.uniqueId->size(), 1);
+    EXPECT_LE(hwInfo.uniqueId->size(), 32);
+}
+
 using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
 
 INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
@@ -236,9 +302,11 @@
     vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
     EXPECT_EQ(attested_key_cert_chain.size(), 1);
 
+    int32_t aidl_version = 0;
+    ASSERT_TRUE(keyMint->getInterfaceVersion(&aidl_version).isOk());
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced,
+    EXPECT_TRUE(verify_attestation_record(aidl_version, "foo", "bar", sw_enforced, hw_enforced,
                                           info.securityLevel,
                                           attested_key_cert_chain[0].encodedCertificate));
 
diff --git a/security/keymint/aidl/vts/performance/Android.bp b/security/keymint/aidl/vts/performance/Android.bp
index 355f87b..7e3a3e5 100644
--- a/security/keymint/aidl/vts/performance/Android.bp
+++ b/security/keymint/aidl/vts/performance/Android.bp
@@ -27,6 +27,7 @@
     name: "VtsAidlKeyMintBenchmarkTest",
     defaults: [
         "VtsHalTargetTestDefaults",
+        "keymint_use_latest_hal_aidl_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
     ],
     srcs: [
@@ -39,7 +40,6 @@
         "libkeymint_support",
     ],
     static_libs: [
-        "android.hardware.security.keymint-V1-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libcppbor_external",
         "libchrome",
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index e162934..36969bb 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -40,8 +40,10 @@
     export_include_dirs: [
         "include",
     ],
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
     shared_libs: [
-        "android.hardware.security.keymint-V1-ndk",
         "libbase",
         "libcrypto",
         "libutils",
diff --git a/security/secureclock/aidl/vts/functional/Android.bp b/security/secureclock/aidl/vts/functional/Android.bp
index 806517d..a34668b 100644
--- a/security/secureclock/aidl/vts/functional/Android.bp
+++ b/security/secureclock/aidl/vts/functional/Android.bp
@@ -27,6 +27,7 @@
     name: "VtsAidlSecureClockTargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
+        "keymint_use_latest_hal_aidl_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
     ],
     cflags: [
@@ -41,7 +42,6 @@
         "libcrypto",
     ],
     static_libs: [
-        "android.hardware.security.keymint-V1-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libkeymint",
     ],
diff --git a/security/sharedsecret/aidl/vts/functional/Android.bp b/security/sharedsecret/aidl/vts/functional/Android.bp
index 94da675..1f0f6a6 100644
--- a/security/sharedsecret/aidl/vts/functional/Android.bp
+++ b/security/sharedsecret/aidl/vts/functional/Android.bp
@@ -27,6 +27,7 @@
     name: "VtsAidlSharedSecretTargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
+        "keymint_use_latest_hal_aidl_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
     ],
     srcs: [
@@ -41,7 +42,6 @@
         "libcrypto",
     ],
     static_libs: [
-        "android.hardware.security.keymint-V1-ndk",
         "android.hardware.security.sharedsecret-V1-ndk",
         "libkeymint",
     ],
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 53ceb0d..43ee327 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -190,8 +190,6 @@
         }
 
         default: {
-            CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
             memcpy(dst->u.data.data(), src.data, 16 * sizeof(float));
             break;
         }
@@ -330,9 +328,6 @@
         }
 
         default: {
-            CHECK_GE((int32_t)src.sensorType,
-                     (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
             memcpy(dst->data, src.u.data.data(), 16 * sizeof(float));
             break;
         }
diff --git a/sensors/aidl/Android.bp b/sensors/aidl/Android.bp
new file mode 100644
index 0000000..92b7ad0
--- /dev/null
+++ b/sensors/aidl/Android.bp
@@ -0,0 +1,32 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.sensors",
+    vendor_available: true,
+    srcs: ["android/hardware/sensors/*.aidl"],
+    imports: [
+        "android.hardware.common-V2",
+        "android.hardware.common.fmq-V1",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/AdditionalInfo.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/AdditionalInfo.aidl
new file mode 100644
index 0000000..5184723
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/AdditionalInfo.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.sensors;
+@FixedSize @VintfStability
+parcelable AdditionalInfo {
+  android.hardware.sensors.AdditionalInfo.AdditionalInfoType type;
+  int serial;
+  android.hardware.sensors.AdditionalInfo.AdditionalInfoPayload payload;
+  @FixedSize @VintfStability
+  union AdditionalInfoPayload {
+    android.hardware.sensors.AdditionalInfo.AdditionalInfoPayload.Int32Values dataInt32;
+    android.hardware.sensors.AdditionalInfo.AdditionalInfoPayload.FloatValues dataFloat;
+    @FixedSize @VintfStability
+    parcelable Int32Values {
+      int[14] values;
+    }
+    @FixedSize @VintfStability
+    parcelable FloatValues {
+      float[14] values;
+    }
+  }
+  @Backing(type="int") @VintfStability
+  enum AdditionalInfoType {
+    AINFO_BEGIN = 0,
+    AINFO_END = 1,
+    AINFO_UNTRACKED_DELAY = 65536,
+    AINFO_INTERNAL_TEMPERATURE = 65537,
+    AINFO_VEC3_CALIBRATION = 65538,
+    AINFO_SENSOR_PLACEMENT = 65539,
+    AINFO_SAMPLING = 65540,
+    AINFO_CHANNEL_NOISE = 131072,
+    AINFO_CHANNEL_SAMPLER = 131073,
+    AINFO_CHANNEL_FILTER = 131074,
+    AINFO_CHANNEL_LINEAR_TRANSFORM = 131075,
+    AINFO_CHANNEL_NONLINEAR_MAP = 131076,
+    AINFO_CHANNEL_RESAMPLER = 131077,
+    AINFO_LOCAL_GEOMAGNETIC_FIELD = 196608,
+    AINFO_LOCAL_GRAVITY = 196609,
+    AINFO_DOCK_STATE = 196610,
+    AINFO_HIGH_PERFORMANCE_MODE = 196611,
+    AINFO_MAGNETIC_FIELD_CALIBRATION = 196612,
+    AINFO_CUSTOM_START = 268435456,
+    AINFO_DEBUGGING_START = 1073741824,
+  }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/DynamicSensorInfo.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/DynamicSensorInfo.aidl
new file mode 100644
index 0000000..0c9a493
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/DynamicSensorInfo.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.sensors;
+@FixedSize @VintfStability
+parcelable DynamicSensorInfo {
+  boolean connected;
+  int sensorHandle;
+  android.hardware.sensors.DynamicSensorInfo.Uuid uuid;
+  @FixedSize @VintfStability
+  parcelable Uuid {
+    byte[16] values;
+  }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl
new file mode 100644
index 0000000..4f49002
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.sensors;
+@FixedSize @VintfStability
+parcelable Event {
+  long timestamp;
+  int sensorHandle;
+  android.hardware.sensors.SensorType sensorType;
+  android.hardware.sensors.Event.EventPayload payload;
+  @FixedSize @VintfStability
+  union EventPayload {
+    android.hardware.sensors.Event.EventPayload.Vec3 vec3;
+    android.hardware.sensors.Event.EventPayload.Vec4 vec4;
+    android.hardware.sensors.Event.EventPayload.Uncal uncal;
+    android.hardware.sensors.Event.EventPayload.MetaData meta;
+    float scalar;
+    long stepCount;
+    android.hardware.sensors.Event.EventPayload.HeartRate heartRate;
+    android.hardware.sensors.Event.EventPayload.Pose6Dof pose6DOF;
+    android.hardware.sensors.DynamicSensorInfo dynamic;
+    android.hardware.sensors.AdditionalInfo additional;
+    android.hardware.sensors.Event.EventPayload.Data data;
+    android.hardware.sensors.Event.EventPayload.HeadTracker headTracker;
+    android.hardware.sensors.Event.EventPayload.LimitedAxesImu limitedAxesImu;
+    android.hardware.sensors.Event.EventPayload.LimitedAxesImuUncal limitedAxesImuUncal;
+    android.hardware.sensors.Event.EventPayload.Heading heading;
+    @FixedSize @VintfStability
+    parcelable Vec4 {
+      float x;
+      float y;
+      float z;
+      float w;
+    }
+    @FixedSize @VintfStability
+    parcelable Vec3 {
+      float x;
+      float y;
+      float z;
+      android.hardware.sensors.SensorStatus status;
+    }
+    @FixedSize @VintfStability
+    parcelable Uncal {
+      float x;
+      float y;
+      float z;
+      float xBias;
+      float yBias;
+      float zBias;
+    }
+    @FixedSize @VintfStability
+    parcelable HeadTracker {
+      float rx;
+      float ry;
+      float rz;
+      float vx;
+      float vy;
+      float vz;
+      int discontinuityCount;
+    }
+    @FixedSize @VintfStability
+    parcelable LimitedAxesImu {
+      float x;
+      float y;
+      float z;
+      float xSupported;
+      float ySupported;
+      float zSupported;
+    }
+    @FixedSize @VintfStability
+    parcelable LimitedAxesImuUncal {
+      float x;
+      float y;
+      float z;
+      float xBias;
+      float yBias;
+      float zBias;
+      float xSupported;
+      float ySupported;
+      float zSupported;
+    }
+    @FixedSize @VintfStability
+    parcelable HeartRate {
+      float bpm;
+      android.hardware.sensors.SensorStatus status;
+    }
+    @FixedSize @VintfStability
+    parcelable Heading {
+      float heading;
+      float accuracy;
+    }
+    @FixedSize @VintfStability
+    parcelable MetaData {
+      android.hardware.sensors.Event.EventPayload.MetaData.MetaDataEventType what;
+      @Backing(type="int") @VintfStability
+      enum MetaDataEventType {
+        META_DATA_FLUSH_COMPLETE = 1,
+      }
+    }
+    @FixedSize @VintfStability
+    parcelable Pose6Dof {
+      float[15] values;
+    }
+    @FixedSize @VintfStability
+    parcelable Data {
+      float[16] values;
+    }
+  }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
new file mode 100644
index 0000000..f60f5bb
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@VintfStability
+interface ISensors {
+  void activate(in int sensorHandle, in boolean enabled);
+  void batch(in int sensorHandle, in long samplingPeriodNs, in long maxReportLatencyNs);
+  int configDirectReport(in int sensorHandle, in int channelHandle, in android.hardware.sensors.ISensors.RateLevel rate);
+  void flush(in int sensorHandle);
+  android.hardware.sensors.SensorInfo[] getSensorsList();
+  void initialize(in android.hardware.common.fmq.MQDescriptor<android.hardware.sensors.Event,android.hardware.common.fmq.SynchronizedReadWrite> eventQueueDescriptor, in android.hardware.common.fmq.MQDescriptor<int,android.hardware.common.fmq.SynchronizedReadWrite> wakeLockDescriptor, in android.hardware.sensors.ISensorsCallback sensorsCallback);
+  void injectSensorData(in android.hardware.sensors.Event event);
+  int registerDirectChannel(in android.hardware.sensors.ISensors.SharedMemInfo mem);
+  void setOperationMode(in android.hardware.sensors.ISensors.OperationMode mode);
+  void unregisterDirectChannel(in int channelHandle);
+  const int ERROR_NO_MEMORY = -12;
+  const int ERROR_BAD_VALUE = -22;
+  const int WAKE_LOCK_TIMEOUT_SECONDS = 1;
+  const int EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS = 1;
+  const int EVENT_QUEUE_FLAG_BITS_EVENTS_READ = 2;
+  const int WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN = 1;
+  const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_FIELD = 0;
+  const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_REPORT_TOKEN = 4;
+  const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_SENSOR_TYPE = 8;
+  const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_ATOMIC_COUNTER = 12;
+  const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_TIMESTAMP = 16;
+  const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 24;
+  const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 88;
+  const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+  @Backing(type="int") @VintfStability
+  enum RateLevel {
+    STOP = 0,
+    NORMAL = 1,
+    FAST = 2,
+    VERY_FAST = 3,
+  }
+  @Backing(type="int") @VintfStability
+  enum OperationMode {
+    NORMAL = 0,
+    DATA_INJECTION = 1,
+  }
+  @VintfStability
+  parcelable SharedMemInfo {
+    android.hardware.sensors.ISensors.SharedMemInfo.SharedMemType type;
+    android.hardware.sensors.ISensors.SharedMemInfo.SharedMemFormat format;
+    int size;
+    android.hardware.common.NativeHandle memoryHandle;
+    @Backing(type="int") @VintfStability
+    enum SharedMemFormat {
+      SENSORS_EVENT = 1,
+    }
+    @Backing(type="int") @VintfStability
+    enum SharedMemType {
+      ASHMEM = 1,
+      GRALLOC = 2,
+    }
+  }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensorsCallback.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensorsCallback.aidl
new file mode 100644
index 0000000..78ab567
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensorsCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.sensors;
+@VintfStability
+interface ISensorsCallback {
+  void onDynamicSensorsConnected(in android.hardware.sensors.SensorInfo[] sensorInfos);
+  void onDynamicSensorsDisconnected(in int[] sensorHandles);
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorInfo.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorInfo.aidl
new file mode 100644
index 0000000..996be3d
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorInfo.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@VintfStability
+parcelable SensorInfo {
+  int sensorHandle;
+  String name;
+  String vendor;
+  int version;
+  android.hardware.sensors.SensorType type;
+  String typeAsString;
+  float maxRange;
+  float resolution;
+  float power;
+  int minDelayUs;
+  int fifoReservedEventCount;
+  int fifoMaxEventCount;
+  String requiredPermission;
+  int maxDelayUs;
+  int flags;
+  const int SENSOR_FLAG_BITS_WAKE_UP = 1;
+  const int SENSOR_FLAG_BITS_CONTINUOUS_MODE = 0;
+  const int SENSOR_FLAG_BITS_ON_CHANGE_MODE = 2;
+  const int SENSOR_FLAG_BITS_ONE_SHOT_MODE = 4;
+  const int SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE = 6;
+  const int SENSOR_FLAG_BITS_DATA_INJECTION = 16;
+  const int SENSOR_FLAG_BITS_DYNAMIC_SENSOR = 32;
+  const int SENSOR_FLAG_BITS_ADDITIONAL_INFO = 64;
+  const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM = 1024;
+  const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_GRALLOC = 2048;
+  const int SENSOR_FLAG_BITS_MASK_REPORTING_MODE = 14;
+  const int SENSOR_FLAG_BITS_MASK_DIRECT_REPORT = 896;
+  const int SENSOR_FLAG_BITS_MASK_DIRECT_CHANNEL = 3072;
+  const int SENSOR_FLAG_SHIFT_REPORTING_MODE = 1;
+  const int SENSOR_FLAG_SHIFT_DATA_INJECTION = 4;
+  const int SENSOR_FLAG_SHIFT_DYNAMIC_SENSOR = 5;
+  const int SENSOR_FLAG_SHIFT_ADDITIONAL_INFO = 6;
+  const int SENSOR_FLAG_SHIFT_DIRECT_REPORT = 7;
+  const int SENSOR_FLAG_SHIFT_DIRECT_CHANNEL = 10;
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorStatus.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorStatus.aidl
new file mode 100644
index 0000000..4521710
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorStatus.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@Backing(type="byte") @VintfStability
+enum SensorStatus {
+  NO_CONTACT = -1,
+  UNRELIABLE = 0,
+  ACCURACY_LOW = 1,
+  ACCURACY_MEDIUM = 2,
+  ACCURACY_HIGH = 3,
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl
new file mode 100644
index 0000000..8c864e9
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@Backing(type="int") @VintfStability
+enum SensorType {
+  META_DATA = 0,
+  ACCELEROMETER = 1,
+  MAGNETIC_FIELD = 2,
+  ORIENTATION = 3,
+  GYROSCOPE = 4,
+  LIGHT = 5,
+  PRESSURE = 6,
+  PROXIMITY = 8,
+  GRAVITY = 9,
+  LINEAR_ACCELERATION = 10,
+  ROTATION_VECTOR = 11,
+  RELATIVE_HUMIDITY = 12,
+  AMBIENT_TEMPERATURE = 13,
+  MAGNETIC_FIELD_UNCALIBRATED = 14,
+  GAME_ROTATION_VECTOR = 15,
+  GYROSCOPE_UNCALIBRATED = 16,
+  SIGNIFICANT_MOTION = 17,
+  STEP_DETECTOR = 18,
+  STEP_COUNTER = 19,
+  GEOMAGNETIC_ROTATION_VECTOR = 20,
+  HEART_RATE = 21,
+  TILT_DETECTOR = 22,
+  WAKE_GESTURE = 23,
+  GLANCE_GESTURE = 24,
+  PICK_UP_GESTURE = 25,
+  WRIST_TILT_GESTURE = 26,
+  DEVICE_ORIENTATION = 27,
+  POSE_6DOF = 28,
+  STATIONARY_DETECT = 29,
+  MOTION_DETECT = 30,
+  HEART_BEAT = 31,
+  DYNAMIC_SENSOR_META = 32,
+  ADDITIONAL_INFO = 33,
+  LOW_LATENCY_OFFBODY_DETECT = 34,
+  ACCELEROMETER_UNCALIBRATED = 35,
+  HINGE_ANGLE = 36,
+  HEAD_TRACKER = 37,
+  ACCELEROMETER_LIMITED_AXES = 38,
+  GYROSCOPE_LIMITED_AXES = 39,
+  ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40,
+  GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41,
+  HEADING = 42,
+  DEVICE_PRIVATE_BASE = 65536,
+}
diff --git a/sensors/aidl/android/hardware/sensors/AdditionalInfo.aidl b/sensors/aidl/android/hardware/sensors/AdditionalInfo.aidl
new file mode 100644
index 0000000..9fe2d39
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/AdditionalInfo.aidl
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+@FixedSize
+@VintfStability
+parcelable AdditionalInfo {
+    /**
+     * type of payload data, see AdditionalInfoType
+     */
+    AdditionalInfoType type;
+
+    /**
+     * sequence number of this frame for this type
+     */
+    int serial;
+
+    AdditionalInfoPayload payload;
+
+    @FixedSize
+    @VintfStability
+    union AdditionalInfoPayload {
+        Int32Values dataInt32;
+        FloatValues dataFloat;
+
+        @FixedSize
+        @VintfStability
+        parcelable Int32Values {
+            int[14] values;
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable FloatValues {
+            float[14] values;
+        }
+    }
+
+    @VintfStability
+    @Backing(type="int")
+    enum AdditionalInfoType {
+        /**
+         * Marks the beginning of additional information frames
+         */
+        AINFO_BEGIN = 0,
+
+        /**
+         * Marks the end of additional information frames
+         */
+        AINFO_END = 1,
+
+        /**
+         * Estimation of the delay that is not tracked by sensor timestamps. This
+         * includes delay introduced by sensor front-end filtering, data transport,
+         * etc.
+         * float[2]: delay in seconds, standard deviation of estimated value
+         */
+        AINFO_UNTRACKED_DELAY = 0x10000,
+
+        /**
+         * float: Celsius temperature
+         */
+        AINFO_INTERNAL_TEMPERATURE,
+
+        /**
+         * First three rows of a homogeneous matrix, which represents calibration to
+         * a three-element vector raw sensor reading.
+         * float[12]: 3x4 matrix in row major order
+         */
+        AINFO_VEC3_CALIBRATION,
+
+        /**
+         * Provides the orientation and location of the sensor element in terms of
+         * the Android coordinate system. This data is given as a 3x4 matrix
+         * consisting of a 3x3 rotation matrix (R) concatenated with a 3x1 location
+         * vector (t). The rotation matrix provides the orientation of the Android
+         * device coordinate frame relative to the local coordinate frame of the
+         * sensor. Note that assuming the axes conventions of the sensor are the
+         * same as Android, this is the inverse of the matrix applied to raw
+         * samples read from the sensor to convert them into the Android
+         * representation. The location vector represents the translation from the
+         * origin of the Android sensor coordinate system to the geometric center
+         * of the sensor, specified in millimeters (mm).
+         *
+         * float[12]: 3x4 matrix in row major order [R; t]
+         *
+         * Example:
+         *     This raw buffer: {0, 1, 0, 0, -1, 0, 0, 10, 0, 0, 1, -2.5}
+         *     Corresponds to this 3x4 matrix:
+         *         0 1 0    0
+         *        -1 0 0   10
+         *         0 0 1 -2.5
+         *     The sensor is oriented such that:
+         *         - the device X axis corresponds to the sensor's local -Y axis
+         *         - the device Y axis corresponds to the sensor's local X axis
+         *         - the device Z axis and sensor's local Z axis are equivalent
+         *     In other words, if viewing the origin of the Android coordinate
+         *     system from the positive Z direction, the device coordinate frame is
+         *     to be rotated 90 degrees counter-clockwise about the Z axis to align
+         *     with the sensor's local coordinate frame. Equivalently, a vector in
+         *     the Android coordinate frame may be multiplied with R to rotate it
+         *     90 degrees clockwise (270 degrees counter-clockwise), yielding its
+         *     representation in the sensor's coordinate frame.
+         *     Relative to the origin of the Android coordinate system, the physical
+         *     center of the sensor is located 10mm in the positive Y direction, and
+         *     2.5mm in the negative Z direction.
+         */
+        AINFO_SENSOR_PLACEMENT,
+
+        /**
+         * float[2]: raw sample period in seconds,
+         *           standard deviation of sampling period
+         */
+        AINFO_SAMPLING,
+
+        /**
+         * int32_t: noise type
+         * float[n]: parameters
+         */
+        AINFO_CHANNEL_NOISE = 0x20000,
+
+        /**
+         * float[3]: sample period, standard deviation of sample period,
+         * quantization unit
+         */
+        AINFO_CHANNEL_SAMPLER,
+
+        /**
+         * Represents a filter:
+         *   \sum_j a_j y[n-j] == \sum_i b_i x[n-i]
+         *
+         * int32_t[3]: number of feedforward coeffients M,
+         *             number of feedback coefficients N (for FIR filter, N = 1).
+         *             bit mask that represents which element the filter is applied
+         *             to. (bit 0==1 means this filter applies to vector element 0).
+         * float[M+N]: filter coefficients (b0, b1, ..., b_{M-1}), then
+         *             (a0, a1, ..., a_{N-1}), a0 is always 1.
+         *
+         * Multiple frames may be needed for higher number of taps.
+         */
+        AINFO_CHANNEL_FILTER,
+
+        /**
+         * int32_t[2]: size in (row, column) ... 1st frame
+         * float[n]: matrix element values in row major order.
+         */
+        AINFO_CHANNEL_LINEAR_TRANSFORM,
+
+        /**
+         * int32_t[2]: extrapolate method, interpolate method
+         * float[n]: mapping key points in pairs, (in, out)...
+         *           (may be used to model saturation).
+         */
+        AINFO_CHANNEL_NONLINEAR_MAP,
+
+        /**
+         * int32_t: resample method (0-th order, 1st order...)
+         * float[1]: resample ratio (upsampling if < 1.0, downsampling if > 1.0).
+         */
+        AINFO_CHANNEL_RESAMPLER,
+
+        /**
+         * Operation environment parameters section
+         * Types in the following section is sent down (instead of reported from)
+         * device as additional information to aid sensor operation. Data is sent
+         * via injectSensorData() function to sensor handle -1 denoting all sensors
+         * in device.
+         *
+         *
+         * Local geomagnetic field information based on device geo location. This
+         * type is primarily for for magnetic field calibration and rotation vector
+         * sensor fusion.
+         * float[3]: strength (uT), declination and inclination angle (rad).
+         */
+        AINFO_LOCAL_GEOMAGNETIC_FIELD = 0x30000,
+
+        /**
+         * Local gravitational acceleration strength at device geo location.
+         * float: gravitational acceleration norm in m/s^2.
+         */
+        AINFO_LOCAL_GRAVITY,
+
+        /**
+         * Device dock state.
+         * int32_t: dock state following Android API Intent.EXTRA_DOCK_STATE
+         * definition, undefined value is ignored.
+         */
+        AINFO_DOCK_STATE,
+
+        /**
+         * High performance mode hint. Device is able to use up more power and take
+         * more resources to improve throughput and latency in high performance mode.
+         * One possible use case is virtual reality, when sensor latency need to be
+         * carefully controlled.
+         * int32_t: 1 or 0, denote if device is in/out of high performance mode,
+         *          other values is ignored.
+         */
+        AINFO_HIGH_PERFORMANCE_MODE,
+
+        /**
+         * Magnetic field calibration hint. Device is notified when manually
+         * triggered magnetic field calibration procedure is started or stopped. The
+         * calibration procedure is assumed timed out after 1 minute from start,
+         * even if an explicit stop is not received.
+         *
+         * int32_t: 1 for start, 0 for stop, other value is ignored.
+         */
+        AINFO_MAGNETIC_FIELD_CALIBRATION,
+
+        /**
+         * Custom information
+         */
+        AINFO_CUSTOM_START = 0x10000000,
+
+        /**
+         * Debugging
+         */
+        AINFO_DEBUGGING_START = 0x40000000,
+    }
+}
diff --git a/sensors/aidl/android/hardware/sensors/DynamicSensorInfo.aidl b/sensors/aidl/android/hardware/sensors/DynamicSensorInfo.aidl
new file mode 100644
index 0000000..4b14ed0
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/DynamicSensorInfo.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+@VintfStability
+@FixedSize
+parcelable DynamicSensorInfo {
+    boolean connected;
+
+    int sensorHandle;
+
+    /**
+     * UUID of a dynamic sensor (using RFC 4122 byte order)
+     * For UUID 12345678-90AB-CDEF-1122-334455667788 the uuid field is
+     * initialized as:
+     *   {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x11, ...}
+     */
+    Uuid uuid;
+
+    @FixedSize
+    @VintfStability
+    parcelable Uuid {
+        byte[16] values;
+    }
+}
diff --git a/sensors/aidl/android/hardware/sensors/Event.aidl b/sensors/aidl/android/hardware/sensors/Event.aidl
new file mode 100644
index 0000000..e8550f1
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/Event.aidl
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.sensors.AdditionalInfo;
+import android.hardware.sensors.DynamicSensorInfo;
+import android.hardware.sensors.SensorStatus;
+import android.hardware.sensors.SensorType;
+
+@VintfStability
+@FixedSize
+parcelable Event {
+    /**
+     * Time measured in nanoseconds, in "elapsedRealtimeNano()'s" timebase.
+     */
+    long timestamp;
+
+    /**
+     * sensor identifier
+     */
+    int sensorHandle;
+
+    SensorType sensorType;
+
+    /**
+     * Union discriminated on sensorType
+     */
+    EventPayload payload;
+
+    /*
+     * acceleration values are in meter per second per second (m/s^2)
+     * magnetic vector values are in micro-Tesla (uT)
+     * orientation values are in degrees
+     * gyroscope values are in rad/s
+     * temperature is in degrees centigrade (Celsius)
+     * distance in centimeters
+     * light in SI lux units
+     * pressure in hectopascal (hPa)
+     * relative humidity in percent
+     */
+    @VintfStability
+    @FixedSize
+    union EventPayload {
+        /**
+         * SensorType::ACCELEROMETER, SensorType::MAGNETIC_FIELD,
+         * SensorType::ORIENTATION, SensorType::GYROSCOPE, SensorType::GRAVITY,
+         * SensorType::LINEAR_ACCELERATION
+         */
+        Vec3 vec3;
+
+        /**
+         * SensorType::GAME_ROTATION_VECTOR
+         */
+        Vec4 vec4;
+
+        /**
+         * SensorType::MAGNETIC_FIELD_UNCALIBRATED,
+         * SensorType::GYROSCOPE_UNCALIBRATED
+         * SensorType::ACCELEROMETER_UNCALIBRATED
+         */
+        Uncal uncal;
+
+        /**
+         * SensorType::META_DATA
+         */
+        MetaData meta;
+
+        /**
+         * SensorType::DEVICE_ORIENTATION, SensorType::LIGHT, SensorType::PRESSURE,
+         * SensorType::TEMPERATURE, SensorType::PROXIMITY,
+         * SensorType::RELATIVE_HUMIDITY, SensorType::AMBIENT_TEMPERATURE,
+         * SensorType::SIGNIFICANT_MOTION, SensorType::STEP_DETECTOR,
+         * SensorType::TILT_DETECTOR, SensorType::WAKE_GESTURE,
+         * SensorType::GLANCE_GESTURE, SensorType::PICK_UP_GESTURE,
+         * SensorType::WRIST_TILT_GESTURE, SensorType::STATIONARY_DETECT,
+         * SensorType::MOTION_DETECT, SensorType::HEART_BEAT,
+         * SensorType::LOW_LATENCY_OFFBODY_DETECT
+         */
+        float scalar;
+
+        /**
+         * SensorType::STEP_COUNTER
+         */
+        long stepCount;
+
+        /**
+         * SensorType::HEART_RATE
+         */
+        HeartRate heartRate;
+
+        /**
+         * SensorType::POSE_6DOF
+         */
+        Pose6Dof pose6DOF;
+
+        /**
+         * SensorType::DYNAMIC_SENSOR_META
+         */
+        DynamicSensorInfo dynamic;
+
+        /**
+         * SensorType::ADDITIONAL_INFO
+         */
+        AdditionalInfo additional;
+
+        /**
+         * The following sensors should use the data field:
+         * - Undefined/custom sensor type >= SensorType::DEVICE_PRIVATE_BASE
+         * - SensorType::ROTATION_VECTOR, SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+         *   - These are Vec4 types with an additional float accuracy field,
+         *     where data[4] is the estimated heading accuracy in radians
+         *     (-1 if unavailable, and invalid if not in the range (0, 2 * pi]).
+         */
+        Data data;
+
+        /**
+         * SensorType::HEAD_TRACKER
+         */
+        HeadTracker headTracker;
+
+        /**
+         * SensorType::ACCELEROMETER_LIMITED_AXES
+         * SensorType::GYROSCOPE_LIMITED_AXES
+         */
+        LimitedAxesImu limitedAxesImu;
+
+        /**
+         * SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED
+         * SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED
+         */
+        LimitedAxesImuUncal limitedAxesImuUncal;
+
+        /**
+         * SensorType::HEADING
+         */
+        Heading heading;
+
+        @FixedSize
+        @VintfStability
+        parcelable Vec4 {
+            float x;
+            float y;
+            float z;
+            float w;
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable Vec3 {
+            float x;
+            float y;
+            float z;
+            SensorStatus status;
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable Uncal {
+            float x;
+            float y;
+            float z;
+            float xBias;
+            float yBias;
+            float zBias;
+        }
+
+        /**
+         * Payload of the HEAD_TRACKER sensor type. Note that the axis
+         * definition of this sensor type differs from the rest of Android. See
+         * SensorType::HEAD_TRACKER for more information.
+         */
+        @FixedSize
+        @VintfStability
+        parcelable HeadTracker {
+            /**
+             * An Euler vector (rotation vector, i.e. a vector whose direction
+             * indicates the axis of rotation and magnitude indicates the angle
+             * to rotate around that axis) representing the transform from
+             * the (arbitrary, possibly slowly drifting) reference frame to the
+             * head frame. Expressed in radians. Magnitude of the vector must be
+             * in the range [0, pi], while the value of individual axes are
+             * in the range [-pi, pi].
+             */
+            float rx;
+            float ry;
+            float rz;
+
+            /**
+             * An Euler vector (rotation vector) representing the angular
+             * velocity of the head (relative to itself), in radians per second.
+             * The direction of this vector indicates the axis of rotation, and
+             * the magnitude indicates the rate of rotation.
+             */
+            float vx;
+            float vy;
+            float vz;
+
+            /**
+             * This value increments (or wraps around to 0) each time the
+             * reference frame is suddenly and significantly changed, for
+             * example if an orientation filter algorithm used for determining
+             * the orientation has had its state reset.
+             */
+            int discontinuityCount;
+        }
+
+        /**
+         * Payload of the ACCELEROMETER_LIMITED_AXES and GYROSCOPE_LIMITED_AXES
+         * sensor types.
+         */
+        @FixedSize
+        @VintfStability
+        parcelable LimitedAxesImu {
+            /**
+             * Acceleration or angular speed values.  If certain axes are not
+             * supported, the associated value must be set to 0.
+             */
+            float x;
+            float y;
+            float z;
+
+            /**
+             * Limited axes sensors must not be supported for all three axes.
+             * These values indicate which axes are supported with a 1.0 for
+             * supported, and a 0 for not supported. The supported axes should
+             * be determined at build time and these values must not change
+             * during runtime.
+             */
+            float xSupported;
+            float ySupported;
+            float zSupported;
+        }
+
+        /**
+         * Payload of the ACCELEROMETER_LIMITED_AXES_UNCALIBRATED and
+         * GYROSCOPE_LIMITED_AXES_UNCALIBRATED sensor types.
+         */
+        @FixedSize
+        @VintfStability
+        parcelable LimitedAxesImuUncal {
+            /**
+             * Acceleration (without bias compensation) or angular (speed
+             * (without drift compensation) values. If certain axes are not
+             * supported, the associated value must be set to 0.
+             */
+            float x;
+            float y;
+            float z;
+
+            /**
+             * Estimated bias values for uncalibrated accelerometer or
+             * estimated drift values for uncalibrated gyroscope. If certain
+             * axes are not supported, the associated value must be set to 0.
+             */
+            float xBias;
+            float yBias;
+            float zBias;
+
+            /**
+             * Limited axes sensors must not be supported for all three axes.
+             * These values indicate which axes are supported with a 1.0 for
+             * supported, and a 0 for not supported. The supported axes should
+             * be determined at build time and these values must not change
+             * during runtime.
+             */
+            float xSupported;
+            float ySupported;
+            float zSupported;
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable HeartRate {
+            /**
+             * Heart rate in beats per minute.
+             * Set to 0 when status is SensorStatus::UNRELIABLE or
+             * SensorStatus::NO_CONTACT
+             */
+            float bpm;
+            /**
+             * Status of the heart rate sensor for this reading.
+             */
+            SensorStatus status;
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable Heading {
+            /**
+             * The direction in which the device is pointing relative to true
+             * north in degrees. The value must be between 0.0 (inclusive) and
+             * 360.0 (exclusive), with 0 indicating north, 90 east, 180 south,
+             * and 270 west.
+             */
+            float heading;
+            /**
+             * Accuracy is defined at 68% confidence. In the case where the
+             * underlying distribution is assumed Gaussian normal, this would be
+             * considered one standard deviation. For example, if the heading
+             * returns 60 degrees, and accuracy returns 10 degrees, then there
+             * is a 68 percent probability of the true heading being between 50
+             * degrees and 70 degrees.
+             */
+            float accuracy;
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable MetaData {
+            MetaDataEventType what;
+
+            @VintfStability
+            @Backing(type="int")
+            enum MetaDataEventType {
+                META_DATA_FLUSH_COMPLETE = 1,
+            }
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable Pose6Dof {
+            float[15] values;
+        }
+
+        @FixedSize
+        @VintfStability
+        parcelable Data {
+            float[16] values;
+        }
+    }
+}
diff --git a/sensors/aidl/android/hardware/sensors/ISensors.aidl b/sensors/aidl/android/hardware/sensors/ISensors.aidl
new file mode 100644
index 0000000..2ac1884
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/ISensors.aidl
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.sensors.Event;
+import android.hardware.sensors.ISensorsCallback;
+import android.hardware.sensors.SensorInfo;
+
+@VintfStability
+interface ISensors {
+    /**
+     * Activate/de-activate one sensor.
+     *
+     * After sensor de-activation, existing sensor events that have not
+     * been written to the event queue must be abandoned immediately so that
+     * subsequent activations do not get stale sensor events (events
+     * that are generated prior to the latter activation).
+     *
+     * @param sensorHandle is the handle of the sensor to change.
+     * @param enabled set to true to enable, or false to disable the sensor.
+     * @return Status::ok on success
+     *         EX_ILLEGAL_ARGUMENT if the sensorHandle is invalid.
+     */
+    void activate(in int sensorHandle, in boolean enabled);
+
+    /**
+     * Sets a sensor’s parameters, including sampling frequency and maximum
+     * report latency. This function can be called while the sensor is
+     * activated, in which case it must not cause any sensor measurements to
+     * be lost: transitioning from one sampling rate to the other cannot cause
+     * lost events, nor can transitioning from a high maximum report latency to
+     * a low maximum report latency.
+     *
+     * @param sensorHandle handle of sensor to be changed.
+     * @param samplingPeriodNs specifies sensor sample period in nanoseconds.
+     * @param maxReportLatencyNs allowed delay time before an event is sampled
+     *     to time of report.
+     * @return Status::ok on success
+     *         EX_ILLEGAL_ARGUMENT if any parameters are invalid.
+     */
+    void batch(in int sensorHandle, in long samplingPeriodNs, in long maxReportLatencyNs);
+
+    /**
+     * Configure direct sensor event report in direct channel.
+     *
+     * This function start, modify rate or stop direct report of a sensor in a
+     * certain direct channel.
+     *
+     * @param sensorHandle handle of sensor to be configured. When combined
+     *     with STOP rate, sensorHandle can be -1 to denote all active sensors
+     *     in the direct channel specified by channel Handle.
+     * @param channelHandle handle of direct channel to be configured.
+     * @param rate rate level, see RateLevel enum.
+     * @param out reportToken The report token, ignored if rate is STOP.
+     *     See SharedMemFormat.
+     * @return The direct report token to identify multiple sensors of the same type in a single
+     *         direct channel.
+     * @return Status::ok on success
+     *         EX_ILLEGAL_ARGUMENT if the parameter is invalid (e.g. unsupported rate level
+     *          for sensor, channelHandle does not exist, etc).
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     */
+    int configDirectReport(in int sensorHandle, in int channelHandle, in RateLevel rate);
+
+    /**
+     * Trigger a flush of internal FIFO.
+     *
+     * Flush adds a FLUSH_COMPLETE metadata event to the end of the "batch mode"
+     * FIFO for the specified sensor and flushes the FIFO.  If the FIFO is empty
+     * or if the sensor doesn't support batching (FIFO size zero), return
+     * SUCCESS and add a trivial FLUSH_COMPLETE event added to the event stream.
+     * This applies to all sensors other than one-shot sensors. If the sensor
+     * is a one-shot sensor, flush must return EX_ILLEGAL_ARGUMENT and not generate any
+     * flush complete metadata.  If the sensor is not active at the time flush()
+     * is called, flush() return EX_ILLEGAL_ARGUMENT.
+     *
+     * @param sensorHandle handle of sensor to be flushed.
+     * @return Status::ok on success
+     *         EX_ILLEGAL_ARGUMENT if the sensorHandle is invalid.
+     */
+    void flush(in int sensorHandle);
+
+    /**
+     * Enumerate all available (static) sensors.
+     *
+     * The SensorInfo for each sensor returned by getSensorsList must be stable
+     * from the initial call to getSensorsList after a device boot until the
+     * entire system restarts. The SensorInfo for each sensor must not change
+     * between subsequent calls to getSensorsList, even across restarts of the
+     * HAL and its dependencies (for example, the sensor handle for a given
+     * sensor must not change across HAL restarts).
+     */
+    SensorInfo[] getSensorsList();
+
+    /**
+     * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback.
+     *
+     * The Fast Message Queues (FMQ) that are used to send data between the
+     * framework and the HAL. The callback is used by the HAL to notify the
+     * framework of asynchronous events, such as a dynamic sensor connection.
+     *
+     * The Event FMQ is used to transport sensor events from the HAL to the
+     * framework. The Event FMQ is created using the eventQueueDescriptor.
+     * Data may only be written to the Event FMQ. Data must not be read from
+     * the Event FMQ since the framework is the only reader. Upon receiving
+     * sensor events, the HAL writes the sensor events to the Event FMQ.
+     *
+     * Once the HAL is finished writing sensor events to the Event FMQ, the HAL
+     * must notify the framework that sensor events are available to be read and
+     * processed. This is accomplished by either:
+     *     1) Calling the Event FMQ’s EventFlag::wake() function with
+     * EventQueueFlagBits::READ_AND_PROCESS
+     *     2) Setting the write notification in the Event FMQ’s writeBlocking()
+     *        function to EventQueueFlagBits::READ_AND_PROCESS.
+     *
+     * If the Event FMQ’s writeBlocking() function is used, the read
+     * notification must be set to EventQueueFlagBits::EVENTS_READ in order to
+     * be notified and unblocked when the framework has successfully read events
+     * from the Event FMQ.
+     *
+     * The Wake Lock FMQ is used by the framework to notify the HAL when it is
+     * safe to release its wake_lock. When the framework receives WAKE_UP events
+     * from the Event FMQ and the framework has acquired a wake_lock, the
+     * framework must write the number of WAKE_UP events processed to the Wake
+     * Lock FMQ. When the HAL reads the data from the Wake Lock FMQ, the HAL
+     * decrements its current count of unprocessed WAKE_UP events and releases
+     * its wake_lock if the current count of unprocessed WAKE_UP events is
+     * zero. It is important to note that the HAL must acquire the wake lock and
+     * update its internal state regarding the number of outstanding WAKE_UP
+     * events _before_ posting the event to the Wake Lock FMQ, in order to avoid
+     * a race condition that can lead to loss of wake lock synchronization with
+     * the framework.
+     *
+     * The framework must use the WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN value to
+     * notify the HAL that data has been written to the Wake Lock FMQ and must
+     * be read by HAL.
+     *
+     * The ISensorsCallback is used by the HAL to notify the framework of
+     * asynchronous events, such as a dynamic sensor connection.
+     *
+     * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events
+     * must begin with "SensorsHAL_WAKEUP".
+     *
+     * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP
+     * event was written to the Event FMQ without receiving a message on the
+     * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be
+     * released.
+     *
+     * If either the Event FMQ or the Wake Lock FMQ is already initialized when
+     * initialize is invoked, then both existing FMQs must be discarded and the
+     * new descriptors must be used to create new FMQs within the HAL. The
+     * number of outstanding WAKE_UP events should also be reset to zero, and
+     * any outstanding wake_locks held as a result of WAKE_UP events should be
+     * released.
+     *
+     * All active sensor requests and direct channels must be closed and
+     * properly cleaned up when initialize is called in order to ensure that the
+     * HAL and framework's state is consistent (e.g. after a runtime restart).
+     *
+     * initialize must be thread safe and prevent concurrent calls
+     * to initialize from simultaneously modifying state.
+     *
+     * @param eventQueueDescriptor Fast Message Queue descriptor that is used to
+     *     create the Event FMQ which is where sensor events are written. The
+     *     descriptor is obtained from the framework's FMQ that is used to read
+     *     sensor events.
+     * @param wakeLockDescriptor Fast Message Queue descriptor that is used to
+     *     create the Wake Lock FMQ which is where wake_lock events are read
+     *     from. The descriptor is obtained from the framework's FMQ that is
+     *     used to write wake_lock events.
+     * @param sensorsCallback sensors callback that receives asynchronous data
+     *     from the Sensors HAL.
+     * @return Status::ok on success
+     *         EX_ILLEGAL_ARGUMENT if the descriptor is invalid (such as null).
+     */
+    void initialize(in MQDescriptor<Event, SynchronizedReadWrite> eventQueueDescriptor,
+            in MQDescriptor<int, SynchronizedReadWrite> wakeLockDescriptor,
+            in ISensorsCallback sensorsCallback);
+
+    /**
+     * Inject a single sensor event or push operation environment parameters to
+     * device.
+     *
+     * When device is in NORMAL mode, this function is called to push operation
+     * environment data to device. In this operation, Event is always of
+     * SensorType::AdditionalInfo type. See operation environment parameters
+     * section in AdditionalInfoType.
+     *
+     * When device is in DATA_INJECTION mode, this function is also used for
+     * injecting sensor events.
+     *
+     * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO
+     * type events should not be routed back to the sensor event queue.
+     *
+     * @see AdditionalInfoType
+     * @see OperationMode
+     * @param event sensor event to be injected
+     * @return Status::ok on success
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     *         EX_SECURITY if the operation is not allowed.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - ERROR_BAD_VALUE if the sensor event cannot be injected.
+     */
+    void injectSensorData(in Event event);
+
+    /**
+     * Register direct report channel.
+     *
+     * Register a direct channel with supplied shared memory information. Upon
+     * return, the sensor hardware is responsible for resetting the memory
+     * content to initial value (depending on memory format settings).
+     *
+     * @param mem shared memory info data structure.
+     * @param out channelHandle The registered channel handle.
+     * @return The direct channel handle, which is positive if successfully registered, and -1
+     *         otherwise.
+     * @return Status::ok on success
+     *         EX_ILLEGAL_ARGUMENT if the shared memory information is not consistent.
+     *         EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+     *         EX_SERVICE_SPECIFIC on error
+     *         - ERROR_NO_MEMORY if shared memory cannot be used by sensor system.
+     */
+    int registerDirectChannel(in SharedMemInfo mem);
+
+    /**
+     * Place the module in a specific mode.
+     *
+     * @see OperationMode
+     * @param mode The operation mode.
+     * @return Status::ok on success
+     *         EX_UNSUPPORTED_OPERATION if requested mode is not supported.
+     *         EX_SECURITY if the operation is not allowed.
+     */
+    void setOperationMode(in OperationMode mode);
+
+    /**
+     * Unregister direct report channel.
+     *
+     * Unregister a direct channel previously registered using
+     * registerDirectChannel, and remove all active sensor report configured in
+     * still active sensor report configured in the direct channel.
+     *
+     * @param channelHandle handle of direct channel to be unregistered.
+     * @return Status::ok on success
+     *         EX_UNSUPPORTED_OPERATION if direct report is not supported.
+     */
+    void unregisterDirectChannel(in int channelHandle);
+
+    /**
+     * Direct report rate level definition. Except for SENSOR_DIRECT_RATE_STOP, each
+     * rate level covers the range (55%, 220%] * nominal report rate. For example,
+     * if config direct report specify a rate level SENSOR_DIRECT_RATE_FAST, it is
+     * legal for sensor hardware to report event at a rate greater than 110Hz, and
+     * less or equal to 440Hz. Note that rate has to remain steady without variation
+     * before new rate level is configured, i.e. if a sensor is configured to
+     * SENSOR_DIRECT_RATE_FAST and starts to report event at 256Hz, it cannot
+     * change rate to 128Hz after a few seconds of running even if 128Hz is also in
+     * the legal range of SENSOR_DIRECT_RATE_FAST. Thus, it is recommended to
+     * associate report rate with RateLvel statically for single sensor.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum RateLevel {
+        STOP,
+        NORMAL,
+        FAST,
+        VERY_FAST,
+    }
+
+    @VintfStability
+    @Backing(type="int")
+    enum OperationMode {
+        // Normal operation. Default state of the module.
+        NORMAL = 0,
+        // Loopback mode. Data is injected for the supported sensors by the sensor service in this
+        // mode.
+        DATA_INJECTION = 1,
+    }
+
+    @VintfStability
+    parcelable SharedMemInfo {
+        SharedMemType type;
+        SharedMemFormat format;
+        int size;
+        NativeHandle memoryHandle;
+
+        @VintfStability
+        @Backing(type="int")
+        enum SharedMemFormat {
+            SENSORS_EVENT = 1,
+        }
+
+        @VintfStability
+        @Backing(type="int")
+        enum SharedMemType {
+            ASHMEM = 1,
+            GRALLOC,
+        }
+    }
+
+    /**
+     * Error codes that are used as service specific errors with the AIDL return
+     * value EX_SERVICE_SPECIFIC.
+     */
+    const int ERROR_NO_MEMORY = -12;
+    const int ERROR_BAD_VALUE = -22;
+
+    /**
+     * The maximum number of seconds to wait for a message on the Wake Lock FMQ
+     * before automatically releasing any wake_lock held for a WAKE_UP event.
+     */
+    const int WAKE_LOCK_TIMEOUT_SECONDS = 1;
+
+    /**
+     * Used to notify the Event FMQ that events should be read and processed.
+     */
+    const int EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS = 1 << 0;
+
+    /**
+     * Used by the framework to signal to the HAL when events have been
+     * successfully read from the Event FMQ.
+     *
+     * If the MessageQueue::writeBlocking function is being used to write sensor
+     * events to the Event FMQ, then the readNotification parameter must be set
+     * to EVENTS_READ.
+     */
+    const int EVENT_QUEUE_FLAG_BITS_EVENTS_READ = 1 << 1;
+
+    /**
+     * Used to notify the HAL that the framework has written data to the Wake
+     * Lock FMQ.
+     */
+    const int WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN = 1 << 0;
+
+    /**
+     * Constants related to direct sensor events. The following table illustrates the
+     * data format.
+     *
+     * Offset   Type        Name
+     * -----------------------------------
+     * 0x0000   int32_t     Size (always DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH)
+     * 0x0004   int32_t     Sensor report token
+     * 0x0008   int32_t     Type (see SensorType.aidl)
+     * 0x000C   uint32_t    Atomic counter
+     * 0x0010   int64_t     Timestamp (see Event.aidl)
+     * 0x0018   float[16]/  Data
+     *          int64_t[8]
+     * 0x0058   int32_t[4]  Reserved (set to zero)
+     */
+    const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_FIELD = 0x0;
+    const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_REPORT_TOKEN = 0x4;
+    const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_SENSOR_TYPE = 0x8;
+    const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_ATOMIC_COUNTER = 0xC;
+    const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_TIMESTAMP = 0x10;
+    const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 0x18;
+    const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 0x58;
+    const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+}
diff --git a/sensors/aidl/android/hardware/sensors/ISensorsCallback.aidl b/sensors/aidl/android/hardware/sensors/ISensorsCallback.aidl
new file mode 100644
index 0000000..01bae52
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/ISensorsCallback.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.sensors.SensorInfo;
+
+@VintfStability
+interface ISensorsCallback {
+    /**
+     * Notify the framework that new dynamic sensors have been connected.
+     *
+     * If a dynamic sensor was previously connected and has not been
+     * disconnected, then that sensor must not be included in sensorInfos.
+     *
+     * @param sensorInfos vector of SensorInfo for each dynamic sensor that
+     *     was connected.
+     */
+    void onDynamicSensorsConnected(in SensorInfo[] sensorInfos);
+
+    /**
+     * Notify the framework that previously connected dynamic sensors have been
+     * disconnected.
+     *
+     * If a dynamic sensor was previously disconnected and has not been
+     * reconnected, then that sensor must not be included in sensorHandles.
+     *
+     * The HAL must ensure that all sensor events from departing dynamic
+     * sensors have been written to the Event FMQ before calling
+     * onDynamicSensorsDisconnected.
+     *
+     * @param sensorHandles vector of sensor handles for each dynamic sensors
+     *     that was disconnected.
+     */
+    void onDynamicSensorsDisconnected(in int[] sensorHandles);
+}
diff --git a/sensors/aidl/android/hardware/sensors/SensorInfo.aidl b/sensors/aidl/android/hardware/sensors/SensorInfo.aidl
new file mode 100644
index 0000000..35caf8b
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/SensorInfo.aidl
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.sensors.SensorType;
+
+@VintfStability
+parcelable SensorInfo {
+    /**
+     * handle that identifies this sensors. This handle is used to reference
+     * this sensor throughout the HAL API.
+     */
+    int sensorHandle;
+
+    /**
+     * Name of this sensor.
+     * All sensors of the same "type" must have a different "name".
+     */
+    String name;
+
+    /**
+     * vendor of the hardware part
+     */
+    String vendor;
+
+    /**
+     * version of the hardware part + driver. The value of this field
+     * must increase when the driver is updated in a way that changes the
+     * output of this sensor. This is important for fused sensors when the
+     * fusion algorithm is updated.
+     */
+    int version;
+
+    /**
+     * this sensor's type.
+     */
+    SensorType type;
+
+    /**
+     * type of this sensor as a string.
+     *
+     * When defining an OEM specific sensor or sensor manufacturer specific
+     * sensor, use your reserve domain name as a prefix.
+     * e.g. com.google.glass.onheaddetector
+     *
+     * For sensors of known type defined in SensorType (value <
+     * SensorType::DEVICE_PRIVATE_BASE), this can be an empty string.
+     */
+    String typeAsString;
+
+    /**
+     * maximum range of this sensor's value in SI units
+     */
+    float maxRange;
+
+    /**
+     * smallest difference between two values reported by this sensor
+     */
+    float resolution;
+
+    /**
+     * rough estimate of this sensor's power consumption in mA
+     */
+    float power;
+
+    /**
+     * this value depends on the reporting mode:
+     *
+     *   continuous: minimum sample period allowed in microseconds
+     *   on-change : 0
+     *   one-shot  :-1
+     *   special   : 0, unless otherwise noted
+     */
+    int minDelayUs;
+
+    /**
+     * number of events reserved for this sensor in the batch mode FIFO.
+     * If there is a dedicated FIFO for this sensor, then this is the
+     * size of this FIFO. If the FIFO is shared with other sensors,
+     * this is the size reserved for that sensor and it can be zero.
+     */
+    int fifoReservedEventCount;
+
+    /**
+     * maximum number of events of this sensor that could be batched.
+     * This is especially relevant when the FIFO is shared between
+     * several sensors; this value is then set to the size of that FIFO.
+     */
+    int fifoMaxEventCount;
+
+    /**
+     * permission required to see this sensor, register to it and receive data.
+     * Set to "" if no permission is required. Some sensor types like the
+     * heart rate monitor have a mandatory require_permission.
+     * For sensors that always require a specific permission, like the heart
+     * rate monitor, the android framework might overwrite this string
+     * automatically.
+     */
+    String requiredPermission;
+
+    /**
+     * This value is defined only for continuous mode and on-change sensors.
+     * It is the delay between two sensor events corresponding to the lowest
+     * frequency that this sensor supports. When lower frequencies are requested
+     * through batch()/setDelay() the events will be generated at this frequency
+     * instead.
+     * It can be used by the framework or applications to estimate when the
+     * batch FIFO may be full.
+     *
+     * continuous, on-change: maximum sampling period allowed in microseconds.
+     * one-shot, special : 0
+     */
+    int maxDelayUs;
+
+    /**
+     * Bitmasks defined in SENSOR_FLAG_BITS_* below.
+     */
+    int flags;
+
+    /**
+     * Whether this sensor wakes up the AP from suspend mode when data is
+     * available.  Whenever sensor events are delivered from a wake_up sensor,
+     * the driver needs to hold a wake_lock till the events are read by the
+     * SensorService i.e. till ISensors::poll() is called the next time.
+     * Once poll is called again it means events have been read by the
+     * SensorService, the driver can safely release the wake_lock. SensorService
+     * will continue to hold a wake_lock till the app actually reads the events.
+     */
+    const int SENSOR_FLAG_BITS_WAKE_UP = 1;
+
+    /**
+     * Reporting modes for various sensors. Each sensor will have exactly one of
+     * these modes set.
+     * The least significant 2nd, 3rd and 4th bits are used to represent four
+     * possible reporting modes.
+     */
+    const int SENSOR_FLAG_BITS_CONTINUOUS_MODE = 0;
+    const int SENSOR_FLAG_BITS_ON_CHANGE_MODE = 2;
+    const int SENSOR_FLAG_BITS_ONE_SHOT_MODE = 4;
+    const int SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE = 6;
+
+    /**
+     * Set this flag if the sensor supports data_injection mode and allows data
+     * to be injected from the SensorService. When in data_injection ONLY
+     * sensors with this flag set are injected sensor data and only sensors with
+     * this flag set are activated. Eg: Accelerometer and Step Counter sensors
+     * can be set with this flag and SensorService will inject accelerometer
+     * data and read the corresponding step counts.
+     */
+    const int SENSOR_FLAG_BITS_DATA_INJECTION = 0x10;
+
+    /**
+     * Set this flag if the sensor is a dynamically connected sensor. See
+     * DynamicSensorInfo and DYNAMIC_SENSOR_META for details.
+     */
+    const int SENSOR_FLAG_BITS_DYNAMIC_SENSOR = 0x20;
+
+    /**
+     * Set this flag if sensor additional information is supported.
+     * See ADDITIONAL_INFO and AdditionalInfo for details.
+     */
+    const int SENSOR_FLAG_BITS_ADDITIONAL_INFO = 0x40;
+
+    /**
+     * Set this flag if sensor suppor direct channel backed by ashmem.
+     * See SharedMemType and registerDirectChannel for more details.
+     */
+    const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM = 0x400;
+
+    /**
+     * Set this flag if sensor suppor direct channel backed by gralloc HAL memory.
+     * See SharedMemType and registerDirectChannel for more details.
+     */
+    const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_GRALLOC = 0x800;
+
+    /**
+     * Flags mask for reporting mode of sensor.
+     */
+    const int SENSOR_FLAG_BITS_MASK_REPORTING_MODE = 0xE;
+
+    /**
+     * Flags mask for direct report maximum rate level support.
+     * See RateLevel.
+     */
+    const int SENSOR_FLAG_BITS_MASK_DIRECT_REPORT = 0x380;
+
+    /**
+     * Flags mask for all direct channel support bits.
+     * See SharedMemType.
+     */
+    const int SENSOR_FLAG_BITS_MASK_DIRECT_CHANNEL = 0xC00;
+
+    /**
+     * Defines the number of bits different pieces of information are shifted in the
+     * SENSOR_FLAG_BITS_* bitmask.
+     */
+    const int SENSOR_FLAG_SHIFT_REPORTING_MODE = 1;
+    const int SENSOR_FLAG_SHIFT_DATA_INJECTION = 4;
+    const int SENSOR_FLAG_SHIFT_DYNAMIC_SENSOR = 5;
+    const int SENSOR_FLAG_SHIFT_ADDITIONAL_INFO = 6;
+    const int SENSOR_FLAG_SHIFT_DIRECT_REPORT = 7;
+    const int SENSOR_FLAG_SHIFT_DIRECT_CHANNEL = 10;
+}
diff --git a/sensors/aidl/android/hardware/sensors/SensorStatus.aidl b/sensors/aidl/android/hardware/sensors/SensorStatus.aidl
new file mode 100644
index 0000000..0fd8697
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/SensorStatus.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+@VintfStability
+@Backing(type="byte")
+enum SensorStatus {
+    NO_CONTACT = -1,
+    UNRELIABLE = 0,
+    ACCURACY_LOW = 1,
+    ACCURACY_MEDIUM = 2,
+    ACCURACY_HIGH = 3,
+}
diff --git a/sensors/aidl/android/hardware/sensors/SensorType.aidl b/sensors/aidl/android/hardware/sensors/SensorType.aidl
new file mode 100644
index 0000000..9098894
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/SensorType.aidl
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors;
+
+@VintfStability
+@Backing(type="int")
+enum SensorType {
+    /**
+     * META_DATA is a special event type used to populate the MetaData
+     * structure. It doesn't correspond to a physical sensor. Events of this
+     * type exist only inside the HAL, their primary purpose is to signal the
+     * completion of a flush request.
+     */
+    META_DATA = 0,
+
+    /**
+     * ACCELEROMETER
+     * reporting-mode: continuous
+     *
+     * All values are in SI units (m/s^2) and measure the acceleration of the
+     * device minus the acceleration due to gravity.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    ACCELEROMETER = 1,
+
+    /**
+     * MAGNETIC_FIELD
+     * reporting-mode: continuous
+     *
+     * All values are in micro-Tesla (uT) and measure the geomagnetic
+     * field in the X, Y and Z axis.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    MAGNETIC_FIELD = 2,
+
+    /**
+     * ORIENTATION
+     * reporting-mode: continuous
+     *
+     * All values are angles in degrees.
+     *
+     * Orientation sensors return sensor events for all 3 axes at a constant
+     * rate defined by setDelay().
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    ORIENTATION = 3,
+
+    /**
+     * GYROSCOPE
+     * reporting-mode: continuous
+     *
+     * All values are in radians/second and measure the rate of rotation
+     * around the X, Y and Z axis.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    GYROSCOPE = 4,
+
+    /**
+     * LIGHT
+     * reporting-mode: on-change
+     *
+     * The light sensor value is returned in SI lux units.
+     *
+     * Both wake-up and non wake-up versions are useful.
+     */
+    LIGHT = 5,
+
+    /**
+     * PRESSURE
+     * reporting-mode: continuous
+     *
+     * The pressure sensor return the athmospheric pressure in hectopascal (hPa)
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    PRESSURE = 6,
+
+    /**
+     * PROXIMITY
+     * reporting-mode: on-change
+     *
+     * The proximity sensor which turns the screen off and back on during calls
+     * is the wake-up proximity sensor. Implement wake-up proximity sensor
+     * before implementing a non wake-up proximity sensor. For the wake-up
+     * proximity sensor set the flag SENSOR_FLAG_WAKE_UP.
+     * The value corresponds to the distance to the nearest object in
+     * centimeters.
+     */
+    PROXIMITY = 8,
+
+    /**
+     * GRAVITY
+     * reporting-mode: continuous
+     *
+     * A gravity output indicates the direction of and magnitude of gravity in
+     * the devices's coordinates.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    GRAVITY = 9,
+
+    /**
+     * LINEAR_ACCELERATION
+     * reporting-mode: continuous
+     *
+     * Indicates the linear acceleration of the device in device coordinates,
+     * not including gravity.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    LINEAR_ACCELERATION = 10,
+
+    /**
+     * ROTATION_VECTOR
+     * reporting-mode: continuous
+     *
+     * The rotation vector symbolizes the orientation of the device relative to
+     * the East-North-Up coordinates frame.
+     *
+     * Note that despite the name, SensorType::ROTATION_VECTOR uses
+     * quaternion representation, rather than the rotation vector representation
+     * (aka Euler vector) seen in SensorType::HEAD_TRACKER.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    ROTATION_VECTOR = 11,
+
+    /**
+     * RELATIVE_HUMIDITY
+     * reporting-mode: on-change
+     *
+     * A relative humidity sensor measures relative ambient air humidity and
+     * returns a value in percent.
+     *
+     * Both wake-up and non wake-up versions are useful.
+     */
+    RELATIVE_HUMIDITY = 12,
+
+    /**
+     * AMBIENT_TEMPERATURE
+     * reporting-mode: on-change
+     *
+     * The ambient (room) temperature in degree Celsius.
+     *
+     * Both wake-up and non wake-up versions are useful.
+     */
+    AMBIENT_TEMPERATURE = 13,
+
+    /**
+     * MAGNETIC_FIELD_UNCALIBRATED
+     * reporting-mode: continuous
+     *
+     * Similar to MAGNETIC_FIELD, but the hard iron calibration is
+     * reported separately instead of being included in the measurement.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    MAGNETIC_FIELD_UNCALIBRATED = 14,
+
+    /**
+     * GAME_ROTATION_VECTOR
+     * reporting-mode: continuous
+     *
+     * Similar to ROTATION_VECTOR, but not using the geomagnetic
+     * field.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    GAME_ROTATION_VECTOR = 15,
+
+    /**
+     * GYROSCOPE_UNCALIBRATED
+     * reporting-mode: continuous
+     *
+     * All values are in radians/second and measure the rate of rotation
+     * around the X, Y and Z axis.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    GYROSCOPE_UNCALIBRATED = 16,
+
+    /**
+     * SIGNIFICANT_MOTION
+     * reporting-mode: one-shot
+     *
+     * A sensor of this type triggers an event each time significant motion
+     * is detected and automatically disables itself.
+     * For Significant Motion sensor to be useful, it must be defined as a
+     * wake-up sensor. (set SENSOR_FLAG_WAKE_UP). Implement the wake-up
+     * significant motion sensor. A non wake-up version is not useful.
+     * The only allowed value to return is 1.0.
+     */
+    SIGNIFICANT_MOTION = 17,
+
+    /**
+     * STEP_DETECTOR
+     * reporting-mode: special
+     *
+     * A sensor of this type triggers an event each time a step is taken
+     * by the user. The only allowed value to return is 1.0 and an event
+     * is generated for each step.
+     *
+     * Both wake-up and non wake-up versions are useful.
+     */
+    STEP_DETECTOR = 18,
+
+    /**
+     * STEP_COUNTER
+     * reporting-mode: on-change
+     *
+     * A sensor of this type returns the number of steps taken by the user since
+     * the last reboot while activated. The value is returned as a uint64_t and
+     * is reset to zero only on a system / android reboot.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    STEP_COUNTER = 19,
+
+    /**
+     * GEOMAGNETIC_ROTATION_VECTOR
+     * reporting-mode: continuous
+     *
+     *  Similar to ROTATION_VECTOR, but using a magnetometer instead
+     *  of using a gyroscope.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    GEOMAGNETIC_ROTATION_VECTOR = 20,
+
+    /**
+     * HEART_RATE
+     * reporting-mode: on-change
+     *
+     *  A sensor of this type returns the current heart rate.
+     *  The events contain the current heart rate in beats per minute (BPM) and
+     *  the status of the sensor during the measurement. See "HeartRate" below
+     *  for more details.
+     *
+     *  Because this sensor is on-change, events must be generated when and only
+     *  when heart_rate.bpm or heart_rate.status have changed since the last
+     *  event. In particular, upon the first activation, unless the device is
+     *  known to not be on the body, the status field of the first event must be
+     *  set to SensorStatus::UNRELIABLE. The event should be generated no faster
+     *  than every period_ns passed to setDelay() or to batch().
+     *  See the definition of the on-change reporting mode for more information.
+     *
+     *  SensorInfo.requiredPermission must be set to
+     *  SENSOR_PERMISSION_BODY_SENSORS.
+     *
+     *  Both wake-up and non wake-up versions are useful.
+     */
+    HEART_RATE = 21,
+
+    /**
+     * WAKE_UP_TILT_DETECTOR
+     * reporting-mode: special (setDelay has no impact)
+     *
+     * A sensor of this type generates an event each time a tilt event is
+     * detected. A tilt event must be generated if the direction of the
+     * 2-seconds window average gravity changed by at least 35 degrees since the
+     * activation or the last trigger of the sensor.
+     *
+     *  reference_estimated_gravity = average of accelerometer measurements over
+     *  the first 1 second after activation or the estimated gravity at the last
+     *  trigger.
+     *
+     *  current_estimated_gravity = average of accelerometer measurements over
+     *  the last 2 seconds.
+     *
+     *  trigger when
+     *     angle(reference_estimated_gravity, current_estimated_gravity)
+     *       > 35 degrees
+     *
+     * Large accelerations without a change in phone orientation must not
+     * trigger a tilt event.
+     * For example, a sharp turn or strong acceleration while driving a car
+     * must not trigger a tilt event, even though the angle of the average
+     * acceleration might vary by more than 35 degrees.
+     *
+     * Typically, this sensor is implemented with the help of only an
+     * accelerometer. Other sensors can be used as well if they do not increase
+     * the power consumption significantly. This is a low power sensor that
+     * must allow the AP to go into suspend mode. Do not emulate this sensor
+     * in the HAL.
+     * Like other wake up sensors, the driver is expected to a hold a wake_lock
+     * with a timeout of 200 ms while reporting this event. The only allowed
+     * return value is 1.0.
+     *
+     * Implement only the wake-up version of this sensor.
+     */
+    TILT_DETECTOR = 22,
+
+    /**
+     * WAKE_GESTURE
+     * reporting-mode: one-shot
+     *
+     * A sensor enabling waking up the device based on a device specific motion.
+     *
+     * When this sensor triggers, the device behaves as if the power button was
+     * pressed, turning the screen on. This behavior (turning on the screen when
+     * this sensor triggers) might be deactivated by the user in the device
+     * settings. Changes in settings do not impact the behavior of the sensor:
+     * only whether the framework turns the screen on when it triggers.
+     *
+     * The actual gesture to be detected is not specified, and can be chosen by
+     * the manufacturer of the device.
+     * This sensor must be low power, as it is likely to be activated 24/7.
+     * The only allowed value to return is 1.0.
+     *
+     * Implement only the wake-up version of this sensor.
+     */
+    WAKE_GESTURE = 23,
+
+    /**
+     * GLANCE_GESTURE
+     * reporting-mode: one-shot
+     *
+     * A sensor enabling briefly turning the screen on to enable the user to
+     * glance content on screen based on a specific motion.  The device must
+     * turn the screen off after a few moments.
+     *
+     * When this sensor triggers, the device turns the screen on momentarily
+     * to allow the user to glance notifications or other content while the
+     * device remains locked in a non-interactive state (dozing). This behavior
+     * (briefly turning on the screen when this sensor triggers) might be
+     * deactivated by the user in the device settings.
+     * Changes in settings do not impact the behavior of the sensor: only
+     * whether the framework briefly turns the screen on when it triggers.
+     *
+     * The actual gesture to be detected is not specified, and can be chosen by
+     * the manufacturer of the device.
+     * This sensor must be low power, as it is likely to be activated 24/7.
+     * The only allowed value to return is 1.0.
+     *
+     * Implement only the wake-up version of this sensor.
+     */
+    GLANCE_GESTURE = 24,
+
+    /**
+     * PICK_UP_GESTURE
+     * reporting-mode: one-shot
+     *
+     * A sensor of this type triggers when the device is picked up regardless of
+     * wherever is was before (desk, pocket, bag). The only allowed return value
+     * is 1.0. This sensor de-activates itself immediately after it triggers.
+     *
+     * Implement only the wake-up version of this sensor.
+     */
+    PICK_UP_GESTURE = 25,
+
+    /**
+     * WRIST_TILT_GESTURE
+     * trigger-mode: special
+     * wake-up sensor: yes
+     *
+     * A sensor of this type triggers an event each time a tilt of the
+     * wrist-worn device is detected.
+     *
+     * This sensor must be low power, as it is likely to be activated 24/7.
+     * The only allowed value to return is 1.0.
+     *
+     * Implement only the wake-up version of this sensor.
+     */
+    WRIST_TILT_GESTURE = 26,
+
+    /**
+     * DEVICE_ORIENTATION
+     * reporting-mode: on-change
+     *
+     * The current orientation of the device. The value is reported in
+     * the "scalar" element of the EventPayload in Event. The
+     * only values that can be reported are (please refer to Android Sensor
+     * Coordinate System to understand the X and Y axis direction with respect
+     * to default orientation):
+     *  - 0: device is in default orientation (Y axis is vertical and points up)
+     *  - 1: device is rotated 90 degrees counter-clockwise from default
+     *       orientation (X axis is vertical and points up)
+     *  - 2: device is rotated 180 degrees from default orientation (Y axis is
+     *       vertical and points down)
+     *  - 3: device is rotated 90 degrees clockwise from default orientation
+     *       (X axis is vertical and points down)
+     *
+     * Moving the device to an orientation where the Z axis is vertical (either
+     * up or down) must not cause a new event to be reported.
+     *
+     * To improve the user experience of this sensor, it is recommended to
+     * implement some physical (i.e., rotation angle) and temporal (i.e., delay)
+     * hysteresis. In other words, minor or transient rotations must not cause
+     * a new event to be reported.
+     *
+     * This is a low power sensor that intended to reduce interrupts of
+     * application processor and thus allow it to go sleep. Use hardware
+     * implementation based on low power consumption sensors, such as
+     * accelerometer. Device must not emulate this sensor in the HAL.
+     *
+     * Both wake-up and non wake-up versions are useful.
+     */
+    DEVICE_ORIENTATION = 27,
+
+    /**
+     * POSE_6DOF
+     * trigger-mode: continuous
+     *
+     * A sensor of this type returns the pose of the device.
+     * Pose of the device is defined as the orientation of the device from a
+     * Earth Centered Earth Fixed frame and the translation from an arbitrary
+     * point at subscription.
+     *
+     * This sensor can be high power. It can use any and all of the following
+     *           . Accelerometer
+     *           . Gyroscope
+     *           . Camera
+     *           . Depth Camera
+     *
+     */
+    POSE_6DOF = 28,
+
+    /**
+     * STATIONARY_DETECT
+     * trigger mode: one shot
+     *
+     * A sensor of this type returns an event if the device is still/stationary
+     * for a while. The period of time to monitor for stationarity must be
+     * greater than 5 seconds. The latency must be less than 10 seconds.
+     *
+     * Stationarity here refers to absolute stationarity. eg: device on desk.
+     *
+     * The only allowed value to return is 1.0.
+     */
+    STATIONARY_DETECT = 29,
+
+    /**
+     * MOTION_DETECT
+     * trigger mode: one shot
+     *
+     * A sensor of this type returns an event if the device is not still for
+     * for a while. The period of time to monitor for stationarity must be
+     * greater than 5 seconds. The latency must be less than 10 seconds.
+     *
+     * Motion here refers to any mechanism in which the device is causes to be
+     * moved in its inertial frame. eg: Pickin up the device and walking with it
+     * to a nearby room may trigger motion wherewas keeping the device on a
+     * table on a smooth train moving at constant velocity may not trigger
+     * motion.
+     *
+     * The only allowed value to return is 1.0.
+     */
+    MOTION_DETECT = 30,
+
+    /**
+     * HEART_BEAT
+     * trigger mode: continuous
+     *
+     * A sensor of this type returns an event everytime a hear beat peak is
+     * detected.
+     *
+     * Peak here ideally corresponds to the positive peak in the QRS complex of
+     * and ECG signal.
+     *
+     * The sensor is not expected to be optimized for latency. As a guide, a
+     * latency of up to 10 seconds is acceptable. However, the timestamp attached
+     * to the event must be accuratly correspond to the time the peak occurred.
+     *
+     * The sensor event contains a parameter for the confidence in the detection
+     * of the peak where 0.0 represent no information at all, and 1.0 represents
+     * certainty.
+     */
+    HEART_BEAT = 31,
+
+    /**
+     * DYNAMIC_SENSOR_META
+     * trigger-mode: special
+     * wake-up sensor: yes
+     *
+     * A sensor event of this type is received when a dynamic sensor is added to
+     * or removed from the system. At most one sensor of this type can be
+     * present in one sensor HAL implementation and presence of a sensor of this
+     * type in sensor HAL implementation indicates that this sensor HAL supports
+     * dynamic sensor feature. Operations, such as batch, activate and setDelay,
+     * to this special purpose sensor must be treated as no-op and return
+     * successful; flush() also has to generate flush complete event as if this
+     * is a sensor that does not support batching.
+     *
+     * A dynamic sensor connection indicates connection of a physical device or
+     * instantiation of a virtual sensor backed by algorithm; and a dynamic
+     * sensor disconnection indicates the opposite. A sensor event of
+     * DYNAMIC_SENSOR_META type should be delivered regardless of
+     * the activation status of the sensor in the event of dynamic sensor
+     * connection and disconnection. In the sensor event, besides the common
+     * data entries, "dynamic_sensor_meta", which includes fields for connection
+     * status, handle of the sensor involved, pointer to sensor_t structure and
+     * a uuid field, must be populated.
+     *
+     * At a dynamic sensor connection event, fields of sensor_t structure
+     * referenced by a pointer in dynamic_sensor_meta must be filled as if it
+     * was regular sensors. Sensor HAL is responsible for recovery of memory if
+     * the corresponding data is dynamicially allocated. However, the
+     * pointer must be valid until the first activate call to the sensor
+     * reported in this connection event. At a dynamic sensor disconnection,
+     * the sensor_t pointer must be NULL.
+     *
+     * The sensor handle assigned to dynamic sensors must never be the same as
+     * that of any regular static sensors, and must be unique until next boot.
+     * In another word, if a handle h is used for a dynamic sensor A, that same
+     * number cannot be used for the same dynamic sensor A or another dynamic
+     * sensor B even after disconnection of A until reboot.
+     *
+     * The UUID field will be used for identifying the sensor in addition to
+     * name, vendor and version and type. For physical sensors of the same
+     * model, all sensors will have the same values in sensor_t, but the UUID
+     * must be unique and persistent for each individual unit. An all zero
+     * UUID indicates it is not possible to differentiate individual sensor
+     * unit.
+     *
+     */
+    DYNAMIC_SENSOR_META = 32,
+
+    /**
+     * ADDITIONAL_INFO
+     * reporting-mode: N/A
+     *
+     * This sensor type is for delivering additional sensor information aside
+     * from sensor event data.
+     * Additional information may include sensor front-end group delay, internal
+     * calibration parameters, noise level metrics, device internal temperature,
+     * etc.
+     *
+     * This type will never bind to a sensor. In other words, no sensor in the
+     * sensor list can have the type SENSOR_TYPE_ADDITIONAL_INFO. If a
+     * sensor HAL supports sensor additional information feature, it reports
+     * sensor_event_t with "sensor" field set to handle of the reporting sensor
+     * and "type" field set to ADDITIONAL_INFO. Delivery of
+     * additional information events is triggered under two conditions: an
+     * enable activate() call or a flush() call to the corresponding sensor.
+     * Besides, time varying parameters can update infrequently without being
+     * triggered. Device is responsible to control update rate. The recommend
+     * update rate is less than 1/1000 of sensor event rate or less than once
+     * per minute in average.
+     *
+     * A single additional information report consists of multiple frames.
+     * Sequences of these frames are ordered using timestamps, which means the
+     * timestamps of sequential frames have to be at least 1 nanosecond apart
+     * from each other. Each frame is a sensor_event_t delivered through the HAL
+     * interface, with related data stored in the "additional_info" field, which
+     * is of type additional_info_event_t.
+     * The "type" field of additional_info_event_t denotes the nature of the
+     * payload data (see additional_info_type_t).
+     * The "serial" field is used to keep the sequence of payload data that
+     * spans multiple frames. The first frame of the entire report is always of
+     * type AINFO_BEGIN, and the last frame is always AINFO_END.
+     *
+     * If flush() was triggering the report, all additional information frames
+     * must be delivered after flush complete event.
+     */
+    ADDITIONAL_INFO = 33,
+
+    /**
+     * LOW_LATENCY_OFFBODY_DETECT
+     * trigger-mode: on-change
+     * wake-up sensor: yes
+     *
+     * A sensor of this type is defined for devices that are supposed to be worn
+     * by the user in the normal use case (such as a watch, wristband, etc) and
+     * is not yet defined for other device.
+     *
+     * A sensor of this type triggers an event each time the wearable device
+     * is removed from the body and each time it's put back onto the body.
+     * It must be low-latency and be able to detect the on-body to off-body
+     * transition within one second (event delivery time included),
+     * and 3-second latency to determine the off-body to on-body transition
+     * (event delivery time included).
+     *
+     * There are only two valid event values for the sensor to return :
+     *    0.0 for off-body
+     *    1.0 for on-body
+     *
+     */
+    LOW_LATENCY_OFFBODY_DETECT = 34,
+
+    /**
+     * ACCELEROMETER_UNCALIBRATED
+     * reporting-mode: continuous
+     *
+     * All values are in SI units (m/s^2) and measure the acceleration of the
+     * device minus the acceleration due to gravity.
+     *
+     * Implement the non-wake-up version of this sensor and implement the
+     * wake-up version if the system possesses a wake up fifo.
+     */
+    ACCELEROMETER_UNCALIBRATED = 35,
+
+    /**
+     * HINGE_ANGLE
+     * reporting-mode: on-change
+     * wake-up sensor: yes
+     *
+     * A sensor of this type measures the angle, in degrees, between two
+     * integral parts of the device. Movement of a hinge measured by this sensor
+     * type is expected to alter the ways in which the user may interact with
+     * the device, for example by unfolding or revealing a display.
+     *
+     * Sensor data is output using EventPayload.scalar.
+     *
+     * Implement wake-up proximity sensor before implementing a non wake-up
+     * proximity sensor.
+     */
+    HINGE_ANGLE = 36,
+
+    /**
+     * HEAD_TRACKER
+     * reporting-mode: continuous
+     *
+     * A sensor of this type measures the orientation of a user's head relative
+     * to an arbitrary reference frame, and the rate of rotation.
+     *
+     * Events produced by this sensor follow a special head-centric coordinate
+     * frame, where:
+     *   - The X axis crosses through the user's ears, with the positive X
+     *     direction extending out of the user's right ear
+     *   - The Y axis crosses from the back of the user's head through their
+     *     nose, with the positive direction extending out of the nose, and the
+     *     X/Y plane being nominally parallel to the ground when the user is
+     *     upright and looking straight ahead
+     *   - The Z axis crosses from the neck through the top of the user's head,
+     *     with the positive direction extending out from the top of the head
+     *
+     * When this sensor type is exposed as a dynamic sensor through a
+     * communications channel that uses HID, such as Bluetooth or USB, as part
+     * of a device with audio output capability (e.g. headphones), then the
+     * DynamicSensorInfo::uuid field shall be set to contents of the HID
+     * Persistent Unique ID to permit association between the sensor and audio
+     * device. Accordingly, the HID Persistent Unique ID (Sensors Page 0x20,
+     * Usage ID 0x302) must be populated as a UUID in binary representation,
+     * following RFC 4122 byte order.
+     */
+    HEAD_TRACKER = 37,
+
+    /**
+     * ACCELEROMETER_LIMITED_AXES
+     * reporting-mode: continuous
+     *
+     * Equivalent to ACCELEROMETER, but supporting cases where one or two axes
+     * are not supported.
+     */
+    ACCELEROMETER_LIMITED_AXES = 38,
+
+    /**
+     * GYROSCOPE_LIMITED_AXES
+     * reporting-mode: continuous
+     *
+     * Equivalent to GYROSCOPE, but supporting cases where one or two axes are
+     * not supported.
+     */
+    GYROSCOPE_LIMITED_AXES = 39,
+
+    /**
+     * ACCELEROMETER_LIMITED_AXES_UNCALIBRATED
+     * reporting-mode: continuous
+     *
+     * Equivalent to ACCELEROMETER_UNCALIBRATED, but supporting cases where one
+     * or two axes are not supported.
+     */
+    ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40,
+
+    /**
+     * GYROSCOPE_LIMITED_AXES_UNCALIBRATED
+     * reporting-mode: continuous
+     *
+     * Equivalent to GYROSCOPE_UNCALIBRATED, but supporting cases where one or
+     * two axes are not supported.
+     */
+    GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41,
+
+    /**
+     * HEADING
+     * reporting-mode: continuous
+     *
+     * A sensor of this type measures the direction in which the device is
+     * pointing relative to true north in degrees.
+     *
+     * This sensor was added for automotive form factors. Other devices with a
+     * clear forward direction might find it useful as well. However, devices
+     * with a more ambiguous orientation such as phones or wearables might want
+     * to consider using other sensors such as Sensor.TYPE_ROTATION_VECTOR
+     * which might be more suitable.
+     */
+    HEADING = 42,
+
+    /**
+     * Base for device manufacturers private sensor types.
+     * These sensor types can't be exposed in the SDK.
+     */
+    DEVICE_PRIVATE_BASE = 0x10000,
+}
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
new file mode 100644
index 0000000..49841a4
--- /dev/null
+++ b/sensors/aidl/default/Android.bp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "libsensorsexampleimpl",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libfmq",
+        "libpower",
+        "libbinder_ndk",
+        "android.hardware.sensors-V1-ndk",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "Sensors.cpp",
+        "Sensor.cpp",
+    ],
+    visibility: [
+        ":__subpackages__",
+        "//hardware/interfaces/tests/extension/sensors:__subpackages__",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.sensors-service.example",
+    relative_install_path: "hw",
+    init_rc: ["sensors-default.rc"],
+    vintf_fragments: ["sensors-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libfmq",
+        "libpower",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "android.hardware.sensors-V1-ndk",
+    ],
+    static_libs: [
+        "libsensorsexampleimpl",
+    ],
+    srcs: ["main.cpp"],
+}
diff --git a/sensors/aidl/default/Sensor.cpp b/sensors/aidl/default/Sensor.cpp
new file mode 100644
index 0000000..50d8841
--- /dev/null
+++ b/sensors/aidl/default/Sensor.cpp
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sensors-impl/Sensor.h"
+
+#include "utils/SystemClock.h"
+
+#include <cmath>
+
+using ::ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+static constexpr int32_t kDefaultMaxDelayUs = 10 * 1000 * 1000;
+
+Sensor::Sensor(ISensorsEventCallback* callback)
+    : mIsEnabled(false),
+      mSamplingPeriodNs(0),
+      mLastSampleTimeNs(0),
+      mCallback(callback),
+      mMode(OperationMode::NORMAL) {
+    mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+    std::unique_lock<std::mutex> lock(mRunMutex);
+    mStopThread = true;
+    mIsEnabled = false;
+    mWaitCV.notify_all();
+    lock.release();
+    mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+    return mSensorInfo;
+}
+
+void Sensor::batch(int64_t samplingPeriodNs) {
+    if (samplingPeriodNs < mSensorInfo.minDelayUs * 1000ll) {
+        samplingPeriodNs = mSensorInfo.minDelayUs * 1000ll;
+    } else if (samplingPeriodNs > mSensorInfo.maxDelayUs * 1000ll) {
+        samplingPeriodNs = mSensorInfo.maxDelayUs * 1000ll;
+    }
+
+    if (mSamplingPeriodNs != samplingPeriodNs) {
+        mSamplingPeriodNs = samplingPeriodNs;
+        // Wake up the 'run' thread to check if a new event should be generated now
+        mWaitCV.notify_all();
+    }
+}
+
+void Sensor::activate(bool enable) {
+    if (mIsEnabled != enable) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mIsEnabled = enable;
+        mWaitCV.notify_all();
+    }
+}
+
+ScopedAStatus Sensor::flush() {
+    // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+    // one-shot sensor.
+    if (!mIsEnabled ||
+        (mSensorInfo.flags & static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE))) {
+        return ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(BnSensors::ERROR_BAD_VALUE));
+    }
+
+    // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+    // to the Event FMQ prior to writing the flush complete event.
+    Event ev;
+    ev.sensorHandle = mSensorInfo.sensorHandle;
+    ev.sensorType = SensorType::META_DATA;
+    EventPayload::MetaData meta = {
+            .what = MetaDataEventType::META_DATA_FLUSH_COMPLETE,
+    };
+    ev.payload.set<EventPayload::Tag::meta>(meta);
+    std::vector<Event> evs{ev};
+    mCallback->postEvents(evs, isWakeUpSensor());
+
+    return ScopedAStatus::ok();
+}
+
+void Sensor::startThread(Sensor* sensor) {
+    sensor->run();
+}
+
+void Sensor::run() {
+    std::unique_lock<std::mutex> runLock(mRunMutex);
+    constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+    while (!mStopThread) {
+        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+            mWaitCV.wait(runLock, [&] {
+                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+            });
+        } else {
+            timespec curTime;
+            clock_gettime(CLOCK_BOOTTIME, &curTime);
+            int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+            int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+            if (now >= nextSampleTime) {
+                mLastSampleTimeNs = now;
+                nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+                mCallback->postEvents(readEvents(), isWakeUpSensor());
+            }
+
+            mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+        }
+    }
+}
+
+bool Sensor::isWakeUpSensor() {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    memset(&event.payload, 0, sizeof(event.payload));
+    readEventPayload(event.payload);
+    events.push_back(event);
+    return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+    if (mMode != mode) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mMode = mode;
+        mWaitCV.notify_all();
+    }
+}
+
+bool Sensor::supportsDataInjection() const {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
+}
+
+ScopedAStatus Sensor::injectEvent(const Event& event) {
+    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+        return ScopedAStatus::ok();
+        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+        // environment data into the device.
+    }
+
+    if (!supportsDataInjection()) {
+        return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+
+    if (mMode == OperationMode::DATA_INJECTION) {
+        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+        return ScopedAStatus::ok();
+    }
+
+    return ScopedAStatus::fromServiceSpecificError(
+            static_cast<int32_t>(BnSensors::ERROR_BAD_VALUE));
+}
+
+OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback)
+    : Sensor(callback), mPreviousEventSet(false) {}
+
+void OnChangeSensor::activate(bool enable) {
+    Sensor::activate(enable);
+    if (!enable) {
+        mPreviousEventSet = false;
+    }
+}
+
+std::vector<Event> OnChangeSensor::readEvents() {
+    std::vector<Event> events = Sensor::readEvents();
+    std::vector<Event> outputEvents;
+
+    for (auto iter = events.begin(); iter != events.end(); ++iter) {
+        Event ev = *iter;
+        if (!mPreviousEventSet ||
+            memcmp(&mPreviousEvent.payload, &ev.payload, sizeof(ev.payload)) != 0) {
+            outputEvents.push_back(ev);
+            mPreviousEvent = ev;
+            mPreviousEventSet = true;
+        }
+    }
+    return outputEvents;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Accel Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::ACCELEROMETER;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 78.4f;  // +/- 8g
+    mSensorInfo.resolution = 1.52e-5;
+    mSensorInfo.power = 0.001f;          // mA
+    mSensorInfo.minDelayUs = 10 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
+};
+
+void AccelSensor::readEventPayload(EventPayload& payload) {
+    EventPayload::Vec3 vec3 = {
+            .x = 0,
+            .y = 0,
+            .z = -9.8,
+            .status = SensorStatus::ACCURACY_HIGH,
+    };
+    payload.set<EventPayload::Tag::vec3>(vec3);
+}
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Pressure Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::PRESSURE;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 1100.0f;       // hPa
+    mSensorInfo.resolution = 0.005f;      // hPa
+    mSensorInfo.power = 0.001f;           // mA
+    mSensorInfo.minDelayUs = 100 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+};
+
+void PressureSensor::readEventPayload(EventPayload& payload) {
+    payload.set<EventPayload::Tag::scalar>(1013.25f);
+}
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Magnetic Field Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 1300.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;          // mA
+    mSensorInfo.minDelayUs = 20 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+};
+
+void MagnetometerSensor::readEventPayload(EventPayload& payload) {
+    EventPayload::Vec3 vec3 = {
+            .x = 100.0,
+            .y = 0,
+            .z = 50.0,
+            .status = SensorStatus::ACCURACY_HIGH,
+    };
+    payload.set<EventPayload::Tag::vec3>(vec3);
+}
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Light Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::LIGHT;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 43000.0f;
+    mSensorInfo.resolution = 10.0f;
+    mSensorInfo.power = 0.001f;           // mA
+    mSensorInfo.minDelayUs = 200 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE);
+};
+
+void LightSensor::readEventPayload(EventPayload& payload) {
+    payload.set<EventPayload::Tag::scalar>(80.0f);
+}
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Proximity Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::PROXIMITY;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 5.0f;
+    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.power = 0.012f;           // mA
+    mSensorInfo.minDelayUs = 200 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE |
+                                              SensorInfo::SENSOR_FLAG_BITS_WAKE_UP);
+};
+
+void ProximitySensor::readEventPayload(EventPayload& payload) {
+    payload.set<EventPayload::Tag::scalar>(2.5f);
+}
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Gyro Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::GYROSCOPE;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelayUs = 10 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+};
+
+void GyroSensor::readEventPayload(EventPayload& payload) {
+    EventPayload::Vec3 vec3 = {
+            .x = 0,
+            .y = 0,
+            .z = 0,
+            .status = SensorStatus::ACCURACY_HIGH,
+    };
+    payload.set<EventPayload::Tag::vec3>(vec3);
+}
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Ambient Temp Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelayUs = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE);
+};
+
+void AmbientTempSensor::readEventPayload(EventPayload& payload) {
+    payload.set<EventPayload::Tag::scalar>(40.0f);
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+                                               ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Relative Humidity Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 100.0f;
+    mSensorInfo.resolution = 0.1f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelayUs = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE);
+}
+
+void RelativeHumiditySensor::readEventPayload(EventPayload& payload) {
+    payload.set<EventPayload::Tag::scalar>(50.0f);
+}
+
+HingeAngleSensor::HingeAngleSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Hinge Angle Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::HINGE_ANGLE;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 360.0f;
+    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelayUs = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE |
+                                              SensorInfo::SENSOR_FLAG_BITS_WAKE_UP |
+                                              SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
+}
+
+void HingeAngleSensor::readEventPayload(EventPayload& payload) {
+    payload.set<EventPayload::Tag::scalar>(180.0f);
+}
+
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/Sensors.cpp b/sensors/aidl/default/Sensors.cpp
new file mode 100644
index 0000000..65dd304
--- /dev/null
+++ b/sensors/aidl/default/Sensors.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sensors-impl/Sensors.h"
+
+#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::sensors::Event;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::ISensorsCallback;
+using ::aidl::android::hardware::sensors::SensorInfo;
+using ::ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+ScopedAStatus Sensors::activate(int32_t in_sensorHandle, bool in_enabled) {
+    auto sensor = mSensors.find(in_sensorHandle);
+    if (sensor != mSensors.end()) {
+        sensor->second->activate(in_enabled);
+        return ScopedAStatus::ok();
+    }
+
+    return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ScopedAStatus Sensors::batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
+                             int64_t /* in_maxReportLatencyNs */) {
+    auto sensor = mSensors.find(in_sensorHandle);
+    if (sensor != mSensors.end()) {
+        sensor->second->batch(in_samplingPeriodNs);
+        return ScopedAStatus::ok();
+    }
+
+    return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ScopedAStatus Sensors::configDirectReport(int32_t /* in_sensorHandle */,
+                                          int32_t /* in_channelHandle */,
+                                          ISensors::RateLevel /* in_rate */,
+                                          int32_t* _aidl_return) {
+    *_aidl_return = EX_UNSUPPORTED_OPERATION;
+
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus Sensors::flush(int32_t in_sensorHandle) {
+    auto sensor = mSensors.find(in_sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->flush();
+    }
+
+    return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ScopedAStatus Sensors::getSensorsList(std::vector<SensorInfo>* _aidl_return) {
+    for (const auto& sensor : mSensors) {
+        _aidl_return->push_back(sensor.second->getSensorInfo());
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Sensors::initialize(
+        const MQDescriptor<Event, SynchronizedReadWrite>& in_eventQueueDescriptor,
+        const MQDescriptor<int32_t, SynchronizedReadWrite>& in_wakeLockDescriptor,
+        const std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback>&
+                in_sensorsCallback) {
+    ScopedAStatus result = ScopedAStatus::ok();
+
+    mEventQueue = std::make_unique<AidlMessageQueue<Event, SynchronizedReadWrite>>(
+            in_eventQueueDescriptor, true /* resetPointers */);
+
+    // Ensure that all sensors are disabled.
+    for (auto sensor : mSensors) {
+        sensor.second->activate(false);
+    }
+
+    // Stop the Wake Lock thread if it is currently running
+    if (mReadWakeLockQueueRun.load()) {
+        mReadWakeLockQueueRun = false;
+        mWakeLockThread.join();
+    }
+
+    // Save a reference to the callback
+    mCallback = in_sensorsCallback;
+
+    // Ensure that any existing EventFlag is properly deleted
+    deleteEventFlag();
+
+    // Create the EventFlag that is used to signal to the framework that sensor events have been
+    // written to the Event FMQ
+    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+        result = ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
+    // events have been successfully read and handled by the framework.
+    mWakeLockQueue = std::make_unique<AidlMessageQueue<int32_t, SynchronizedReadWrite>>(
+            in_wakeLockDescriptor, true /* resetPointers */);
+
+    if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+        result = ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    // Start the thread to read events from the Wake Lock FMQ
+    mReadWakeLockQueueRun = true;
+    mWakeLockThread = std::thread(startReadWakeLockThread, this);
+    return result;
+}
+
+ScopedAStatus Sensors::injectSensorData(const Event& in_event) {
+    auto sensor = mSensors.find(in_event.sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->injectEvent(in_event);
+    }
+    return ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(ERROR_BAD_VALUE));
+}
+
+ScopedAStatus Sensors::registerDirectChannel(const ISensors::SharedMemInfo& /* in_mem */,
+                                             int32_t* _aidl_return) {
+    *_aidl_return = EX_UNSUPPORTED_OPERATION;
+
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus Sensors::setOperationMode(OperationMode in_mode) {
+    for (auto sensor : mSensors) {
+        sensor.second->setOperationMode(in_mode);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Sensors::unregisterDirectChannel(int32_t /* in_channelHandle */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/include/sensors-impl/Sensor.h b/sensors/aidl/default/include/sensors-impl/Sensor.h
new file mode 100644
index 0000000..e6cd3e6
--- /dev/null
+++ b/sensors/aidl/default/include/sensors-impl/Sensor.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <aidl/android/hardware/sensors/BnSensors.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+class ISensorsEventCallback {
+  public:
+    using Event = ::aidl::android::hardware::sensors::Event;
+
+    virtual ~ISensorsEventCallback(){};
+    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+  public:
+    using OperationMode = ::aidl::android::hardware::sensors::ISensors::OperationMode;
+    using Event = ::aidl::android::hardware::sensors::Event;
+    using EventPayload = ::aidl::android::hardware::sensors::Event::EventPayload;
+    using SensorInfo = ::aidl::android::hardware::sensors::SensorInfo;
+    using SensorType = ::aidl::android::hardware::sensors::SensorType;
+    using MetaDataEventType =
+            ::aidl::android::hardware::sensors::Event::EventPayload::MetaData::MetaDataEventType;
+
+    Sensor(ISensorsEventCallback* callback);
+    virtual ~Sensor();
+
+    const SensorInfo& getSensorInfo() const;
+    void batch(int64_t samplingPeriodNs);
+    virtual void activate(bool enable);
+    ndk::ScopedAStatus flush();
+
+    void setOperationMode(OperationMode mode);
+    bool supportsDataInjection() const;
+    ndk::ScopedAStatus injectEvent(const Event& event);
+
+  protected:
+    void run();
+    virtual std::vector<Event> readEvents();
+    virtual void readEventPayload(EventPayload&) = 0;
+    static void startThread(Sensor* sensor);
+
+    bool isWakeUpSensor();
+
+    bool mIsEnabled;
+    int64_t mSamplingPeriodNs;
+    int64_t mLastSampleTimeNs;
+    SensorInfo mSensorInfo;
+
+    std::atomic_bool mStopThread;
+    std::condition_variable mWaitCV;
+    std::mutex mRunMutex;
+    std::thread mRunThread;
+
+    ISensorsEventCallback* mCallback;
+
+    OperationMode mMode;
+};
+
+class OnChangeSensor : public Sensor {
+  public:
+    OnChangeSensor(ISensorsEventCallback* callback);
+
+    virtual void activate(bool enable) override;
+
+  protected:
+    virtual std::vector<Event> readEvents() override;
+
+  protected:
+    Event mPreviousEvent;
+    bool mPreviousEventSet;
+};
+
+class AccelSensor : public Sensor {
+  public:
+    AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class GyroSensor : public Sensor {
+  public:
+    GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+  public:
+    AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class PressureSensor : public Sensor {
+  public:
+    PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class MagnetometerSensor : public Sensor {
+  public:
+    MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class LightSensor : public OnChangeSensor {
+  public:
+    LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class ProximitySensor : public OnChangeSensor {
+  public:
+    ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+  public:
+    RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class HingeAngleSensor : public OnChangeSensor {
+  public:
+    HingeAngleSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    virtual void readEventPayload(EventPayload& payload) override;
+};
+
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/include/sensors-impl/Sensors.h b/sensors/aidl/default/include/sensors-impl/Sensors.h
new file mode 100644
index 0000000..e270d96
--- /dev/null
+++ b/sensors/aidl/default/include/sensors-impl/Sensors.h
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
+#include <aidl/android/hardware/sensors/BnSensors.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <map>
+#include "Sensor.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::OK;
+using ::android::status_t;
+using ::android::hardware::EventFlag;
+
+class Sensors : public BnSensors, public ISensorsEventCallback {
+    static constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
+
+  public:
+    Sensors()
+        : mEventQueueFlag(nullptr),
+          mNextHandle(1),
+          mOutstandingWakeUpEvents(0),
+          mReadWakeLockQueueRun(false),
+          mAutoReleaseWakeLockTime(0),
+          mHasWakeLock(false) {
+        AddSensor<AccelSensor>();
+        AddSensor<GyroSensor>();
+        AddSensor<AmbientTempSensor>();
+        AddSensor<PressureSensor>();
+        AddSensor<MagnetometerSensor>();
+        AddSensor<LightSensor>();
+        AddSensor<ProximitySensor>();
+        AddSensor<RelativeHumiditySensor>();
+        AddSensor<HingeAngleSensor>();
+    }
+
+    virtual ~Sensors() {
+        deleteEventFlag();
+        mReadWakeLockQueueRun = false;
+        mWakeLockThread.join();
+    }
+
+    ::ndk::ScopedAStatus activate(int32_t in_sensorHandle, bool in_enabled) override;
+    ::ndk::ScopedAStatus batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
+                               int64_t in_maxReportLatencyNs) override;
+    ::ndk::ScopedAStatus configDirectReport(
+            int32_t in_sensorHandle, int32_t in_channelHandle,
+            ::aidl::android::hardware::sensors::ISensors::RateLevel in_rate,
+            int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus flush(int32_t in_sensorHandle) override;
+    ::ndk::ScopedAStatus getSensorsList(
+            std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
+    ::ndk::ScopedAStatus initialize(
+            const ::aidl::android::hardware::common::fmq::MQDescriptor<
+                    ::aidl::android::hardware::sensors::Event,
+                    ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
+                    in_eventQueueDescriptor,
+            const ::aidl::android::hardware::common::fmq::MQDescriptor<
+                    int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
+                    in_wakeLockDescriptor,
+            const std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback>&
+                    in_sensorsCallback) override;
+    ::ndk::ScopedAStatus injectSensorData(
+            const ::aidl::android::hardware::sensors::Event& in_event) override;
+    ::ndk::ScopedAStatus registerDirectChannel(
+            const ::aidl::android::hardware::sensors::ISensors::SharedMemInfo& in_mem,
+            int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus setOperationMode(
+            ::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) override;
+    ::ndk::ScopedAStatus unregisterDirectChannel(int32_t in_channelHandle) override;
+
+    void postEvents(const std::vector<Event>& events, bool wakeup) override {
+        std::lock_guard<std::mutex> lock(mWriteLock);
+        if (mEventQueue == nullptr) {
+            return;
+        }
+        if (mEventQueue->write(&events.front(), events.size())) {
+            mEventQueueFlag->wake(
+                    static_cast<uint32_t>(BnSensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS));
+
+            if (wakeup) {
+                // Keep track of the number of outstanding WAKE_UP events in order to properly hold
+                // a wake lock until the framework has secured a wake lock
+                updateWakeLock(events.size(), 0 /* eventsHandled */);
+            }
+        }
+    }
+
+  protected:
+    // Add a new sensor
+    template <class SensorType>
+    void AddSensor() {
+        std::shared_ptr<SensorType> sensor =
+                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+    }
+
+    // Utility function to delete the Event Flag
+    void deleteEventFlag() {
+        if (mEventQueueFlag != nullptr) {
+            status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag);
+            if (status != OK) {
+                ALOGI("Failed to delete event flag: %d", status);
+            }
+        }
+    }
+
+    static void startReadWakeLockThread(Sensors* sensors) { sensors->readWakeLockFMQ(); }
+
+    // Function to read the Wake Lock FMQ and release the wake lock when appropriate
+    void readWakeLockFMQ() {
+        while (mReadWakeLockQueueRun.load()) {
+            constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000;  // 500 ms
+            int32_t eventsHandled = 0;
+
+            // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to
+            // ensure that any held wake lock is able to be released if it is held for too long.
+            mWakeLockQueue->readBlocking(
+                    &eventsHandled, 1 /* count */, 0 /* readNotification */,
+                    static_cast<uint32_t>(WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN), kReadTimeoutNs);
+            updateWakeLock(0 /* eventsWritten */, eventsHandled);
+        }
+    }
+
+    /**
+     * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
+     */
+    void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
+        std::lock_guard<std::mutex> lock(mWakeLockLock);
+        int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
+        if (newVal < 0) {
+            mOutstandingWakeUpEvents = 0;
+        } else {
+            mOutstandingWakeUpEvents = newVal;
+        }
+
+        if (eventsWritten > 0) {
+            // Update the time at which the last WAKE_UP event was sent
+            mAutoReleaseWakeLockTime = ::android::uptimeMillis() +
+                                       static_cast<uint32_t>(WAKE_LOCK_TIMEOUT_SECONDS) * 1000;
+        }
+
+        if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
+            acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
+            mHasWakeLock = true;
+        } else if (mHasWakeLock) {
+            // Check if the wake lock should be released automatically if
+            // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written
+            // to the Wake Lock FMQ.
+            if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
+                ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
+                      WAKE_LOCK_TIMEOUT_SECONDS);
+                mOutstandingWakeUpEvents = 0;
+            }
+
+            if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
+                mHasWakeLock = false;
+            }
+        }
+    }
+
+  private:
+    // The Event FMQ where sensor events are written
+    std::unique_ptr<AidlMessageQueue<Event, SynchronizedReadWrite>> mEventQueue;
+    // The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+    std::unique_ptr<AidlMessageQueue<int32_t, SynchronizedReadWrite>> mWakeLockQueue;
+    // Event Flag to signal to the framework when sensor events are available to be read
+    EventFlag* mEventQueueFlag;
+    // Callback for asynchronous events, such as dynamic sensor connections.
+    std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> mCallback;
+    // A map of the available sensors.
+    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+    // The next available sensor handle.
+    int32_t mNextHandle;
+    // Lock to protect writes to the FMQs.
+    std::mutex mWriteLock;
+    // Lock to protect acquiring and releasing the wake lock
+    std::mutex mWakeLockLock;
+    // Track the number of WAKE_UP events that have not been handled by the framework
+    uint32_t mOutstandingWakeUpEvents;
+    // A thread to read the Wake Lock FMQ
+    std::thread mWakeLockThread;
+    // Flag to indicate that the Wake Lock Thread should continue to run
+    std::atomic_bool mReadWakeLockQueueRun;
+    // Track the time when the wake lock should automatically be released
+    int64_t mAutoReleaseWakeLockTime;
+    // Flag to indicate if a wake lock has been acquired
+    bool mHasWakeLock;
+};
+
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/main.cpp b/sensors/aidl/default/main.cpp
new file mode 100644
index 0000000..8a5a7de
--- /dev/null
+++ b/sensors/aidl/default/main.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sensors-impl/Sensors.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::sensors::Sensors;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // Make a default sensors service
+    auto sensor = ndk::SharedRefBase::make<Sensors>();
+    const std::string sensorName = std::string() + Sensors::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(sensor->asBinder().get(), sensorName.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/sensors/aidl/default/multihal/Android.bp b/sensors/aidl/default/multihal/Android.bp
new file mode 100644
index 0000000..eee1062
--- /dev/null
+++ b/sensors/aidl/default/multihal/Android.bp
@@ -0,0 +1,58 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "android.hardware.sensors@aidl-multihal",
+    vendor: true,
+    header_libs: [
+        "android.hardware.sensors@2.X-multihal.header",
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "libfmq",
+        "libpower",
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "android.hardware.sensors-V1-ndk",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "HalProxyAidl.cpp",
+        "ConvertUtils.cpp",
+    ],
+    visibility: [
+        ":__subpackages__",
+        "//hardware/interfaces/sensors/aidl/multihal:__subpackages__",
+        "//hardware/interfaces/tests/extension/sensors:__subpackages__",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-multihal",
+        "libaidlcommonsupport",
+    ],
+}
diff --git a/sensors/aidl/default/multihal/ConvertUtils.cpp b/sensors/aidl/default/multihal/ConvertUtils.cpp
new file mode 100644
index 0000000..509bbb0
--- /dev/null
+++ b/sensors/aidl/default/multihal/ConvertUtils.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConvertUtils.h"
+#include <android-base/logging.h>
+#include <log/log.h>
+
+using AidlSensorInfo = ::aidl::android::hardware::sensors::SensorInfo;
+using AidlSensorType = ::aidl::android::hardware::sensors::SensorType;
+using AidlEvent = ::aidl::android::hardware::sensors::Event;
+using AidlSensorStatus = ::aidl::android::hardware::sensors::SensorStatus;
+using ::aidl::android::hardware::sensors::AdditionalInfo;
+using ::aidl::android::hardware::sensors::DynamicSensorInfo;
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using V1_0SensorStatus = ::android::hardware::sensors::V1_0::SensorStatus;
+using ::android::hardware::sensors::V1_0::AdditionalInfoType;
+using V2_1SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
+using V2_1Event = ::android::hardware::sensors::V2_1::Event;
+using V2_1SensorType = ::android::hardware::sensors::V2_1::SensorType;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+AidlSensorInfo convertSensorInfo(const V2_1SensorInfo& sensorInfo) {
+    AidlSensorInfo aidlSensorInfo;
+    aidlSensorInfo.sensorHandle = sensorInfo.sensorHandle;
+    aidlSensorInfo.name = sensorInfo.name;
+    aidlSensorInfo.vendor = sensorInfo.vendor;
+    aidlSensorInfo.version = sensorInfo.version;
+    aidlSensorInfo.type = (AidlSensorType)sensorInfo.type;
+    aidlSensorInfo.typeAsString = sensorInfo.typeAsString;
+    aidlSensorInfo.maxRange = sensorInfo.maxRange;
+    aidlSensorInfo.resolution = sensorInfo.resolution;
+    aidlSensorInfo.power = sensorInfo.power;
+    aidlSensorInfo.minDelayUs = sensorInfo.minDelay;
+    aidlSensorInfo.fifoReservedEventCount = sensorInfo.fifoReservedEventCount;
+    aidlSensorInfo.fifoMaxEventCount = sensorInfo.fifoMaxEventCount;
+    aidlSensorInfo.requiredPermission = sensorInfo.requiredPermission;
+    aidlSensorInfo.maxDelayUs = sensorInfo.maxDelay;
+    aidlSensorInfo.flags = sensorInfo.flags;
+    return aidlSensorInfo;
+}
+
+void convertToHidlEvent(const AidlEvent& aidlEvent, V2_1Event* hidlEvent) {
+    hidlEvent->timestamp = aidlEvent.timestamp;
+    hidlEvent->sensorHandle = aidlEvent.sensorHandle;
+    hidlEvent->sensorType = (V2_1SensorType)aidlEvent.sensorType;
+
+    switch (aidlEvent.sensorType) {
+        case AidlSensorType::META_DATA:
+            hidlEvent->u.meta.what =
+                    (MetaDataEventType)aidlEvent.payload.get<Event::EventPayload::meta>().what;
+            break;
+        case AidlSensorType::ACCELEROMETER:
+        case AidlSensorType::MAGNETIC_FIELD:
+        case AidlSensorType::ORIENTATION:
+        case AidlSensorType::GYROSCOPE:
+        case AidlSensorType::GRAVITY:
+        case AidlSensorType::LINEAR_ACCELERATION:
+            hidlEvent->u.vec3.x = aidlEvent.payload.get<Event::EventPayload::vec3>().x;
+            hidlEvent->u.vec3.y = aidlEvent.payload.get<Event::EventPayload::vec3>().y;
+            hidlEvent->u.vec3.z = aidlEvent.payload.get<Event::EventPayload::vec3>().z;
+            break;
+        case AidlSensorType::GAME_ROTATION_VECTOR:
+            hidlEvent->u.vec4.x = aidlEvent.payload.get<Event::EventPayload::vec4>().x;
+            hidlEvent->u.vec4.y = aidlEvent.payload.get<Event::EventPayload::vec4>().y;
+            hidlEvent->u.vec4.z = aidlEvent.payload.get<Event::EventPayload::vec4>().z;
+            hidlEvent->u.vec4.w = aidlEvent.payload.get<Event::EventPayload::vec4>().w;
+            break;
+        case AidlSensorType::ROTATION_VECTOR:
+        case AidlSensorType::GEOMAGNETIC_ROTATION_VECTOR:
+            std::copy(aidlEvent.payload.get<Event::EventPayload::data>().values.data(),
+                      aidlEvent.payload.get<Event::EventPayload::data>().values.data() + 5,
+                      hidlEvent->u.data.data());
+            break;
+        case AidlSensorType::ACCELEROMETER_UNCALIBRATED:
+        case AidlSensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case AidlSensorType::GYROSCOPE_UNCALIBRATED:
+            hidlEvent->u.uncal.x = aidlEvent.payload.get<Event::EventPayload::uncal>().x;
+            hidlEvent->u.uncal.y = aidlEvent.payload.get<Event::EventPayload::uncal>().y;
+            hidlEvent->u.uncal.z = aidlEvent.payload.get<Event::EventPayload::uncal>().z;
+            hidlEvent->u.uncal.x_bias = aidlEvent.payload.get<Event::EventPayload::uncal>().xBias;
+            hidlEvent->u.uncal.y_bias = aidlEvent.payload.get<Event::EventPayload::uncal>().yBias;
+            hidlEvent->u.uncal.z_bias = aidlEvent.payload.get<Event::EventPayload::uncal>().zBias;
+            break;
+        case AidlSensorType::DEVICE_ORIENTATION:
+        case AidlSensorType::LIGHT:
+        case AidlSensorType::PRESSURE:
+        case AidlSensorType::PROXIMITY:
+        case AidlSensorType::RELATIVE_HUMIDITY:
+        case AidlSensorType::AMBIENT_TEMPERATURE:
+        case AidlSensorType::SIGNIFICANT_MOTION:
+        case AidlSensorType::STEP_DETECTOR:
+        case AidlSensorType::TILT_DETECTOR:
+        case AidlSensorType::WAKE_GESTURE:
+        case AidlSensorType::GLANCE_GESTURE:
+        case AidlSensorType::PICK_UP_GESTURE:
+        case AidlSensorType::WRIST_TILT_GESTURE:
+        case AidlSensorType::STATIONARY_DETECT:
+        case AidlSensorType::MOTION_DETECT:
+        case AidlSensorType::HEART_BEAT:
+        case AidlSensorType::LOW_LATENCY_OFFBODY_DETECT:
+        case AidlSensorType::HINGE_ANGLE:
+            hidlEvent->u.scalar = aidlEvent.payload.get<Event::EventPayload::scalar>();
+            break;
+        case AidlSensorType::STEP_COUNTER:
+            hidlEvent->u.stepCount = aidlEvent.payload.get<AidlEvent::EventPayload::stepCount>();
+            break;
+        case AidlSensorType::HEART_RATE:
+            hidlEvent->u.heartRate.bpm =
+                    aidlEvent.payload.get<AidlEvent::EventPayload::heartRate>().bpm;
+            hidlEvent->u.heartRate.status =
+                    (V1_0SensorStatus)aidlEvent.payload.get<Event::EventPayload::heartRate>()
+                            .status;
+            break;
+        case AidlSensorType::POSE_6DOF:
+            std::copy(std::begin(aidlEvent.payload.get<AidlEvent::EventPayload::pose6DOF>().values),
+                      std::end(aidlEvent.payload.get<AidlEvent::EventPayload::pose6DOF>().values),
+                      hidlEvent->u.pose6DOF.data());
+            break;
+        case AidlSensorType::DYNAMIC_SENSOR_META:
+            hidlEvent->u.dynamic.connected =
+                    aidlEvent.payload.get<Event::EventPayload::dynamic>().connected;
+            hidlEvent->u.dynamic.sensorHandle =
+                    aidlEvent.payload.get<Event::EventPayload::dynamic>().sensorHandle;
+            std::copy(
+                    std::begin(
+                            aidlEvent.payload.get<AidlEvent::EventPayload::dynamic>().uuid.values),
+                    std::end(aidlEvent.payload.get<AidlEvent::EventPayload::dynamic>().uuid.values),
+                    hidlEvent->u.dynamic.uuid.data());
+            break;
+        case AidlSensorType::ADDITIONAL_INFO: {
+            const AdditionalInfo& additionalInfo =
+                    aidlEvent.payload.get<AidlEvent::EventPayload::additional>();
+            hidlEvent->u.additional.type = (AdditionalInfoType)additionalInfo.type;
+            hidlEvent->u.additional.serial = additionalInfo.serial;
+
+            switch (additionalInfo.payload.getTag()) {
+                case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
+                    const auto& aidlData =
+                            additionalInfo.payload
+                                    .get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
+                                    .values;
+                    std::copy(std::begin(aidlData), std::end(aidlData),
+                              hidlEvent->u.additional.u.data_int32.data());
+                    break;
+                }
+                case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
+                    const auto& aidlData =
+                            additionalInfo.payload
+                                    .get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
+                                    .values;
+                    std::copy(std::begin(aidlData), std::end(aidlData),
+                              hidlEvent->u.additional.u.data_float.data());
+                    break;
+                }
+                default:
+                    ALOGE("Invalid sensor additioanl info tag: %d",
+                          additionalInfo.payload.getTag());
+                    break;
+            }
+            break;
+        }
+        default:
+            CHECK_GE((int32_t)aidlEvent.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+            std::copy(std::begin(aidlEvent.payload.get<AidlEvent::EventPayload::data>().values),
+                      std::end(aidlEvent.payload.get<AidlEvent::EventPayload::data>().values),
+                      hidlEvent->u.data.data());
+            break;
+    }
+}
+
+void convertToAidlEvent(const V2_1Event& hidlEvent, AidlEvent* aidlEvent) {
+    aidlEvent->timestamp = hidlEvent.timestamp;
+    aidlEvent->sensorHandle = hidlEvent.sensorHandle;
+    aidlEvent->sensorType = (AidlSensorType)hidlEvent.sensorType;
+    switch (hidlEvent.sensorType) {
+        case V2_1SensorType::META_DATA: {
+            AidlEvent::EventPayload::MetaData meta;
+            meta.what = (Event::EventPayload::MetaData::MetaDataEventType)hidlEvent.u.meta.what;
+            aidlEvent->payload.set<Event::EventPayload::meta>(meta);
+            break;
+        }
+        case V2_1SensorType::ACCELEROMETER:
+        case V2_1SensorType::MAGNETIC_FIELD:
+        case V2_1SensorType::ORIENTATION:
+        case V2_1SensorType::GYROSCOPE:
+        case V2_1SensorType::GRAVITY:
+        case V2_1SensorType::LINEAR_ACCELERATION: {
+            AidlEvent::EventPayload::Vec3 vec3;
+            vec3.x = hidlEvent.u.vec3.x;
+            vec3.y = hidlEvent.u.vec3.y;
+            vec3.z = hidlEvent.u.vec3.z;
+            aidlEvent->payload.set<Event::EventPayload::vec3>(vec3);
+            break;
+        }
+        case V2_1SensorType::GAME_ROTATION_VECTOR: {
+            AidlEvent::EventPayload::Vec4 vec4;
+            vec4.x = hidlEvent.u.vec4.x;
+            vec4.y = hidlEvent.u.vec4.y;
+            vec4.z = hidlEvent.u.vec4.z;
+            vec4.w = hidlEvent.u.vec4.w;
+            aidlEvent->payload.set<Event::EventPayload::vec4>(vec4);
+            break;
+        }
+        case V2_1SensorType::ROTATION_VECTOR:
+        case V2_1SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+            AidlEvent::EventPayload::Data data;
+            std::copy(hidlEvent.u.data.data(), hidlEvent.u.data.data() + 5,
+                      std::begin(data.values));
+            aidlEvent->payload.set<Event::EventPayload::data>(data);
+            break;
+        }
+        case V2_1SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case V2_1SensorType::GYROSCOPE_UNCALIBRATED:
+        case V2_1SensorType::ACCELEROMETER_UNCALIBRATED: {
+            AidlEvent::EventPayload::Uncal uncal;
+            uncal.x = hidlEvent.u.uncal.x;
+            uncal.y = hidlEvent.u.uncal.y;
+            uncal.z = hidlEvent.u.uncal.z;
+            uncal.xBias = hidlEvent.u.uncal.x_bias;
+            uncal.yBias = hidlEvent.u.uncal.y_bias;
+            uncal.zBias = hidlEvent.u.uncal.z_bias;
+            aidlEvent->payload.set<Event::EventPayload::uncal>(uncal);
+            break;
+        }
+        case V2_1SensorType::DEVICE_ORIENTATION:
+        case V2_1SensorType::LIGHT:
+        case V2_1SensorType::PRESSURE:
+        case V2_1SensorType::PROXIMITY:
+        case V2_1SensorType::RELATIVE_HUMIDITY:
+        case V2_1SensorType::AMBIENT_TEMPERATURE:
+        case V2_1SensorType::SIGNIFICANT_MOTION:
+        case V2_1SensorType::STEP_DETECTOR:
+        case V2_1SensorType::TILT_DETECTOR:
+        case V2_1SensorType::WAKE_GESTURE:
+        case V2_1SensorType::GLANCE_GESTURE:
+        case V2_1SensorType::PICK_UP_GESTURE:
+        case V2_1SensorType::WRIST_TILT_GESTURE:
+        case V2_1SensorType::STATIONARY_DETECT:
+        case V2_1SensorType::MOTION_DETECT:
+        case V2_1SensorType::HEART_BEAT:
+        case V2_1SensorType::LOW_LATENCY_OFFBODY_DETECT:
+        case V2_1SensorType::HINGE_ANGLE:
+            aidlEvent->payload.set<Event::EventPayload::scalar>(hidlEvent.u.scalar);
+            break;
+        case V2_1SensorType::STEP_COUNTER:
+            aidlEvent->payload.set<Event::EventPayload::stepCount>(hidlEvent.u.stepCount);
+            break;
+        case V2_1SensorType::HEART_RATE: {
+            AidlEvent::EventPayload::HeartRate heartRate;
+            heartRate.bpm = hidlEvent.u.heartRate.bpm;
+            heartRate.status = (SensorStatus)hidlEvent.u.heartRate.status;
+            aidlEvent->payload.set<Event::EventPayload::heartRate>(heartRate);
+            break;
+        }
+        case V2_1SensorType::POSE_6DOF: {
+            AidlEvent::EventPayload::Pose6Dof pose6Dof;
+            std::copy(hidlEvent.u.pose6DOF.data(),
+                      hidlEvent.u.pose6DOF.data() + hidlEvent.u.pose6DOF.size(),
+                      std::begin(pose6Dof.values));
+            aidlEvent->payload.set<Event::EventPayload::pose6DOF>(pose6Dof);
+            break;
+        }
+        case V2_1SensorType::DYNAMIC_SENSOR_META: {
+            DynamicSensorInfo dynamicSensorInfo;
+            dynamicSensorInfo.connected = hidlEvent.u.dynamic.connected;
+            dynamicSensorInfo.sensorHandle = hidlEvent.u.dynamic.sensorHandle;
+            std::copy(hidlEvent.u.dynamic.uuid.data(),
+                      hidlEvent.u.dynamic.uuid.data() + hidlEvent.u.dynamic.uuid.size(),
+                      std::begin(dynamicSensorInfo.uuid.values));
+            aidlEvent->payload.set<Event::EventPayload::dynamic>(dynamicSensorInfo);
+            break;
+        }
+        case V2_1SensorType::ADDITIONAL_INFO: {
+            AdditionalInfo additionalInfo;
+            additionalInfo.type = (AdditionalInfo::AdditionalInfoType)hidlEvent.u.additional.type;
+            additionalInfo.serial = hidlEvent.u.additional.serial;
+
+            AdditionalInfo::AdditionalInfoPayload::Int32Values int32Values;
+            std::copy(hidlEvent.u.additional.u.data_int32.data(),
+                      hidlEvent.u.additional.u.data_int32.data() +
+                              hidlEvent.u.additional.u.data_int32.size(),
+                      std::begin(int32Values.values));
+            additionalInfo.payload.set<AdditionalInfo::AdditionalInfoPayload::dataInt32>(
+                    int32Values);
+            aidlEvent->payload.set<Event::EventPayload::additional>(additionalInfo);
+            break;
+        }
+        default: {
+            CHECK_GE((int32_t)hidlEvent.sensorType, (int32_t)V2_1SensorType::DEVICE_PRIVATE_BASE);
+            AidlEvent::EventPayload::Data data;
+            std::copy(hidlEvent.u.data.data(), hidlEvent.u.data.data() + hidlEvent.u.data.size(),
+                      std::begin(data.values));
+            aidlEvent->payload.set<Event::EventPayload::data>(data);
+            break;
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/multihal/HalProxyAidl.cpp b/sensors/aidl/default/multihal/HalProxyAidl.cpp
new file mode 100644
index 0000000..64805e6
--- /dev/null
+++ b/sensors/aidl/default/multihal/HalProxyAidl.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "HalProxyAidl.h"
+#include <aidlcommonsupport/NativeHandle.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hidl/Status.h>
+#include "ConvertUtils.h"
+#include "EventMessageQueueWrapperAidl.h"
+#include "ISensorsCallbackWrapperAidl.h"
+#include "WakeLockMessageQueueWrapperAidl.h"
+#include "convertV2_1.h"
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::ISensorsCallback;
+using ::android::hardware::sensors::V2_1::implementation::convertToOldEvent;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+static binder_status_t resultToBinderStatus(::android::hardware::sensors::V1_0::Result result) {
+    switch (result) {
+        case ::android::hardware::sensors::V1_0::Result::OK:
+            return STATUS_OK;
+        case ::android::hardware::sensors::V1_0::Result::PERMISSION_DENIED:
+            return STATUS_PERMISSION_DENIED;
+        case ::android::hardware::sensors::V1_0::Result::NO_MEMORY:
+            return STATUS_NO_MEMORY;
+        case ::android::hardware::sensors::V1_0::Result::BAD_VALUE:
+            return STATUS_BAD_VALUE;
+        case ::android::hardware::sensors::V1_0::Result::INVALID_OPERATION:
+            return STATUS_INVALID_OPERATION;
+    }
+}
+
+static ::android::hardware::sensors::V1_0::RateLevel convertRateLevel(
+        ISensors::RateLevel rateLevel) {
+    switch (rateLevel) {
+        case ISensors::RateLevel::STOP:
+            return ::android::hardware::sensors::V1_0::RateLevel::STOP;
+        case ISensors::RateLevel::NORMAL:
+            return ::android::hardware::sensors::V1_0::RateLevel::NORMAL;
+        case ISensors::RateLevel::FAST:
+            return ::android::hardware::sensors::V1_0::RateLevel::FAST;
+        case ISensors::RateLevel::VERY_FAST:
+            return ::android::hardware::sensors::V1_0::RateLevel::VERY_FAST;
+    }
+}
+
+static ::android::hardware::sensors::V1_0::OperationMode convertOperationMode(
+        ISensors::OperationMode operationMode) {
+    switch (operationMode) {
+        case ISensors::OperationMode::NORMAL:
+            return ::android::hardware::sensors::V1_0::OperationMode::NORMAL;
+        case ISensors::OperationMode::DATA_INJECTION:
+            return ::android::hardware::sensors::V1_0::OperationMode::DATA_INJECTION;
+    }
+}
+
+static ::android::hardware::sensors::V1_0::SharedMemType convertSharedMemType(
+        ISensors::SharedMemInfo::SharedMemType sharedMemType) {
+    switch (sharedMemType) {
+        case ISensors::SharedMemInfo::SharedMemType::ASHMEM:
+            return ::android::hardware::sensors::V1_0::SharedMemType::ASHMEM;
+        case ISensors::SharedMemInfo::SharedMemType::GRALLOC:
+            return ::android::hardware::sensors::V1_0::SharedMemType::GRALLOC;
+    }
+}
+
+static ::android::hardware::sensors::V1_0::SharedMemFormat convertSharedMemFormat(
+        ISensors::SharedMemInfo::SharedMemFormat sharedMemFormat) {
+    switch (sharedMemFormat) {
+        case ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT:
+            return ::android::hardware::sensors::V1_0::SharedMemFormat::SENSORS_EVENT;
+    }
+}
+
+static ::android::hardware::sensors::V1_0::SharedMemInfo convertSharedMemInfo(
+        const ISensors::SharedMemInfo& sharedMemInfo) {
+    ::android::hardware::sensors::V1_0::SharedMemInfo v1SharedMemInfo;
+    v1SharedMemInfo.type = convertSharedMemType(sharedMemInfo.type);
+    v1SharedMemInfo.format = convertSharedMemFormat(sharedMemInfo.format);
+    v1SharedMemInfo.size = sharedMemInfo.size;
+    v1SharedMemInfo.memoryHandle =
+            ::android::hardware::hidl_handle(::android::makeFromAidl(sharedMemInfo.memoryHandle));
+    return v1SharedMemInfo;
+}
+
+::ndk::ScopedAStatus HalProxyAidl::activate(int32_t in_sensorHandle, bool in_enabled) {
+    return ndk::ScopedAStatus::fromStatus(
+            resultToBinderStatus(HalProxy::activate(in_sensorHandle, in_enabled)));
+}
+
+::ndk::ScopedAStatus HalProxyAidl::batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
+                                         int64_t in_maxReportLatencyNs) {
+    return ndk::ScopedAStatus::fromStatus(resultToBinderStatus(
+            HalProxy::batch(in_sensorHandle, in_samplingPeriodNs, in_maxReportLatencyNs)));
+}
+
+::ndk::ScopedAStatus HalProxyAidl::configDirectReport(int32_t in_sensorHandle,
+                                                      int32_t in_channelHandle,
+                                                      ISensors::RateLevel in_rate,
+                                                      int32_t* _aidl_return) {
+    binder_status_t binderStatus;
+    HalProxy::configDirectReport(
+            in_sensorHandle, in_channelHandle, convertRateLevel(in_rate),
+            [&binderStatus, _aidl_return](::android::hardware::sensors::V1_0::Result result,
+                                          int32_t reportToken) {
+                binderStatus = resultToBinderStatus(result);
+                *_aidl_return = reportToken;
+            });
+    return ndk::ScopedAStatus::fromStatus(binderStatus);
+}
+
+::ndk::ScopedAStatus HalProxyAidl::flush(int32_t in_sensorHandle) {
+    return ndk::ScopedAStatus::fromStatus(resultToBinderStatus(HalProxy::flush(in_sensorHandle)));
+}
+
+::ndk::ScopedAStatus HalProxyAidl::getSensorsList(
+        std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) {
+    for (const auto& sensor : HalProxy::getSensors()) {
+        _aidl_return->push_back(convertSensorInfo(sensor.second));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus HalProxyAidl::initialize(
+        const MQDescriptor<::aidl::android::hardware::sensors::Event, SynchronizedReadWrite>&
+                in_eventQueueDescriptor,
+        const MQDescriptor<int32_t, SynchronizedReadWrite>& in_wakeLockDescriptor,
+        const std::shared_ptr<ISensorsCallback>& in_sensorsCallback) {
+    ::android::sp<::android::hardware::sensors::V2_1::implementation::ISensorsCallbackWrapperBase>
+            dynamicCallback = new ISensorsCallbackWrapperAidl(in_sensorsCallback);
+
+    auto aidlEventQueue =
+            std::make_unique<::android::AidlMessageQueue<::aidl::android::hardware::sensors::Event,
+                                                         SynchronizedReadWrite>>(
+                    in_eventQueueDescriptor, true /* resetPointers */);
+    std::unique_ptr<
+            ::android::hardware::sensors::V2_1::implementation::EventMessageQueueWrapperBase>
+            eventQueue = std::make_unique<EventMessageQueueWrapperAidl>(aidlEventQueue);
+
+    auto aidlWakeLockQueue =
+            std::make_unique<::android::AidlMessageQueue<int32_t, SynchronizedReadWrite>>(
+                    in_wakeLockDescriptor, true /* resetPointers */);
+    std::unique_ptr<
+            ::android::hardware::sensors::V2_1::implementation::WakeLockMessageQueueWrapperBase>
+            wakeLockQueue = std::make_unique<WakeLockMessageQueueWrapperAidl>(aidlWakeLockQueue);
+
+    return ndk::ScopedAStatus::fromStatus(
+            resultToBinderStatus(initializeCommon(eventQueue, wakeLockQueue, dynamicCallback)));
+}
+
+::ndk::ScopedAStatus HalProxyAidl::injectSensorData(
+        const ::aidl::android::hardware::sensors::Event& in_event) {
+    ::android::hardware::sensors::V2_1::Event hidlEvent;
+    convertToHidlEvent(in_event, &hidlEvent);
+    return ndk::ScopedAStatus::fromStatus(
+            resultToBinderStatus(HalProxy::injectSensorData(convertToOldEvent(hidlEvent))));
+}
+
+::ndk::ScopedAStatus HalProxyAidl::registerDirectChannel(const ISensors::SharedMemInfo& in_mem,
+                                                         int32_t* _aidl_return) {
+    binder_status_t binderStatus;
+    ::android::hardware::sensors::V1_0::SharedMemInfo sharedMemInfo = convertSharedMemInfo(in_mem);
+
+    HalProxy::registerDirectChannel(
+            sharedMemInfo,
+            [&binderStatus, _aidl_return](::android::hardware::sensors::V1_0::Result result,
+                                          int32_t reportToken) {
+                binderStatus = resultToBinderStatus(result);
+                *_aidl_return = reportToken;
+            });
+
+    native_handle_delete(
+            const_cast<native_handle_t*>(sharedMemInfo.memoryHandle.getNativeHandle()));
+    return ndk::ScopedAStatus::fromStatus(binderStatus);
+}
+
+::ndk::ScopedAStatus HalProxyAidl::setOperationMode(
+        ::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) {
+    return ndk::ScopedAStatus::fromStatus(
+            resultToBinderStatus(HalProxy::setOperationMode(convertOperationMode(in_mode))));
+}
+
+::ndk::ScopedAStatus HalProxyAidl::unregisterDirectChannel(int32_t in_channelHandle) {
+    return ndk::ScopedAStatus::fromStatus(
+            resultToBinderStatus(HalProxy::unregisterDirectChannel(in_channelHandle)));
+}
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/sensors/aidl/default/multihal/include/ConvertUtils.h b/sensors/aidl/default/multihal/include/ConvertUtils.h
new file mode 100644
index 0000000..91dfabd
--- /dev/null
+++ b/sensors/aidl/default/multihal/include/ConvertUtils.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/sensors/BnSensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+/**
+ * Generates an AIDL SensorInfo instance from the passed HIDL V2.1 SensorInfo instance.
+ */
+::aidl::android::hardware::sensors::SensorInfo convertSensorInfo(
+        const ::android::hardware::sensors::V2_1::SensorInfo& sensorInfo);
+
+/**
+ * Populates a HIDL V2.1 Event instance based on an AIDL Event instance.
+ */
+void convertToHidlEvent(const ::aidl::android::hardware::sensors::Event& aidlEvent,
+                        ::android::hardware::sensors::V2_1::Event* hidlEvent);
+
+/**
+ * Populates an AIDL Event instance based on a HIDL V2.1 Event instance.
+ */
+void convertToAidlEvent(const ::android::hardware::sensors::V2_1::Event& hidlEvent,
+                        ::aidl::android::hardware::sensors::Event* aidlEvent);
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/sensors/aidl/default/multihal/include/EventMessageQueueWrapperAidl.h b/sensors/aidl/default/multihal/include/EventMessageQueueWrapperAidl.h
new file mode 100644
index 0000000..3eaa1d4
--- /dev/null
+++ b/sensors/aidl/default/multihal/include/EventMessageQueueWrapperAidl.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <fmq/AidlMessageQueue.h>
+#include "ConvertUtils.h"
+#include "EventMessageQueueWrapper.h"
+#include "ISensorsWrapper.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+class EventMessageQueueWrapperAidl
+    : public ::android::hardware::sensors::V2_1::implementation::EventMessageQueueWrapperBase {
+  public:
+    EventMessageQueueWrapperAidl(
+            std::unique_ptr<::android::AidlMessageQueue<
+                    ::aidl::android::hardware::sensors::Event,
+                    ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>& queue)
+        : mQueue(std::move(queue)) {}
+
+    virtual std::atomic<uint32_t>* getEventFlagWord() override {
+        return mQueue->getEventFlagWord();
+    }
+
+    virtual size_t availableToRead() override { return mQueue->availableToRead(); }
+
+    size_t availableToWrite() override { return mQueue->availableToWrite(); }
+
+    virtual bool read(::android::hardware::sensors::V2_1::Event* events,
+                      size_t numToRead) override {
+        bool success = mQueue->read(mIntermediateEventBuffer.data(), numToRead);
+        for (int i = 0; i < numToRead; ++i) {
+            convertToHidlEvent(mIntermediateEventBuffer[i], &events[i]);
+        }
+        return success;
+    }
+
+    bool write(const ::android::hardware::sensors::V2_1::Event* events,
+               size_t numToWrite) override {
+        for (int i = 0; i < numToWrite; ++i) {
+            convertToAidlEvent(events[i], &mIntermediateEventBuffer[i]);
+        }
+        return mQueue->write(mIntermediateEventBuffer.data(), numToWrite);
+    }
+
+    virtual bool write(
+            const std::vector<::android::hardware::sensors::V2_1::Event>& events) override {
+        for (int i = 0; i < events.size(); ++i) {
+            convertToAidlEvent(events[i], &mIntermediateEventBuffer[i]);
+        }
+        return mQueue->write(mIntermediateEventBuffer.data(), events.size());
+    }
+
+    bool writeBlocking(const ::android::hardware::sensors::V2_1::Event* events, size_t count,
+                       uint32_t readNotification, uint32_t writeNotification, int64_t timeOutNanos,
+                       ::android::hardware::EventFlag* evFlag) override {
+        for (int i = 0; i < count; ++i) {
+            convertToAidlEvent(events[i], &mIntermediateEventBuffer[i]);
+        }
+        return mQueue->writeBlocking(mIntermediateEventBuffer.data(), count, readNotification,
+                                     writeNotification, timeOutNanos, evFlag);
+    }
+
+    size_t getQuantumCount() override { return mQueue->getQuantumCount(); }
+
+  private:
+    std::unique_ptr<::android::AidlMessageQueue<
+            ::aidl::android::hardware::sensors::Event,
+            ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
+            mQueue;
+    std::array<::aidl::android::hardware::sensors::Event,
+               ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT>
+            mIntermediateEventBuffer;
+};
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/multihal/include/HalProxyAidl.h b/sensors/aidl/default/multihal/include/HalProxyAidl.h
new file mode 100644
index 0000000..7401726
--- /dev/null
+++ b/sensors/aidl/default/multihal/include/HalProxyAidl.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/sensors/BnSensors.h>
+#include "HalProxy.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+class HalProxyAidl : public ::android::hardware::sensors::V2_1::implementation::HalProxy,
+                     public ::aidl::android::hardware::sensors::BnSensors {
+    ::ndk::ScopedAStatus activate(int32_t in_sensorHandle, bool in_enabled) override;
+    ::ndk::ScopedAStatus batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
+                               int64_t in_maxReportLatencyNs) override;
+    ::ndk::ScopedAStatus configDirectReport(
+            int32_t in_sensorHandle, int32_t in_channelHandle,
+            ::aidl::android::hardware::sensors::ISensors::RateLevel in_rate,
+            int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus flush(int32_t in_sensorHandle) override;
+    ::ndk::ScopedAStatus getSensorsList(
+            std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
+    ::ndk::ScopedAStatus initialize(
+            const ::aidl::android::hardware::common::fmq::MQDescriptor<
+                    ::aidl::android::hardware::sensors::Event,
+                    ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
+                    in_eventQueueDescriptor,
+            const ::aidl::android::hardware::common::fmq::MQDescriptor<
+                    int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
+                    in_wakeLockDescriptor,
+            const std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback>&
+                    in_sensorsCallback) override;
+    ::ndk::ScopedAStatus injectSensorData(
+            const ::aidl::android::hardware::sensors::Event& in_event) override;
+    ::ndk::ScopedAStatus registerDirectChannel(
+            const ::aidl::android::hardware::sensors::ISensors::SharedMemInfo& in_mem,
+            int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus setOperationMode(
+            ::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) override;
+    ::ndk::ScopedAStatus unregisterDirectChannel(int32_t in_channelHandle) override;
+};
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/multihal/include/ISensorsCallbackWrapperAidl.h b/sensors/aidl/default/multihal/include/ISensorsCallbackWrapperAidl.h
new file mode 100644
index 0000000..6ef6c63
--- /dev/null
+++ b/sensors/aidl/default/multihal/include/ISensorsCallbackWrapperAidl.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "ConvertUtils.h"
+#include "ISensorsCallbackWrapper.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+static std::vector<::aidl::android::hardware::sensors::SensorInfo> convertToAidlSensorInfos(
+        const ::android::hardware::hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>&
+                sensorInfos) {
+    std::vector<::aidl::android::hardware::sensors::SensorInfo> aidlSensorInfos;
+    for (const auto& sensorInfo : sensorInfos) {
+        aidlSensorInfos.push_back(convertSensorInfo(sensorInfo));
+    }
+    return aidlSensorInfos;
+}
+
+class ISensorsCallbackWrapperAidl
+    : public ::android::hardware::sensors::V2_1::implementation::ISensorsCallbackWrapperBase {
+  public:
+    ISensorsCallbackWrapperAidl(
+            std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> sensorsCallback)
+        : mSensorsCallback(sensorsCallback) {}
+
+    ::android::hardware::Return<void> onDynamicSensorsConnected(
+            const ::android::hardware::hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>&
+                    sensorInfos) override {
+        mSensorsCallback->onDynamicSensorsConnected(convertToAidlSensorInfos(sensorInfos));
+        return ::android::hardware::Void();
+    }
+
+    ::android::hardware::Return<void> onDynamicSensorsDisconnected(
+            const ::android::hardware::hidl_vec<int32_t>& sensorHandles) override {
+        mSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
+        return ::android::hardware::Void();
+    }
+
+  private:
+    std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> mSensorsCallback;
+};
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
\ No newline at end of file
diff --git a/sensors/aidl/default/multihal/include/WakeLockMessageQueueWrapperAidl.h b/sensors/aidl/default/multihal/include/WakeLockMessageQueueWrapperAidl.h
new file mode 100644
index 0000000..6be0b69
--- /dev/null
+++ b/sensors/aidl/default/multihal/include/WakeLockMessageQueueWrapperAidl.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <fmq/AidlMessageQueue.h>
+#include "WakeLockMessageQueueWrapper.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+class WakeLockMessageQueueWrapperAidl
+    : public ::android::hardware::sensors::V2_1::implementation::WakeLockMessageQueueWrapperBase {
+  public:
+    WakeLockMessageQueueWrapperAidl(
+            std::unique_ptr<::android::AidlMessageQueue<
+                    int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>& queue)
+        : mQueue(std::move(queue)) {}
+
+    virtual std::atomic<uint32_t>* getEventFlagWord() override {
+        return mQueue->getEventFlagWord();
+    }
+
+    bool readBlocking(uint32_t* wakeLocks, size_t numToRead, uint32_t readNotification,
+                      uint32_t writeNotification, int64_t timeOutNanos,
+                      ::android::hardware::EventFlag* evFlag) override {
+        return mQueue->readBlocking(reinterpret_cast<int32_t*>(wakeLocks), numToRead,
+                                    readNotification, writeNotification, timeOutNanos, evFlag);
+    }
+
+    bool write(const uint32_t* wakeLock) override {
+        return mQueue->write(reinterpret_cast<const int32_t*>(wakeLock));
+    }
+
+  private:
+    std::unique_ptr<::android::AidlMessageQueue<
+            int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
+            mQueue;
+};
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/sensors/aidl/default/sensors-default.rc b/sensors/aidl/default/sensors-default.rc
new file mode 100644
index 0000000..96da85d
--- /dev/null
+++ b/sensors/aidl/default/sensors-default.rc
@@ -0,0 +1,5 @@
+service vendor.sensors-default /vendor/bin/hw/android.hardware.sensors-service.example
+    class hal
+    user system
+    group system
+    rlimit rtprio 10 10
diff --git a/sensors/aidl/default/sensors-default.xml b/sensors/aidl/default/sensors-default.xml
new file mode 100644
index 0000000..7898a6b
--- /dev/null
+++ b/sensors/aidl/default/sensors-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.sensors</name>
+        <version>1</version>
+        <fqname>ISensors/default</fqname>
+    </hal>
+</manifest>
diff --git a/sensors/aidl/multihal/Android.bp b/sensors/aidl/multihal/Android.bp
new file mode 100644
index 0000000..6d35daf
--- /dev/null
+++ b/sensors/aidl/multihal/Android.bp
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.sensors-service.multihal",
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.X-multihal.header",
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    init_rc: ["android.hardware.sensors-service-multihal.rc"],
+    vintf_fragments: ["android.hardware.sensors-multihal.xml"],
+    shared_libs: [
+        "android.hardware.sensors@2.0-ScopedWakelock",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "android.hardware.sensors-V1-ndk",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libpower",
+        "libutils",
+        "libbinder_ndk",
+        "libhidlbase",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-multihal",
+        "android.hardware.sensors@aidl-multihal",
+    ],
+}
diff --git a/sensors/aidl/multihal/OWNERS b/sensors/aidl/multihal/OWNERS
new file mode 100644
index 0000000..e955670
--- /dev/null
+++ b/sensors/aidl/multihal/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
\ No newline at end of file
diff --git a/sensors/aidl/multihal/android.hardware.sensors-multihal.xml b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
new file mode 100644
index 0000000..d78edff
--- /dev/null
+++ b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ 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 version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.sensors</name>
+        <version>1</version>
+        <fqname>ISensors/default</fqname>
+    </hal>
+</manifest>
diff --git a/sensors/aidl/multihal/android.hardware.sensors-service-multihal.rc b/sensors/aidl/multihal/android.hardware.sensors-service-multihal.rc
new file mode 100644
index 0000000..3f91a0a
--- /dev/null
+++ b/sensors/aidl/multihal/android.hardware.sensors-service-multihal.rc
@@ -0,0 +1,7 @@
+service vendor.sensors-hal-multihal /vendor/bin/hw/android.hardware.sensors-service.multihal
+    class hal
+    user system
+    group system wakelock context_hub
+    task_profiles ServiceCapacityLow
+    capabilities BLOCK_SUSPEND
+    rlimit rtprio 10 10
\ No newline at end of file
diff --git a/sensors/aidl/multihal/service.cpp b/sensors/aidl/multihal/service.cpp
new file mode 100644
index 0000000..11c108a
--- /dev/null
+++ b/sensors/aidl/multihal/service.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include "HalProxyAidl.h"
+
+using ::aidl::android::hardware::sensors::implementation::HalProxyAidl;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // Make a default multihal sensors service
+    auto halProxy = ndk::SharedRefBase::make<HalProxyAidl>();
+    const std::string halProxyName = std::string() + HalProxyAidl::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(halProxy->asBinder().get(), halProxyName.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/sensors/aidl/vts/Android.bp b/sensors/aidl/vts/Android.bp
new file mode 100644
index 0000000..b5a5f15
--- /dev/null
+++ b/sensors/aidl/vts/Android.bp
@@ -0,0 +1,51 @@
+// Copyright 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsAidlHalSensorsTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsAidlHalSensorsTargetTest.cpp",
+        "SensorsAidlEnvironment.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libvndksupport",
+        "libfmq",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+    ],
+    static_libs: [
+        "android.hardware.sensors-V1-ndk",
+        "VtsHalSensorsTargetTestUtils",
+        "libaidlcommonsupport",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/sensors/aidl/vts/OWNERS b/sensors/aidl/vts/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/aidl/vts/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/aidl/vts/SensorsAidlEnvironment.cpp b/sensors/aidl/vts/SensorsAidlEnvironment.cpp
new file mode 100644
index 0000000..e71251f
--- /dev/null
+++ b/sensors/aidl/vts/SensorsAidlEnvironment.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsAidlEnvironment.h"
+
+#include <android/binder_manager.h>
+#include <log/log.h>
+
+#include <aidl/android/hardware/sensors/BnSensorsCallback.h>
+
+using aidl::android::hardware::sensors::BnSensorsCallback;
+using aidl::android::hardware::sensors::SensorInfo;
+using android::hardware::EventFlag;
+using ndk::ScopedAStatus;
+using ndk::SpAIBinder;
+
+namespace {
+
+void serviceDied(void* /* cookie */) {
+    ALOGE("Sensors HAL died (likely crashed) during test");
+    FAIL() << "Sensors HAL died during test";
+}
+
+class NoOpSensorsCallback : public BnSensorsCallback {
+  public:
+    ScopedAStatus onDynamicSensorsConnected(
+            const std::vector<SensorInfo>& /* sensorInfos */) override {
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus onDynamicSensorsDisconnected(
+            const std::vector<int32_t>& /* sensorHandles */) override {
+        return ScopedAStatus::ok();
+    }
+};
+
+}  // anonymous namespace
+
+SensorsAidlEnvironment::SensorsAidlEnvironment(const std::string& service_name)
+    : SensorsVtsEnvironmentBase(service_name),
+      mCallback(ndk::SharedRefBase::make<NoOpSensorsCallback>()),
+      mDeathRecipient(AIBinder_DeathRecipient_new(serviceDied)) {}
+
+bool SensorsAidlEnvironment::resetHal() {
+    bool succeed = false;
+    do {
+        mSensors = ISensors::fromBinder(
+                SpAIBinder(AServiceManager_waitForService(mServiceName.c_str())));
+        if (mSensors == nullptr) {
+            break;
+        }
+
+        AIBinder_linkToDeath(mSensors->asBinder().get(), mDeathRecipient.get(), this);
+
+        // Initialize FMQs
+        mWakeLockQueue = std::make_unique<WakeLockQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                                         true /* configureEventFlagWord */);
+        mEventQueue = std::make_unique<EventQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                                   true /* configureEventFlagWord */);
+
+        if (mWakeLockQueue == nullptr || mEventQueue == nullptr) {
+            break;
+        }
+
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+        EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+        if (mEventQueueFlag == nullptr) {
+            break;
+        }
+
+        mSensors->initialize(mEventQueue->dupeDesc(), mWakeLockQueue->dupeDesc(), mCallback);
+
+        std::vector<SensorInfo> sensorList;
+        if (!mSensors->getSensorsList(&sensorList).isOk()) {
+            break;
+        }
+
+        // stop each sensor individually
+        bool ok = true;
+        for (const auto& i : sensorList) {
+            if (!mSensors->activate(i.sensorHandle, false).isOk()) {
+                ok = false;
+                break;
+            }
+        }
+
+        if (!ok) {
+            break;
+        }
+
+        // mark it done
+        succeed = true;
+    } while (0);
+
+    if (!succeed) {
+        mSensors = nullptr;
+    }
+
+    return succeed;
+}
+
+void SensorsAidlEnvironment::TearDown() {
+    mStopThread = true;
+
+    if (mEventQueueFlag != nullptr) {
+        // Wake up the event queue so the poll thread can exit
+        mEventQueueFlag->wake(ISensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS);
+        if (mPollThread.joinable()) {
+            mPollThread.join();
+        }
+
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+    }
+}
+
+void SensorsAidlEnvironment::startPollingThread() {
+    mStopThread = false;
+    mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+    mPollThread = std::thread(pollingThread, this);
+}
+
+void SensorsAidlEnvironment::readEvents() {
+    size_t availableEvents = mEventQueue->availableToRead();
+
+    if (availableEvents == 0) {
+        uint32_t eventFlagState = 0;
+
+        mEventQueueFlag->wait(ISensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS, &eventFlagState);
+        availableEvents = mEventQueue->availableToRead();
+    }
+
+    size_t eventsToRead = std::min(availableEvents, mEventBuffer.size());
+    if (eventsToRead > 0) {
+        if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
+            mEventQueueFlag->wake(ISensors::EVENT_QUEUE_FLAG_BITS_EVENTS_READ);
+            for (size_t i = 0; i < eventsToRead; i++) {
+                addEvent(mEventBuffer[i]);
+            }
+        }
+    }
+}
+
+void SensorsAidlEnvironment::pollingThread(SensorsAidlEnvironment* env) {
+    ALOGD("polling thread start");
+
+    while (!env->mStopThread.load()) {
+        env->readEvents();
+    }
+
+    ALOGD("polling thread end");
+}
diff --git a/sensors/aidl/vts/SensorsAidlEnvironment.h b/sensors/aidl/vts/SensorsAidlEnvironment.h
new file mode 100644
index 0000000..2f5f287
--- /dev/null
+++ b/sensors/aidl/vts/SensorsAidlEnvironment.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSORS_AIDL_ENVIRONMENT_H
+#define ANDROID_SENSORS_AIDL_ENVIRONMENT_H
+
+#include "sensors-vts-utils/SensorsVtsEnvironmentBase.h"
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <fmq/AidlMessageQueue.h>
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::ISensorsCallback;
+
+static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 256;
+
+class SensorsAidlTest;
+
+class SensorsAidlEnvironment : public SensorsVtsEnvironmentBase<Event> {
+  public:
+    virtual void TearDown() override;
+
+  protected:
+    friend SensorsAidlTest;
+    SensorsAidlEnvironment(const std::string& service_name);
+
+    /**
+     * Resets the HAL with new FMQs and a new Event Flag
+     *
+     * @return bool true if successful, false otherwise
+     */
+    bool resetHal() override;
+
+    /**
+     * Starts the polling thread that reads sensor events from the Event FMQ
+     */
+    void startPollingThread() override;
+
+    /**
+     * Thread responsible for calling functions to read Event FMQ
+     *
+     * @param env SensorEnvironment to being polling for events on
+     */
+    static void pollingThread(SensorsAidlEnvironment* env);
+
+    /**
+     * Reads and saves sensor events from the Event FMQ
+     */
+    void readEvents();
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsAidlEnvironment);
+
+    /**
+     * Pointer to the Sensors HAL Interface that allows the test to call HAL functions.
+     */
+    std::shared_ptr<ISensors> mSensors;
+    std::shared_ptr<ISensorsCallback> mCallback;
+
+    ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+    /**
+     * Type used to simplify the creation of the Wake Lock FMQ
+     */
+    typedef android::AidlMessageQueue<int32_t, SynchronizedReadWrite> WakeLockQueue;
+    typedef android::AidlMessageQueue<Event, SynchronizedReadWrite> EventQueue;
+
+    /**
+     * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed
+     * WAKE_UP sensor events.
+     */
+    std::unique_ptr<WakeLockQueue> mWakeLockQueue;
+    std::unique_ptr<EventQueue> mEventQueue;
+
+    /**
+     * The Event Queue Flag notifies the test framework when sensor events have been written to the
+     * Event FMQ by the Sensors HAL.
+     */
+    ::android::hardware::EventFlag* mEventQueueFlag;
+
+    std::atomic_bool mStopThread;
+    std::thread mPollThread;
+
+    /**
+     * An array that is used to store sensor events read from the Event FMQ
+     */
+    std::array<Event, MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+};
+
+#endif  // ANDROID_SENSORS_AIDL_ENVIRONMENT_H
diff --git a/sensors/aidl/vts/SensorsAidlTestSharedMemory.h b/sensors/aidl/vts/SensorsAidlTestSharedMemory.h
new file mode 100644
index 0000000..4b5916a
--- /dev/null
+++ b/sensors/aidl/vts/SensorsAidlTestSharedMemory.h
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SENSORS_AIDL_TEST_SHARED_MEMORY_H
+#define ANDROID_SENSORS_AIDL_TEST_SHARED_MEMORY_H
+
+#include "sensors-vts-utils/GrallocWrapper.h"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/macros.h>
+#include <log/log.h>
+
+#include <sys/mman.h>
+#include <cinttypes>
+
+#include <cutils/ashmem.h>
+
+using ::aidl::android::hardware::sensors::BnSensors;
+using ::aidl::android::hardware::sensors::Event;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::SensorType;
+
+template <class SensorType, class Event>
+class SensorsAidlTestSharedMemory {
+  public:
+    static SensorsAidlTestSharedMemory* create(ISensors::SharedMemInfo::SharedMemType type,
+                                               size_t size) {
+        constexpr size_t kMaxSize =
+                128 * 1024 * 1024;  // sensor test should not need more than 128M
+        if (size == 0 || size >= kMaxSize) {
+            return nullptr;
+        }
+
+        auto m = new SensorsAidlTestSharedMemory<SensorType, Event>(type, size);
+        if (m->mSize != size || m->mBuffer == nullptr) {
+            delete m;
+            m = nullptr;
+        }
+        return m;
+    }
+
+    ISensors::SharedMemInfo getSharedMemInfo() const {
+        ISensors::SharedMemInfo mem = {
+                .type = mType,
+                .format = ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT,
+                .size = static_cast<int32_t>(mSize),
+                .memoryHandle = android::dupToAidl(mNativeHandle)};
+        return mem;
+    }
+    char* getBuffer() const { return mBuffer; }
+    size_t getSize() const { return mSize; }
+    std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const {
+        constexpr size_t kEventSize =
+                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH);
+        constexpr size_t kOffsetSize =
+                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_FIELD);
+        constexpr size_t kOffsetToken =
+                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_REPORT_TOKEN);
+        constexpr size_t kOffsetType =
+                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_SENSOR_TYPE);
+        constexpr size_t kOffsetAtomicCounter = static_cast<size_t>(
+                BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_ATOMIC_COUNTER);
+        constexpr size_t kOffsetTimestamp =
+                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_TIMESTAMP);
+        constexpr size_t kOffsetData =
+                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA);
+
+        std::vector<Event> events;
+        std::vector<float> data(16);
+
+        while (offset + kEventSize <= mSize) {
+            int64_t atomicCounter =
+                    *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter);
+            if (atomicCounter <= lastCounter) {
+                ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter,
+                      lastCounter);
+                break;
+            }
+
+            int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize);
+            if (size != kEventSize) {
+                // unknown error, events parsed may be wrong, remove all
+                events.clear();
+                break;
+            }
+
+            int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken);
+            int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType);
+            int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp);
+
+            ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32
+                  ", timestamp %" PRId64,
+                  offset, atomicCounter, token, type, timestamp);
+
+            Event event = {
+                    .timestamp = timestamp,
+                    .sensorHandle = token,
+                    .sensorType = type,
+            };
+
+            event.set<Event::Data>(reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
+            // event.u.data = android::hardware::hidl_array<float,
+            // 16>(reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
+
+            events.push_back(event);
+
+            lastCounter = atomicCounter;
+            offset += kEventSize;
+        }
+
+        return events;
+    }
+
+    virtual ~SensorsAidlTestSharedMemory() {
+        switch (mType) {
+            case ISensors::SharedMemInfo::SharedMemType::ASHMEM: {
+                if (mSize != 0) {
+                    ::munmap(mBuffer, mSize);
+                    mBuffer = nullptr;
+
+                    ::native_handle_close(mNativeHandle);
+                    ::native_handle_delete(mNativeHandle);
+
+                    mNativeHandle = nullptr;
+                    mSize = 0;
+                }
+                break;
+            }
+            case ISensors::SharedMemInfo::SharedMemType::GRALLOC: {
+                if (mSize != 0) {
+                    mGrallocWrapper->freeBuffer(mNativeHandle);
+                    mNativeHandle = nullptr;
+                    mSize = 0;
+                }
+                break;
+            }
+            default: {
+                if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
+                    ALOGE("SensorsAidlTestSharedMemory %p not properly destructed: "
+                          "type %d, native handle %p, size %zu, buffer %p",
+                          this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+                }
+                break;
+            }
+        }
+    }
+
+  private:
+    SensorsAidlTestSharedMemory(ISensors::SharedMemInfo::SharedMemType type, size_t size)
+        : mType(type), mSize(0), mBuffer(nullptr) {
+        native_handle_t* handle = nullptr;
+        char* buffer = nullptr;
+        switch (type) {
+            case ISensors::SharedMemInfo::SharedMemType::ASHMEM: {
+                int fd;
+                handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/);
+                if (handle != nullptr) {
+                    handle->data[0] = fd =
+                            ::ashmem_create_region("SensorsAidlTestSharedMemory", size);
+                    if (handle->data[0] > 0) {
+                        // memory is pinned by default
+                        buffer = static_cast<char*>(
+                                ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+                        if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
+                            break;
+                        }
+                        ::native_handle_close(handle);
+                    }
+                    ::native_handle_delete(handle);
+                    handle = nullptr;
+                }
+                break;
+            }
+            case ISensors::SharedMemInfo::SharedMemType::GRALLOC: {
+                mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
+                if (!mGrallocWrapper->isInitialized()) {
+                    break;
+                }
+
+                std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
+                handle = buf.first;
+                buffer = static_cast<char*>(buf.second);
+                break;
+            }
+            default:
+                break;
+        }
+
+        if (buffer != nullptr) {
+            mNativeHandle = handle;
+            mSize = size;
+            mBuffer = buffer;
+        }
+    }
+
+    ISensors::SharedMemInfo::SharedMemType mType;
+    native_handle_t* mNativeHandle;
+    size_t mSize;
+    char* mBuffer;
+    std::unique_ptr<::android::GrallocWrapper> mGrallocWrapper;
+
+    DISALLOW_COPY_AND_ASSIGN(SensorsAidlTestSharedMemory);
+};
+
+#endif  // ANDROID_SENSORS_TEST_SHARED_MEMORY_H
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
new file mode 100644
index 0000000..1bc7263
--- /dev/null
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -0,0 +1,1065 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/sensors/BnSensors.h>
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <hardware/sensors.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include "SensorsAidlEnvironment.h"
+#include "SensorsAidlTestSharedMemory.h"
+#include "sensors-vts-utils/SensorsVtsEnvironmentBase.h"
+
+#include <cinttypes>
+#include <condition_variable>
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::SensorInfo;
+using aidl::android::hardware::sensors::SensorStatus;
+using aidl::android::hardware::sensors::SensorType;
+using android::ProcessState;
+using std::chrono::duration_cast;
+
+constexpr size_t kEventSize =
+        static_cast<size_t>(ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH);
+
+namespace {
+
+static void assertTypeMatchStringType(SensorType type, const std::string& stringType) {
+    if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+        return;
+    }
+
+    switch (type) {
+#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type)                      \
+    case SensorType::type:                                           \
+        ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \
+        break;
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
+        default:
+            FAIL() << "Type " << static_cast<int>(type)
+                   << " in android defined range is not checked, "
+                   << "stringType = " << stringType;
+#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
+    }
+}
+
+bool isDirectChannelTypeSupported(SensorInfo sensor, ISensors::SharedMemInfo::SharedMemType type) {
+    switch (type) {
+        case ISensors::SharedMemInfo::SharedMemType::ASHMEM:
+            return (sensor.flags & SensorInfo::SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM) != 0;
+        case ISensors::SharedMemInfo::SharedMemType::GRALLOC:
+            return (sensor.flags & SensorInfo::SENSOR_FLAG_BITS_DIRECT_CHANNEL_GRALLOC) != 0;
+        default:
+            return false;
+    }
+}
+
+bool isDirectReportRateSupported(SensorInfo sensor, ISensors::RateLevel rate) {
+    unsigned int r = static_cast<unsigned int>(sensor.flags &
+                                               SensorInfo::SENSOR_FLAG_BITS_MASK_DIRECT_REPORT) >>
+                     static_cast<unsigned int>(SensorInfo::SENSOR_FLAG_SHIFT_DIRECT_REPORT);
+    return r >= static_cast<unsigned int>(rate);
+}
+
+int expectedReportModeForType(SensorType type) {
+    switch (type) {
+        case SensorType::ACCELEROMETER:
+        case SensorType::ACCELEROMETER_UNCALIBRATED:
+        case SensorType::GYROSCOPE:
+        case SensorType::MAGNETIC_FIELD:
+        case SensorType::ORIENTATION:
+        case SensorType::PRESSURE:
+        case SensorType::GRAVITY:
+        case SensorType::LINEAR_ACCELERATION:
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::GAME_ROTATION_VECTOR:
+        case SensorType::GYROSCOPE_UNCALIBRATED:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+        case SensorType::POSE_6DOF:
+        case SensorType::HEART_BEAT:
+            return SensorInfo::SENSOR_FLAG_BITS_CONTINUOUS_MODE;
+
+        case SensorType::LIGHT:
+        case SensorType::PROXIMITY:
+        case SensorType::RELATIVE_HUMIDITY:
+        case SensorType::AMBIENT_TEMPERATURE:
+        case SensorType::HEART_RATE:
+        case SensorType::DEVICE_ORIENTATION:
+        case SensorType::STEP_COUNTER:
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+            return SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE;
+
+        case SensorType::SIGNIFICANT_MOTION:
+        case SensorType::WAKE_GESTURE:
+        case SensorType::GLANCE_GESTURE:
+        case SensorType::PICK_UP_GESTURE:
+        case SensorType::MOTION_DETECT:
+        case SensorType::STATIONARY_DETECT:
+            return SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE;
+
+        case SensorType::STEP_DETECTOR:
+        case SensorType::TILT_DETECTOR:
+        case SensorType::WRIST_TILT_GESTURE:
+        case SensorType::DYNAMIC_SENSOR_META:
+            return SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE;
+
+        default:
+            ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
+            return INT32_MAX;
+    }
+}
+
+void assertTypeMatchReportMode(SensorType type, int reportMode) {
+    if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+        return;
+    }
+
+    int expected = expectedReportModeForType(type);
+
+    ASSERT_TRUE(expected == INT32_MAX || expected == reportMode)
+            << "reportMode=" << static_cast<int>(reportMode)
+            << "expected=" << static_cast<int>(expected);
+}
+
+void assertDelayMatchReportMode(int32_t minDelayUs, int32_t maxDelayUs, int reportMode) {
+    switch (reportMode) {
+        case SensorInfo::SENSOR_FLAG_BITS_CONTINUOUS_MODE:
+            ASSERT_LT(0, minDelayUs);
+            ASSERT_LE(0, maxDelayUs);
+            break;
+        case SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE:
+            ASSERT_LE(0, minDelayUs);
+            ASSERT_LE(0, maxDelayUs);
+            break;
+        case SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE:
+            ASSERT_EQ(-1, minDelayUs);
+            ASSERT_EQ(0, maxDelayUs);
+            break;
+        case SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE:
+            // do not enforce anything for special reporting mode
+            break;
+        default:
+            FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
+    }
+}
+
+void checkIsOk(ndk::ScopedAStatus status) {
+    ASSERT_TRUE(status.isOk());
+}
+
+}  // namespace
+
+class EventCallback : public IEventCallback<Event> {
+  public:
+    void reset() {
+        mFlushMap.clear();
+        mEventMap.clear();
+    }
+
+    void onEvent(const Event& event) override {
+        if (event.sensorType == SensorType::META_DATA &&
+            event.payload.get<Event::EventPayload::Tag::meta>().what ==
+                    Event::EventPayload::MetaData::MetaDataEventType::META_DATA_FLUSH_COMPLETE) {
+            std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+            mFlushMap[event.sensorHandle]++;
+            mFlushCV.notify_all();
+        } else if (event.sensorType != SensorType::ADDITIONAL_INFO) {
+            std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+            mEventMap[event.sensorHandle].push_back(event);
+            mEventCV.notify_all();
+        }
+    }
+
+    int32_t getFlushCount(int32_t sensorHandle) {
+        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+        return mFlushMap[sensorHandle];
+    }
+
+    void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
+                            int32_t numCallsToFlush, std::chrono::milliseconds timeout) {
+        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+        mFlushCV.wait_for(lock, timeout,
+                          [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
+    }
+
+    const std::vector<Event> getEvents(int32_t sensorHandle) {
+        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+        return mEventMap[sensorHandle];
+    }
+
+    void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
+                       std::chrono::milliseconds timeout) {
+        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+        mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
+    }
+
+  protected:
+    bool flushesReceived(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t numCallsToFlush) {
+        for (const SensorInfo& sensor : sensorsToWaitFor) {
+            if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    bool eventsReceived(const std::vector<SensorInfo>& sensorsToWaitFor) {
+        for (const SensorInfo& sensor : sensorsToWaitFor) {
+            if (getEvents(sensor.sensorHandle).size() == 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    std::map<int32_t, int32_t> mFlushMap;
+    std::recursive_mutex mFlushMutex;
+    std::condition_variable_any mFlushCV;
+
+    std::map<int32_t, std::vector<Event>> mEventMap;
+    std::recursive_mutex mEventMutex;
+    std::condition_variable_any mEventCV;
+};
+
+class SensorsAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mEnvironment = new SensorsAidlEnvironment(GetParam());
+        mEnvironment->SetUp();
+
+        // Ensure that we have a valid environment before performing tests
+        ASSERT_NE(getSensors(), nullptr);
+    }
+
+    virtual void TearDown() override {
+        for (int32_t handle : mSensorHandles) {
+            activate(handle, false);
+        }
+        mSensorHandles.clear();
+
+        mEnvironment->TearDown();
+        delete mEnvironment;
+        mEnvironment = nullptr;
+    }
+
+  protected:
+    std::vector<SensorInfo> getNonOneShotSensors();
+    std::vector<SensorInfo> getNonOneShotAndNonSpecialSensors();
+    std::vector<SensorInfo> getNonOneShotAndNonOnChangeAndNonSpecialSensors();
+    std::vector<SensorInfo> getOneShotSensors();
+    std::vector<SensorInfo> getInjectEventSensors();
+
+    void verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType memType);
+
+    void verifyRegisterDirectChannel(
+            std::shared_ptr<SensorsAidlTestSharedMemory<SensorType, Event>> mem,
+            int32_t* directChannelHandle, bool supportsSharedMemType,
+            bool supportsAnyDirectChannel);
+
+    void verifyConfigure(const SensorInfo& sensor, ISensors::SharedMemInfo::SharedMemType memType,
+                         int32_t directChannelHandle, bool directChannelSupported);
+
+    void queryDirectChannelSupport(ISensors::SharedMemInfo::SharedMemType memType,
+                                   bool* supportsSharedMemType, bool* supportsAnyDirectChannel);
+
+    void verifyUnregisterDirectChannel(int32_t* directChannelHandle, bool supportsAnyDirectChannel);
+
+    void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
+                        ISensors::RateLevel rateLevel, int32_t* reportToken);
+
+    inline std::shared_ptr<ISensors>& getSensors() { return mEnvironment->mSensors; }
+
+    inline SensorsAidlEnvironment* getEnvironment() { return mEnvironment; }
+
+    inline bool isValidType(SensorType sensorType) { return (int)sensorType > 0; }
+
+    std::vector<SensorInfo> getSensorsList();
+
+    int32_t getInvalidSensorHandle() {
+        // Find a sensor handle that does not exist in the sensor list
+        int32_t maxHandle = 0;
+        for (const SensorInfo& sensor : getSensorsList()) {
+            maxHandle = std::max(maxHandle, sensor.sensorHandle);
+        }
+        return maxHandle + 1;
+    }
+
+    ndk::ScopedAStatus activate(int32_t sensorHandle, bool enable);
+    void activateAllSensors(bool enable);
+
+    ndk::ScopedAStatus batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                             int64_t maxReportLatencyNs) {
+        return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    ndk::ScopedAStatus flush(int32_t sensorHandle) { return getSensors()->flush(sensorHandle); }
+
+    ndk::ScopedAStatus registerDirectChannel(const ISensors::SharedMemInfo& mem,
+                                             int32_t* aidlReturn);
+
+    ndk::ScopedAStatus unregisterDirectChannel(int32_t* channelHandle) {
+        return getSensors()->unregisterDirectChannel(*channelHandle);
+    }
+
+    ndk::ScopedAStatus configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                          ISensors::RateLevel rate, int32_t* reportToken) {
+        return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, reportToken);
+    }
+
+    void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+                            int32_t expectedFlushCount, bool expectedResult);
+
+    void runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+                      int32_t flushCalls, int32_t expectedFlushCount, bool expectedResult);
+
+    inline static int32_t extractReportMode(int32_t flag) {
+        return (flag & (SensorInfo::SENSOR_FLAG_BITS_CONTINUOUS_MODE |
+                        SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE |
+                        SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE |
+                        SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE));
+    }
+
+    // All sensors and direct channnels used
+    std::unordered_set<int32_t> mSensorHandles;
+    std::unordered_set<int32_t> mDirectChannelHandles;
+
+  private:
+    SensorsAidlEnvironment* mEnvironment;
+};
+
+ndk::ScopedAStatus SensorsAidlTest::registerDirectChannel(const ISensors::SharedMemInfo& mem,
+                                                          int32_t* aidlReturn) {
+    // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
+    // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
+    // Unregistering a channel more than once should not have negative effect.
+
+    ndk::ScopedAStatus status = getSensors()->registerDirectChannel(mem, aidlReturn);
+    if (status.isOk()) {
+        mDirectChannelHandles.insert(*aidlReturn);
+    }
+    return status;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getSensorsList() {
+    std::vector<SensorInfo> sensorInfoList;
+    checkIsOk(getSensors()->getSensorsList(&sensorInfoList));
+    return sensorInfoList;
+}
+
+ndk::ScopedAStatus SensorsAidlTest::activate(int32_t sensorHandle, bool enable) {
+    // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+    // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+    // check the return value of deactivation. Deactivating a sensor more than once does not have
+    // negative effect.
+    if (enable) {
+        mSensorHandles.insert(sensorHandle);
+    }
+    return getSensors()->activate(sensorHandle, enable);
+}
+
+void SensorsAidlTest::activateAllSensors(bool enable) {
+    for (const SensorInfo& sensorInfo : getSensorsList()) {
+        if (isValidType(sensorInfo.type)) {
+            checkIsOk(batch(sensorInfo.sensorHandle, sensorInfo.minDelayUs,
+                            0 /* maxReportLatencyNs */));
+            checkIsOk(activate(sensorInfo.sensorHandle, enable));
+        }
+    }
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getNonOneShotSensors() {
+    std::vector<SensorInfo> sensors;
+    for (const SensorInfo& info : getSensorsList()) {
+        if (extractReportMode(info.flags) != SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getNonOneShotAndNonSpecialSensors() {
+    std::vector<SensorInfo> sensors;
+    for (const SensorInfo& info : getSensorsList()) {
+        int reportMode = extractReportMode(info.flags);
+        if (reportMode != SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE &&
+            reportMode != SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getNonOneShotAndNonOnChangeAndNonSpecialSensors() {
+    std::vector<SensorInfo> sensors;
+    for (const SensorInfo& info : getSensorsList()) {
+        int reportMode = extractReportMode(info.flags);
+        if (reportMode != SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE &&
+            reportMode != SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE &&
+            reportMode != SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getOneShotSensors() {
+    std::vector<SensorInfo> sensors;
+    for (const SensorInfo& info : getSensorsList()) {
+        if (extractReportMode(info.flags) == SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getInjectEventSensors() {
+    std::vector<SensorInfo> out;
+    std::vector<SensorInfo> sensorInfoList = getSensorsList();
+    for (const SensorInfo& info : sensorInfoList) {
+        if (info.flags & SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION) {
+            out.push_back(info);
+        }
+    }
+    return out;
+}
+
+void SensorsAidlTest::runSingleFlushTest(const std::vector<SensorInfo>& sensors,
+                                         bool activateSensor, int32_t expectedFlushCount,
+                                         bool expectedResult) {
+    runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResult);
+}
+
+void SensorsAidlTest::runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+                                   int32_t flushCalls, int32_t expectedFlushCount,
+                                   bool expectedResult) {
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    for (const SensorInfo& sensor : sensors) {
+        // Configure and activate the sensor
+        batch(sensor.sensorHandle, sensor.maxDelayUs, 0 /* maxReportLatencyNs */);
+        activate(sensor.sensorHandle, activateSensor);
+
+        // Flush the sensor
+        for (int32_t i = 0; i < flushCalls; i++) {
+            SCOPED_TRACE(::testing::Message()
+                         << "Flush " << i << "/" << flushCalls << ": "
+                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                         << sensor.sensorHandle << std::dec
+                         << " type=" << static_cast<int>(sensor.type) << " name=" << sensor.name);
+
+            EXPECT_EQ(flush(sensor.sensorHandle).isOk(), expectedResult);
+        }
+    }
+
+    // Wait up to one second for the flush events
+    callback.waitForFlushEvents(sensors, flushCalls, std::chrono::milliseconds(1000) /* timeout */);
+
+    // Deactivate all sensors after waiting for flush events so pending flush events are not
+    // abandoned by the HAL.
+    for (const SensorInfo& sensor : sensors) {
+        activate(sensor.sensorHandle, false);
+    }
+    getEnvironment()->unregisterCallback();
+
+    // Check that the correct number of flushes are present for each sensor
+    for (const SensorInfo& sensor : sensors) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+        ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
+    }
+}
+
+TEST_P(SensorsAidlTest, SensorListValid) {
+    std::vector<SensorInfo> sensorInfoList = getSensorsList();
+    std::unordered_map<int32_t, std::vector<std::string>> sensorTypeNameMap;
+    for (size_t i = 0; i < sensorInfoList.size(); ++i) {
+        const SensorInfo& info = sensorInfoList[i];
+        SCOPED_TRACE(::testing::Message()
+                     << i << "/" << sensorInfoList.size() << ": "
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << info.sensorHandle << std::dec << " type=" << static_cast<int>(info.type)
+                     << " name=" << info.name);
+
+        // Test type string non-empty only for private sensor typeinfo.
+        if (info.type >= SensorType::DEVICE_PRIVATE_BASE) {
+            EXPECT_FALSE(info.typeAsString.empty());
+        } else if (!info.typeAsString.empty()) {
+            // Test type string matches framework string if specified for non-private typeinfo.
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(info.type, info.typeAsString));
+        }
+
+        // Test if all sensor has name and vendor
+        EXPECT_FALSE(info.name.empty());
+        EXPECT_FALSE(info.vendor.empty());
+
+        // Make sure that sensors of the same type have a unique name.
+        std::vector<std::string>& v = sensorTypeNameMap[static_cast<int32_t>(info.type)];
+        bool isUniqueName = std::find(v.begin(), v.end(), info.name) == v.end();
+        EXPECT_TRUE(isUniqueName) << "Duplicate sensor Name: " << info.name;
+        if (isUniqueName) {
+            v.push_back(info.name);
+        }
+
+        EXPECT_LE(0, info.power);
+        EXPECT_LT(0, info.maxRange);
+
+        // Info type, should have no sensor
+        EXPECT_FALSE(info.type == SensorType::ADDITIONAL_INFO ||
+                     info.type == SensorType::META_DATA);
+
+        EXPECT_GE(info.fifoMaxEventCount, info.fifoReservedEventCount);
+
+        // Test Reporting mode valid
+        EXPECT_NO_FATAL_FAILURE(
+                assertTypeMatchReportMode(info.type, extractReportMode(info.flags)));
+
+        // Test min max are in the right order
+        EXPECT_LE(info.minDelayUs, info.maxDelayUs);
+        // Test min/max delay matches reporting mode
+        EXPECT_NO_FATAL_FAILURE(assertDelayMatchReportMode(info.minDelayUs, info.maxDelayUs,
+                                                           extractReportMode(info.flags)));
+    }
+}
+
+TEST_P(SensorsAidlTest, SetOperationMode) {
+    if (getInjectEventSensors().size() > 0) {
+        ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
+        ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::DATA_INJECTION).isOk());
+        ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
+    } else {
+        ASSERT_EQ(getSensors()
+                          ->setOperationMode(ISensors::OperationMode::DATA_INJECTION)
+                          .getExceptionCode(),
+                  EX_UNSUPPORTED_OPERATION);
+    }
+}
+
+TEST_P(SensorsAidlTest, InjectSensorEventData) {
+    std::vector<SensorInfo> sensors = getInjectEventSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::DATA_INJECTION).isOk());
+
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    // AdditionalInfo event should not be sent to Event FMQ
+    Event additionalInfoEvent;
+    additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO;
+    additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
+
+    Event injectedEvent;
+    injectedEvent.timestamp = android::elapsedRealtimeNano();
+    Event::EventPayload::Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+    injectedEvent.payload.set<Event::EventPayload::Tag::vec3>(data);
+
+    for (const auto& s : sensors) {
+        additionalInfoEvent.sensorHandle = s.sensorHandle;
+        ASSERT_TRUE(getSensors()->injectSensorData(additionalInfoEvent).isOk());
+
+        injectedEvent.sensorType = s.type;
+        injectedEvent.sensorHandle = s.sensorHandle;
+        ASSERT_TRUE(getSensors()->injectSensorData(injectedEvent).isOk());
+    }
+
+    // Wait for events to be written back to the Event FMQ
+    callback.waitForEvents(sensors, std::chrono::milliseconds(1000) /* timeout */);
+    getEnvironment()->unregisterCallback();
+
+    for (const auto& s : sensors) {
+        auto events = callback.getEvents(s.sensorHandle);
+        if (events.empty()) {
+            FAIL() << "Received no events";
+        } else {
+            auto lastEvent = events.back();
+            SCOPED_TRACE(::testing::Message()
+                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                         << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+                         << " name=" << s.name);
+
+            // Verify that only a single event has been received
+            ASSERT_EQ(events.size(), 1);
+
+            // Verify that the event received matches the event injected and is not the additional
+            // info event
+            ASSERT_EQ(lastEvent.sensorType, s.type);
+            ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp);
+            ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().x,
+                      injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().x);
+            ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().y,
+                      injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().y);
+            ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().z,
+                      injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().z);
+            ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().status,
+                      injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().status);
+        }
+    }
+
+    ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
+}
+
+TEST_P(SensorsAidlTest, CallInitializeTwice) {
+    // Create a helper class so that a second environment is able to be instantiated
+    class SensorsAidlEnvironmentTest : public SensorsAidlEnvironment {
+      public:
+        SensorsAidlEnvironmentTest(const std::string& service_name)
+            : SensorsAidlEnvironment(service_name) {}
+    };
+
+    if (getSensorsList().size() == 0) {
+        // No sensors
+        return;
+    }
+
+    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
+    constexpr int32_t kNumEvents = 1;
+
+    // Create a new environment that calls initialize()
+    std::unique_ptr<SensorsAidlEnvironmentTest> newEnv =
+            std::make_unique<SensorsAidlEnvironmentTest>(GetParam());
+    newEnv->SetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if setting up the new environment failed
+    }
+
+    activateAllSensors(true);
+    // Verify that the old environment does not receive any events
+    EXPECT_EQ(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), 0);
+    // Verify that the new event queue receives sensor events
+    EXPECT_GE(newEnv.get()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    activateAllSensors(false);
+
+    // Cleanup the test environment
+    newEnv->TearDown();
+
+    // Restore the test environment for future tests
+    getEnvironment()->TearDown();
+    getEnvironment()->SetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
+
+    // Ensure that the original environment is receiving events
+    activateAllSensors(true);
+    EXPECT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    activateAllSensors(false);
+}
+
+TEST_P(SensorsAidlTest, CleanupConnectionsOnInitialize) {
+    activateAllSensors(true);
+
+    // Verify that events are received
+    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
+    constexpr int32_t kNumEvents = 1;
+    ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+
+    // Clear the active sensor handles so they are not disabled during TearDown
+    auto handles = mSensorHandles;
+    mSensorHandles.clear();
+    getEnvironment()->TearDown();
+    getEnvironment()->SetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
+
+    // Verify no events are received until sensors are re-activated
+    ASSERT_EQ(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), 0);
+    activateAllSensors(true);
+    ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+
+    // Disable sensors
+    activateAllSensors(false);
+
+    // Restore active sensors prior to clearing the environment
+    mSensorHandles = handles;
+}
+
+TEST_P(SensorsAidlTest, FlushSensor) {
+    std::vector<SensorInfo> sensors = getNonOneShotSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    constexpr int32_t kFlushes = 5;
+    runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */,
+                       true /* expectedResult */);
+    runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, true /* expectedResult */);
+}
+
+TEST_P(SensorsAidlTest, FlushOneShotSensor) {
+    // Find a sensor that is a one-shot sensor
+    std::vector<SensorInfo> sensors = getOneShotSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */,
+                       false /* expectedResult */);
+}
+
+TEST_P(SensorsAidlTest, FlushInactiveSensor) {
+    // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
+    std::vector<SensorInfo> sensors = getNonOneShotSensors();
+    if (sensors.size() == 0) {
+        sensors = getOneShotSensors();
+        if (sensors.size() == 0) {
+            return;
+        }
+    }
+
+    runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */,
+                       false /* expectedResult */);
+}
+
+TEST_P(SensorsAidlTest, Batch) {
+    if (getSensorsList().size() == 0) {
+        return;
+    }
+
+    activateAllSensors(false /* enable */);
+    for (const SensorInfo& sensor : getSensorsList()) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+
+        // Call batch on inactive sensor
+        // One shot sensors have minDelay set to -1 which is an invalid
+        // parameter. Use 0 instead to avoid errors.
+        int64_t samplingPeriodNs =
+                extractReportMode(sensor.flags) == SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE
+                        ? 0
+                        : sensor.minDelayUs;
+        checkIsOk(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */));
+
+        // Activate the sensor
+        activate(sensor.sensorHandle, true /* enabled */);
+
+        // Call batch on an active sensor
+        checkIsOk(batch(sensor.sensorHandle, sensor.maxDelayUs, 0 /* maxReportLatencyNs */));
+    }
+    activateAllSensors(false /* enable */);
+
+    // Call batch on an invalid sensor
+    SensorInfo sensor = getSensorsList().front();
+    sensor.sensorHandle = getInvalidSensorHandle();
+    ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelayUs, 0 /* maxReportLatencyNs */)
+                      .getExceptionCode(),
+              EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_P(SensorsAidlTest, Activate) {
+    if (getSensorsList().size() == 0) {
+        return;
+    }
+
+    // Verify that sensor events are generated when activate is called
+    for (const SensorInfo& sensor : getSensorsList()) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+
+        checkIsOk(batch(sensor.sensorHandle, sensor.minDelayUs, 0 /* maxReportLatencyNs */));
+        checkIsOk(activate(sensor.sensorHandle, true));
+
+        // Call activate on a sensor that is already activated
+        checkIsOk(activate(sensor.sensorHandle, true));
+
+        // Deactivate the sensor
+        checkIsOk(activate(sensor.sensorHandle, false));
+
+        // Call deactivate on a sensor that is already deactivated
+        checkIsOk(activate(sensor.sensorHandle, false));
+    }
+
+    // Attempt to activate an invalid sensor
+    int32_t invalidHandle = getInvalidSensorHandle();
+    ASSERT_EQ(activate(invalidHandle, true).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+    ASSERT_EQ(activate(invalidHandle, false).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_P(SensorsAidlTest, NoStaleEvents) {
+    constexpr std::chrono::milliseconds kFiveHundredMs(500);
+    constexpr std::chrono::milliseconds kOneSecond(1000);
+
+    // Register the callback to receive sensor events
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    // This test is not valid for one-shot, on-change or special-report-mode sensors
+    const std::vector<SensorInfo> sensors = getNonOneShotAndNonOnChangeAndNonSpecialSensors();
+    std::chrono::milliseconds maxMinDelay(0);
+    for (const SensorInfo& sensor : sensors) {
+        std::chrono::milliseconds minDelay = duration_cast<std::chrono::milliseconds>(
+                std::chrono::microseconds(sensor.minDelayUs));
+        maxMinDelay = std::chrono::milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
+    }
+
+    // Activate the sensors so that they start generating events
+    activateAllSensors(true);
+
+    // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
+    // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
+    // of time to guarantee that a sample has arrived.
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+    activateAllSensors(false);
+
+    // Save the last received event for each sensor
+    std::map<int32_t, int64_t> lastEventTimestampMap;
+    for (const SensorInfo& sensor : sensors) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+
+        if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
+            lastEventTimestampMap[sensor.sensorHandle] =
+                    callback.getEvents(sensor.sensorHandle).back().timestamp;
+        }
+    }
+
+    // Allow some time to pass, reset the callback, then reactivate the sensors
+    usleep(duration_cast<std::chrono::microseconds>(kOneSecond + (5 * maxMinDelay)).count());
+    callback.reset();
+    activateAllSensors(true);
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+    activateAllSensors(false);
+
+    getEnvironment()->unregisterCallback();
+
+    for (const SensorInfo& sensor : sensors) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+
+        // Skip sensors that did not previously report an event
+        if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
+            continue;
+        }
+
+        // Ensure that the first event received is not stale by ensuring that its timestamp is
+        // sufficiently different from the previous event
+        const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
+        std::chrono::milliseconds delta =
+                duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(
+                        newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
+        std::chrono::milliseconds sensorMinDelay = duration_cast<std::chrono::milliseconds>(
+                std::chrono::microseconds(sensor.minDelayUs));
+        ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
+    }
+}
+
+void SensorsAidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
+                                     ISensors::RateLevel rateLevel, int32_t* reportToken) {
+    ndk::ScopedAStatus status =
+            configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel, reportToken);
+
+    SCOPED_TRACE(::testing::Message()
+                 << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                 << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                 << " name=" << sensor.name);
+
+    if (isDirectReportRateSupported(sensor, rateLevel)) {
+        ASSERT_TRUE(status.isOk());
+        if (rateLevel != ISensors::RateLevel::STOP) {
+            ASSERT_GT(*reportToken, 0);
+        } else {
+            ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+        }
+    }
+}
+
+void SensorsAidlTest::queryDirectChannelSupport(ISensors::SharedMemInfo::SharedMemType memType,
+                                                bool* supportsSharedMemType,
+                                                bool* supportsAnyDirectChannel) {
+    *supportsSharedMemType = false;
+    *supportsAnyDirectChannel = false;
+    for (const SensorInfo& curSensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(curSensor, memType)) {
+            *supportsSharedMemType = true;
+        }
+        if (isDirectChannelTypeSupported(curSensor,
+                                         ISensors::SharedMemInfo::SharedMemType::ASHMEM) ||
+            isDirectChannelTypeSupported(curSensor,
+                                         ISensors::SharedMemInfo::SharedMemType::GRALLOC)) {
+            *supportsAnyDirectChannel = true;
+        }
+
+        if (*supportsSharedMemType && *supportsAnyDirectChannel) {
+            break;
+        }
+    }
+}
+
+void SensorsAidlTest::verifyRegisterDirectChannel(
+        std::shared_ptr<SensorsAidlTestSharedMemory<SensorType, Event>> mem,
+        int32_t* directChannelHandle, bool supportsSharedMemType, bool supportsAnyDirectChannel) {
+    char* buffer = mem->getBuffer();
+    size_t size = mem->getSize();
+
+    if (supportsSharedMemType) {
+        memset(buffer, 0xff, size);
+    }
+
+    int32_t channelHandle;
+
+    ::ndk::ScopedAStatus status = registerDirectChannel(mem->getSharedMemInfo(), &channelHandle);
+    if (supportsSharedMemType) {
+        ASSERT_TRUE(status.isOk());
+        ASSERT_EQ(channelHandle, 0);
+    } else {
+        int32_t error = supportsAnyDirectChannel ? EX_ILLEGAL_ARGUMENT : EX_UNSUPPORTED_OPERATION;
+        ASSERT_EQ(status.getExceptionCode(), error);
+        ASSERT_EQ(channelHandle, -1);
+    }
+    *directChannelHandle = channelHandle;
+}
+
+void SensorsAidlTest::verifyUnregisterDirectChannel(int32_t* channelHandle,
+                                                    bool supportsAnyDirectChannel) {
+    int result = supportsAnyDirectChannel ? EX_NONE : EX_UNSUPPORTED_OPERATION;
+    ndk::ScopedAStatus status = unregisterDirectChannel(channelHandle);
+    ASSERT_EQ(status.getExceptionCode(), result);
+}
+
+void SensorsAidlTest::verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType memType) {
+    constexpr size_t kNumEvents = 1;
+    constexpr size_t kMemSize = kNumEvents * kEventSize;
+
+    std::shared_ptr<SensorsAidlTestSharedMemory<SensorType, Event>> mem(
+            SensorsAidlTestSharedMemory<SensorType, Event>::create(memType, kMemSize));
+    ASSERT_NE(mem, nullptr);
+
+    bool supportsSharedMemType;
+    bool supportsAnyDirectChannel;
+    queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
+
+    for (const SensorInfo& sensor : getSensorsList()) {
+        int32_t directChannelHandle = 0;
+        verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
+                                    supportsAnyDirectChannel);
+        verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
+        verifyUnregisterDirectChannel(&directChannelHandle, supportsAnyDirectChannel);
+    }
+}
+
+void SensorsAidlTest::verifyConfigure(const SensorInfo& sensor,
+                                      ISensors::SharedMemInfo::SharedMemType memType,
+                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
+    SCOPED_TRACE(::testing::Message()
+                 << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                 << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                 << " name=" << sensor.name);
+
+    int32_t reportToken = 0;
+    if (isDirectChannelTypeSupported(sensor, memType)) {
+        // Verify that each rate level is properly supported
+        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::NORMAL, &reportToken);
+        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::FAST, &reportToken);
+        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::VERY_FAST, &reportToken);
+        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::STOP, &reportToken);
+
+        // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
+        ndk::ScopedAStatus status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
+                                                       ISensors::RateLevel::NORMAL, &reportToken);
+        ASSERT_EQ(status.getServiceSpecificError(), android::BAD_VALUE);
+
+        status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
+                                    ISensors::RateLevel::STOP, &reportToken);
+        ASSERT_TRUE(status.isOk());
+    } else {
+        // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
+        // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
+        // channel is not supported at all
+        int error = supportsAnyDirectChannel ? EX_ILLEGAL_ARGUMENT : EX_UNSUPPORTED_OPERATION;
+        ndk::ScopedAStatus status = configDirectReport(sensor.sensorHandle, directChannelHandle,
+                                                       ISensors::RateLevel::NORMAL, &reportToken);
+        ASSERT_EQ(status.getExceptionCode(), error);
+    }
+}
+
+TEST_P(SensorsAidlTest, DirectChannelAshmem) {
+    verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType::ASHMEM);
+}
+
+TEST_P(SensorsAidlTest, DirectChannelGralloc) {
+    verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType::GRALLOC);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsAidlTest);
+INSTANTIATE_TEST_SUITE_P(Sensors, SensorsAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(ISensors::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
index f5fc066..73b0594 100644
--- a/sensors/common/default/2.X/multihal/HalProxy.cpp
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -176,7 +176,13 @@
     std::unique_ptr<EventMessageQueueWrapperBase> queue =
             std::make_unique<EventMessageQueueWrapperV2_1>(eventQueue);
 
-    return initializeCommon(queue, wakeLockDescriptor, dynamicCallback);
+    // Create the Wake Lock FMQ from the wakeLockDescriptor. Reset the read/write positions.
+    auto hidlWakeLockQueue =
+            std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+    std::unique_ptr<WakeLockMessageQueueWrapperBase> wakeLockQueue =
+            std::make_unique<WakeLockMessageQueueWrapperHidl>(hidlWakeLockQueue);
+
+    return initializeCommon(queue, wakeLockQueue, dynamicCallback);
 }
 
 Return<Result> HalProxy::initialize(
@@ -192,12 +198,18 @@
     std::unique_ptr<EventMessageQueueWrapperBase> queue =
             std::make_unique<EventMessageQueueWrapperV1_0>(eventQueue);
 
-    return initializeCommon(queue, wakeLockDescriptor, dynamicCallback);
+    // Create the Wake Lock FMQ from the wakeLockDescriptor. Reset the read/write positions.
+    auto hidlWakeLockQueue =
+            std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+    std::unique_ptr<WakeLockMessageQueueWrapperBase> wakeLockQueue =
+            std::make_unique<WakeLockMessageQueueWrapperHidl>(hidlWakeLockQueue);
+
+    return initializeCommon(queue, wakeLockQueue, dynamicCallback);
 }
 
 Return<Result> HalProxy::initializeCommon(
         std::unique_ptr<EventMessageQueueWrapperBase>& eventQueue,
-        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        std::unique_ptr<WakeLockMessageQueueWrapperBase>& wakeLockQueue,
         const sp<ISensorsCallbackWrapperBase>& sensorsCallback) {
     Result result = Result::OK;
 
@@ -222,8 +234,7 @@
 
     // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
     // events have been successfully read and handled by the framework.
-    mWakeLockQueue =
-            std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+    mWakeLockQueue = std::move(wakeLockQueue);
 
     if (mEventQueueFlag != nullptr) {
         EventFlag::deleteEventFlag(&mEventQueueFlag);
diff --git a/sensors/common/default/2.X/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h
index 35d7c8b..6174528 100644
--- a/sensors/common/default/2.X/multihal/include/HalProxy.h
+++ b/sensors/common/default/2.X/multihal/include/HalProxy.h
@@ -23,6 +23,7 @@
 #include "V2_0/ScopedWakelock.h"
 #include "V2_0/SubHal.h"
 #include "V2_1/SubHal.h"
+#include "WakeLockMessageQueueWrapper.h"
 #include "convertV2_1.h"
 
 #include <android/hardware/sensors/2.1/ISensors.h>
@@ -98,10 +99,9 @@
             const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
             const sp<V2_0::ISensorsCallback>& sensorsCallback);
 
-    Return<Result> initializeCommon(
-            std::unique_ptr<EventMessageQueueWrapperBase>& eventQueue,
-            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
-            const sp<ISensorsCallbackWrapperBase>& sensorsCallback);
+    Return<Result> initializeCommon(std::unique_ptr<EventMessageQueueWrapperBase>& eventQueue,
+                                    std::unique_ptr<WakeLockMessageQueueWrapperBase>& wakeLockQueue,
+                                    const sp<ISensorsCallbackWrapperBase>& sensorsCallback);
 
     Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
                          int64_t maxReportLatencyNs);
@@ -141,6 +141,8 @@
 
     void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
 
+    const std::map<int32_t, SensorInfo>& getSensors() { return mSensors; }
+
   private:
     using EventMessageQueueV2_1 = MessageQueue<V2_1::Event, kSynchronizedReadWrite>;
     using EventMessageQueueV2_0 = MessageQueue<V1_0::Event, kSynchronizedReadWrite>;
@@ -154,7 +156,7 @@
     /**
      * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
      */
-    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
+    std::unique_ptr<WakeLockMessageQueueWrapperBase> mWakeLockQueue;
 
     /**
      * Event Flag to signal to the framework when sensor events are available to be read and to
diff --git a/sensors/common/utils/WakeLockMessageQueueWrapper.h b/sensors/common/utils/WakeLockMessageQueueWrapper.h
new file mode 100644
index 0000000..3a219cf
--- /dev/null
+++ b/sensors/common/utils/WakeLockMessageQueueWrapper.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "convertV2_1.h"
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <log/log.h>
+
+#include <atomic>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+class WakeLockMessageQueueWrapperBase {
+  public:
+    virtual ~WakeLockMessageQueueWrapperBase() {}
+
+    virtual std::atomic<uint32_t>* getEventFlagWord() = 0;
+    virtual bool readBlocking(uint32_t* events, size_t numToRead, uint32_t readNotification,
+                              uint32_t writeNotification, int64_t timeOutNanos,
+                              ::android::hardware::EventFlag* evFlag = nullptr) = 0;
+    virtual bool write(const uint32_t* wakeLock) = 0;
+};
+
+class WakeLockMessageQueueWrapperHidl : public WakeLockMessageQueueWrapperBase {
+  public:
+    WakeLockMessageQueueWrapperHidl(
+            std::unique_ptr<::android::hardware::MessageQueue<uint32_t, kSynchronizedReadWrite>>&
+                    queue)
+        : mQueue(std::move(queue)) {}
+
+    std::atomic<uint32_t>* getEventFlagWord() override { return mQueue->getEventFlagWord(); }
+
+    bool readBlocking(uint32_t* wakeLocks, size_t numToRead, uint32_t readNotification,
+                      uint32_t writeNotification, int64_t timeOutNanos,
+                      ::android::hardware::EventFlag* evFlag) override {
+        return mQueue->readBlocking(wakeLocks, numToRead, readNotification, writeNotification,
+                                    timeOutNanos, evFlag);
+    }
+
+    bool write(const uint32_t* wakeLock) override { return mQueue->write(wakeLock); }
+
+  private:
+    std::unique_ptr<::android::hardware::MessageQueue<uint32_t, kSynchronizedReadWrite>> mQueue;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index fcccc27..28e8090 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -10,6 +10,7 @@
 aidl_interface {
     name: "android.hardware.soundtrigger3",
     vendor_available: true,
+    host_supported: true,
     flags: ["-Werror", "-Weverything", ],
     srcs: [
         "android/hardware/soundtrigger3/ISoundTriggerHw.aidl",
diff --git a/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl b/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl
index 2a3fc64..618331b 100644
--- a/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl
+++ b/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl
@@ -18,15 +18,12 @@
 
 import android.hardware.soundtrigger3.ISoundTriggerHwCallback;
 import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback;
-
+import android.media.soundtrigger.ModelParameter;
+import android.media.soundtrigger.ModelParameterRange;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
 import android.media.soundtrigger.SoundModel;
-import android.media.soundtrigger.ModelParameter;
-import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.Properties;
-import android.media.soundtrigger.RecognitionConfig;
 
 /**
  * SoundTrigger HAL interface. Used for hardware recognition of hotwords
@@ -196,12 +193,12 @@
      *     an audio stream associated with this recognition session.
      * @param config A RecognitionConfig structure containing attributes of the recognition to
      *     perform.
-      * @throws ServiceSpecificException(RESOURCE_CONTENTION) if the model cannot be started due
+     * @throws ServiceSpecificException(RESOURCE_CONTENTION) if the model cannot be started due
      *     to resource constraints. This is typically a temporary condition and the client may
      *     retry after the onResourcesAvailable() global callback is invoked.
-    */
-    void startRecognition(in int modelHandle, in int deviceHandle,
-                          in int ioHandle, in RecognitionConfig config);
+     */
+    void startRecognition(
+            in int modelHandle, in int deviceHandle, in int ioHandle, in RecognitionConfig config);
 
     /**
      * Stop recognition on a given model.
@@ -235,7 +232,8 @@
      * @return This structure indicates supported attributes of the parameter for the given model
      *      handle. If the parameter is not supported, null is returned.
      */
-    @nullable ModelParameterRange queryParameter(in int modelHandle, in ModelParameter modelParam);
+    @nullable ModelParameterRange queryParameter(
+            in int modelHandle, in ModelParameter modelParam);
 
     /**
      * Get a model specific parameter.
diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp
index 6025339..c770e91 100644
--- a/tv/tuner/1.0/default/Lnb.cpp
+++ b/tv/tuner/1.0/default/Lnb.cpp
@@ -33,9 +33,10 @@
 
 Lnb::~Lnb() {}
 
-Return<Result> Lnb::setCallback(const sp<ILnbCallback>& /* callback */) {
+Return<Result> Lnb::setCallback(const sp<ILnbCallback>& callback) {
     ALOGV("%s", __FUNCTION__);
 
+    mCallback = callback;
     return Result::SUCCESS;
 }
 
@@ -57,9 +58,16 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) {
     ALOGV("%s", __FUNCTION__);
 
+    if (mCallback != nullptr) {
+        // The correct implementation should be to return the response from the
+        // device via onDiseqcMessage(). The below implementation is only to enable
+        // testing for LnbCallbacks.
+        ALOGV("[hidl] %s - this is for test purpose only, and must be replaced!", __FUNCTION__);
+        mCallback->onDiseqcMessage(diseqcMessage);
+    }
     return Result::SUCCESS;
 }
 
diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h
index 1e97214..c14bbd8 100644
--- a/tv/tuner/1.0/default/Lnb.h
+++ b/tv/tuner/1.0/default/Lnb.h
@@ -57,6 +57,7 @@
   private:
     int mId;
     virtual ~Lnb();
+    sp<ILnbCallback> mCallback;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
old mode 100644
new mode 100755
index 4a642a0..acc524b
--- a/tv/tuner/1.0/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
@@ -377,6 +377,7 @@
         result &= getDvrTests()->getDvrPlaybackMQDescriptor() == success();
         getDvrTests()->startPlaybackInputThread(mDvrConfig.playbackInputFile,
                                                 mDvrConfig.settings.playback());
+        getDvrTests()->startDvrPlayback();
         if (!result) {
             ALOGW("[vts] Software frontend dvr configure failed.");
             return failure();
@@ -400,6 +401,7 @@
     status = mFrontend->stopTune();
     if (mIsSoftwareFe && testWithDemux) {
         getDvrTests()->stopPlaybackThread();
+        getDvrTests()->stopDvrPlayback();
         getDvrTests()->closeDvrPlayback();
     }
     return AssertionResult(status == Result::SUCCESS);
diff --git a/tv/tuner/1.1/default/Frontend.cpp b/tv/tuner/1.1/default/Frontend.cpp
index f5463a9..919c956 100644
--- a/tv/tuner/1.1/default/Frontend.cpp
+++ b/tv/tuner/1.1/default/Frontend.cpp
@@ -88,46 +88,60 @@
 
 Return<Result> Frontend::scan(const FrontendSettings& settings, FrontendScanType type) {
     ALOGV("%s", __FUNCTION__);
+
+    // If it's in middle of scanning, stop it first.
+    if (mScanThread.joinable()) {
+        mScanThread.join();
+    }
+
+    mFrontendSettings = settings;
+    mFrontendScanType = type;
+    mScanThread = std::thread(&Frontend::scanThreadLoop, this);
+
+    return Result::SUCCESS;
+}
+
+void Frontend::scanThreadLoop() {
     FrontendScanMessage msg;
 
     if (mIsLocked) {
         msg.isEnd(true);
         mCallback->onScanMessage(FrontendScanMessageType::END, msg);
-        return Result::SUCCESS;
+        return;
     }
 
     uint32_t frequency;
-    switch (settings.getDiscriminator()) {
+    switch (mFrontendSettings.getDiscriminator()) {
         case FrontendSettings::hidl_discriminator::analog:
-            frequency = settings.analog().frequency;
+            frequency = mFrontendSettings.analog().frequency;
             break;
         case FrontendSettings::hidl_discriminator::atsc:
-            frequency = settings.atsc().frequency;
+            frequency = mFrontendSettings.atsc().frequency;
             break;
         case FrontendSettings::hidl_discriminator::atsc3:
-            frequency = settings.atsc3().frequency;
+            frequency = mFrontendSettings.atsc3().frequency;
             break;
         case FrontendSettings::hidl_discriminator::dvbs:
-            frequency = settings.dvbs().frequency;
+            frequency = mFrontendSettings.dvbs().frequency;
             break;
         case FrontendSettings::hidl_discriminator::dvbc:
-            frequency = settings.dvbc().frequency;
+            frequency = mFrontendSettings.dvbc().frequency;
             break;
         case FrontendSettings::hidl_discriminator::dvbt:
-            frequency = settings.dvbt().frequency;
+            frequency = mFrontendSettings.dvbt().frequency;
             break;
         case FrontendSettings::hidl_discriminator::isdbs:
-            frequency = settings.isdbs().frequency;
+            frequency = mFrontendSettings.isdbs().frequency;
             break;
         case FrontendSettings::hidl_discriminator::isdbs3:
-            frequency = settings.isdbs3().frequency;
+            frequency = mFrontendSettings.isdbs3().frequency;
             break;
         case FrontendSettings::hidl_discriminator::isdbt:
-            frequency = settings.isdbt().frequency;
+            frequency = mFrontendSettings.isdbt().frequency;
             break;
     }
 
-    if (type == FrontendScanType::SCAN_BLIND) {
+    if (mFrontendScanType == FrontendScanType::SCAN_BLIND) {
         frequency += 100 * 1000;
     }
 
@@ -204,8 +218,6 @@
     msg.isLocked(true);
     mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
     mIsLocked = true;
-
-    return Result::SUCCESS;
 }
 
 Return<Result> Frontend::scan_1_1(const FrontendSettings& settings, FrontendScanType type,
@@ -218,6 +230,10 @@
 Return<Result> Frontend::stopScan() {
     ALOGV("%s", __FUNCTION__);
 
+    if (mScanThread.joinable()) {
+        mScanThread.join();
+    }
+
     mIsLocked = false;
     return Result::SUCCESS;
 }
diff --git a/tv/tuner/1.1/default/Frontend.h b/tv/tuner/1.1/default/Frontend.h
index a28fb64..bf739a8 100644
--- a/tv/tuner/1.1/default/Frontend.h
+++ b/tv/tuner/1.1/default/Frontend.h
@@ -20,6 +20,7 @@
 #include <android/hardware/tv/tuner/1.1/IFrontend.h>
 #include <fstream>
 #include <iostream>
+#include <thread>
 #include "Tuner.h"
 
 using namespace std;
@@ -81,13 +82,17 @@
   private:
     virtual ~Frontend();
     bool supportsSatellite();
+    void scanThreadLoop();
+
     sp<IFrontendCallback> mCallback;
     sp<Tuner> mTunerService;
     FrontendType mType = FrontendType::UNDEFINED;
     FrontendId mId = 0;
     bool mIsLocked = false;
     uint32_t mCiCamId;
-
+    std::thread mScanThread;
+    FrontendSettings mFrontendSettings;
+    FrontendScanType mFrontendScanType;
     std::ifstream mFrontendData;
 };
 
diff --git a/tv/tuner/1.1/default/Lnb.cpp b/tv/tuner/1.1/default/Lnb.cpp
index 044727f..5dd0147 100644
--- a/tv/tuner/1.1/default/Lnb.cpp
+++ b/tv/tuner/1.1/default/Lnb.cpp
@@ -33,9 +33,10 @@
 
 Lnb::~Lnb() {}
 
-Return<Result> Lnb::setCallback(const sp<ILnbCallback>& /* callback */) {
+Return<Result> Lnb::setCallback(const sp<ILnbCallback>& callback) {
     ALOGV("%s", __FUNCTION__);
 
+    mCallback = callback;
     return Result::SUCCESS;
 }
 
@@ -57,9 +58,16 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) {
     ALOGV("%s", __FUNCTION__);
 
+    if (mCallback != nullptr) {
+        // The correct implementation should be to return the response from the
+        // device via onDiseqcMessage(). The below implementation is only to enable
+        // testing for LnbCallbacks.
+        ALOGV("[hidl] %s - this is for test purpose only, and must be replaced!", __FUNCTION__);
+        mCallback->onDiseqcMessage(diseqcMessage);
+    }
     return Result::SUCCESS;
 }
 
diff --git a/tv/tuner/1.1/default/Lnb.h b/tv/tuner/1.1/default/Lnb.h
index 70a8e41..b34ca39 100644
--- a/tv/tuner/1.1/default/Lnb.h
+++ b/tv/tuner/1.1/default/Lnb.h
@@ -51,6 +51,7 @@
   private:
     int mId;
     virtual ~Lnb();
+    sp<ILnbCallback> mCallback;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.1/vts/functional/FrontendTests.cpp b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
index a595a93..9f0f30d 100644
--- a/tv/tuner/1.1/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
@@ -444,6 +444,7 @@
         result &= getDvrTests()->getDvrPlaybackMQDescriptor() == success();
         getDvrTests()->startPlaybackInputThread(mDvrConfig.playbackInputFile,
                                                 mDvrConfig.settings.playback());
+        getDvrTests()->startDvrPlayback();
         if (!result) {
             ALOGW("[vts] Software frontend dvr configure failed.");
             return failure();
@@ -459,6 +460,7 @@
     status = mFrontend->stopTune();
     if (mIsSoftwareFe && testWithDemux) {
         getDvrTests()->stopPlaybackThread();
+        getDvrTests()->stopDvrPlayback();
         getDvrTests()->closeDvrPlayback();
     }
     return AssertionResult(status == Result::SUCCESS);
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl
index bfd2aa8..6c538ea 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/AudioStreamType.aidl
@@ -51,4 +51,8 @@
   OPUS = 13,
   VORBIS = 14,
   DRA = 15,
+  AAC_ADTS = 16,
+  AAC_LATM = 17,
+  AAC_HE_ADTS = 18,
+  AAC_HE_LATM = 19,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl
index b51e633..8a05dbd 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl
@@ -36,6 +36,7 @@
 @VintfStability
 parcelable DemuxFilterDownloadEvent {
   int itemId;
+  int downloadId;
   int mpuSequenceNumber;
   int itemFragmentIndex;
   int lastItemFragmentIndex;
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl
index ff06888..86ce646 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl
@@ -35,5 +35,6 @@
 /* @hide */
 @VintfStability
 parcelable DemuxFilterDownloadSettings {
+  boolean useDownloadId;
   int downloadId;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
index a463d68..61a9555 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
@@ -38,6 +38,8 @@
   int streamId;
   boolean isPtsPresent;
   long pts;
+  boolean isDtsPresent;
+  long dts;
   long dataLength;
   long offset;
   android.hardware.common.NativeHandle avMemory;
@@ -46,4 +48,5 @@
   int mpuSequenceNumber;
   boolean isPesPrivateData;
   android.hardware.tv.tuner.DemuxFilterMediaEventExtraMetaData extraMetaData;
+  android.hardware.tv.tuner.DemuxFilterScIndexMask scIndexMask;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl
index 01b8a77..199a09c 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl
@@ -38,5 +38,5 @@
   int tableId;
   int version;
   int sectionNum;
-  int dataLength;
+  long dataLength;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl
index 2858565..7936e59 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl
@@ -39,4 +39,5 @@
   boolean isCheckCrc;
   boolean isRepeat;
   boolean isRaw;
+  int bitWidthOfLengthField;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessage.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessage.aidl
index 2c6cc00..e763cfb 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessage.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessage.aidl
@@ -50,4 +50,5 @@
   android.hardware.tv.tuner.FrontendModulation modulation;
   android.hardware.tv.tuner.FrontendDvbcAnnex annex;
   boolean isHighPriority;
+  int[] dvbtCellIds;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl
index b121c85..6976ecd 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendScanMessageType.aidl
@@ -50,4 +50,5 @@
   MODULATION = 12,
   DVBC_ANNEX = 13,
   HIGH_PRIORITY = 14,
+  DVBT_CELL_IDS = 15,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
index 7677221..1e0f5f0 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
@@ -74,4 +74,7 @@
   boolean isShortFrames;
   android.hardware.tv.tuner.FrontendIsdbtMode isdbtMode;
   android.hardware.tv.tuner.FrontendIsdbtPartialReceptionFlag partialReceptionFlag;
+  int[] streamIdList;
+  int[] dvbtCellIds;
+  android.hardware.tv.tuner.FrontendScanAtsc3PlpInfo[] allPlpInfo;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
new file mode 100644
index 0000000..41944ce
--- /dev/null
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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.tv.tuner;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum FrontendStatusReadiness {
+  UNDEFINED = 0,
+  UNAVAILABLE = 1,
+  UNSTABLE = 2,
+  STABLE = 3,
+  UNSUPPORTED = 4,
+}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
index 6342479..cd6ccb3 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
@@ -74,4 +74,7 @@
   IS_SHORT_FRAMES = 36,
   ISDBT_MODE = 37,
   ISDBT_PARTIAL_RECEPTION_FLAG = 38,
+  STREAM_ID_LIST = 39,
+  DVBT_CELL_IDS = 40,
+  ATSC3_ALL_PLP_INFO = 41,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
index ed5b0c0..3e3ff4f 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
@@ -43,7 +43,9 @@
   void stopScan();
   android.hardware.tv.tuner.FrontendStatus[] getStatus(in android.hardware.tv.tuner.FrontendStatusType[] statusTypes);
   void setLnb(in int lnbId);
-  void setLna(in boolean bEnable);
   int linkCiCam(in int ciCamId);
   void unlinkCiCam(in int ciCamId);
+  String getHardwareInfo();
+  void removeOutputPid(int pid);
+  android.hardware.tv.tuner.FrontendStatusReadiness[] getFrontendStatusReadiness(in android.hardware.tv.tuner.FrontendStatusType[] statusTypes);
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
index 0e903d8..0ff2da9 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
@@ -44,4 +44,7 @@
   int[] getLnbIds();
   android.hardware.tv.tuner.ILnb openLnbById(in int lnbId);
   android.hardware.tv.tuner.ILnb openLnbByName(in String lnbName, out int[] lnbId);
+  void setLna(in boolean bEnable);
+  void setMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType, in int maxNumber);
+  int getMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType);
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/AudioStreamType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/AudioStreamType.aidl
index 1bb5c68f..9e9a8cf 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/AudioStreamType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/AudioStreamType.aidl
@@ -99,4 +99,24 @@
      * SJ/T 11368-2006
      */
     DRA,
+
+    /*
+     * AAC with ADTS (Audio Data Transport Format).
+     */
+    AAC_ADTS,
+
+    /*
+     * AAC with ADTS with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+     */
+    AAC_LATM,
+
+    /*
+     * High-Efficiency AAC (HE-AAC) with ADTS (Audio Data Transport Format).
+     */
+    AAC_HE_ADTS,
+
+    /*
+     * High-Efficiency AAC (HE-AAC) with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+     */
+    AAC_HE_LATM,
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl
index cf88928..b9df5a0 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadEvent.aidl
@@ -28,6 +28,11 @@
     int itemId;
 
     /**
+     * Uniquely identify data content within the same Package ID (PID).
+     */
+    int downloadId;
+
+    /**
      * MPU sequence number of filtered data (only for MMTP)
      */
     int mpuSequenceNumber;
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl
index bd79bd5..1188b03 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterDownloadSettings.aidl
@@ -23,6 +23,11 @@
 @VintfStability
 parcelable DemuxFilterDownloadSettings {
     /**
+     * Whether download ID should be used.
+     */
+    boolean useDownloadId;
+
+    /**
      * Download ID (also known as the carousel ID) is carried in the PMT in
      * ISO/IEC 13818-1 for the service containing the object carousel.
      */
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
index ec7bbf1..32f0cb2 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.aidl
@@ -19,6 +19,7 @@
 import android.hardware.common.NativeHandle;
 
 import android.hardware.tv.tuner.DemuxFilterMediaEventExtraMetaData;
+import android.hardware.tv.tuner.DemuxFilterScIndexMask;
 
 /**
  * Filter Event for Audio or Video Filter.
@@ -40,6 +41,16 @@
     long pts;
 
     /**
+     * true if DTS is present in the PES header.
+     */
+    boolean isDtsPresent;
+
+    /**
+     * Decode TimeStamp for audio or video frame.
+     */
+    long dts;
+
+    /**
      * Data size in bytes of audio or video frame
      */
     long dataLength;
@@ -74,4 +85,10 @@
     boolean isPesPrivateData;
 
     DemuxFilterMediaEventExtraMetaData extraMetaData;
+
+    /**
+     * DemuxFilterScIndexMask for the key frame info. It's optional to hardware which can only
+     * access unit framing at decode stage.
+     */
+    DemuxFilterScIndexMask scIndexMask;
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl
index d666316..a5f9ca7 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionEvent.aidl
@@ -40,5 +40,5 @@
     /**
      * Data size in bytes of filtered data
      */
-    int dataLength;
+    long dataLength;
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl
index 2102aa0..aa30175 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterSectionSettings.aidl
@@ -19,7 +19,7 @@
 import android.hardware.tv.tuner.DemuxFilterSectionSettingsCondition;
 
 /**
- * Filter Settings for Section data according to ISO/IEC 13818-1.
+ * Filter Settings for Section data according to ISO/IEC 13818-1 and ISO/IEC 23008-1.
  * @hide
  */
 @VintfStability
@@ -32,7 +32,16 @@
     boolean isCheckCrc;
 
     /**
-     * true if the filter repeats the data with the same version
+     * true if the filter repeats the data.
+     *
+     * If false, for DemuxFilterSectionSettingsConditionTableInfo, HAL filters out all sections
+     * based on tableId and version, and stops filtering data. For DemuxFilterSectionBits, HAL
+     * filters out first section which matches the DemuxFilterSectionBits configuration, and stops
+     * filtering data.
+     *
+     * If true, for DemuxFilterSectionSettingsConditionTableInfo, HAL filters out all sections based
+     * on tableId and version, and repeats. For DemuxFilterSectionBits, HAL filters out sections
+     * which match the DemuxFilterSectionBits configuration, and repeats.
      */
     boolean isRepeat;
 
@@ -40,4 +49,12 @@
      * true if the filter send onFilterStatus instead of onFilterEvent.
      */
     boolean isRaw;
+
+    /**
+     * The bit width of the MMTP (MPEG Media Transport Protocol) section message's length field
+     * according to ISO/IEC 23008-1.
+     *
+     * The filter uses this for CRC checking when isCheckCrc is true.
+     */
+    int bitWidthOfLengthField;
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
index f07c26f..e6f3b63 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
@@ -24,7 +24,8 @@
 @Backing(type="byte")
 enum DemuxFilterStatus {
     /**
-     * The data in the filter buffer is ready to be read.
+     * The data in the filter buffer is ready to be read. It can also be used to know the STC
+     * (System Time Clock) ready status if it's PCR filter.
      */
     DATA_READY = 1 << 0,
 
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendEventType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendEventType.aidl
index 40b5161..501dc1f 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendEventType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendEventType.aidl
@@ -24,7 +24,9 @@
 @Backing(type="int")
 enum FrontendEventType {
     /**
-     * The frontend has locked to the signal specified by the tune method.
+     * The frontend has locked to the signal specified by the tune method. It can also be notified
+     * after signal is locked if the signal attributes transmission parameter of the signal is
+     * changed (e.g., Modulation).
      */
     LOCKED,
 
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessage.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessage.aidl
index 19c6766..a941066 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessage.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessage.aidl
@@ -70,4 +70,10 @@
     FrontendDvbcAnnex annex;
 
     boolean isHighPriority;
+
+    /**
+     * DVB-T Cell Ids.
+     */
+    int[] dvbtCellIds;
+
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessageType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessageType.aidl
index 2b91216..f4d2ee0 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessageType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendScanMessageType.aidl
@@ -86,4 +86,10 @@
     DVBC_ANNEX,
 
     HIGH_PRIORITY,
+
+    /**
+     * DVB-T CELL ID.
+     */
+    DVBT_CELL_IDS,
+
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
index 9302b76..b5d0201 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
@@ -27,6 +27,7 @@
 import android.hardware.tv.tuner.FrontendModulationStatus;
 import android.hardware.tv.tuner.FrontendRollOff;
 import android.hardware.tv.tuner.FrontendSpectralInversion;
+import android.hardware.tv.tuner.FrontendScanAtsc3PlpInfo;
 import android.hardware.tv.tuner.FrontendStatusAtsc3PlpInfo;
 import android.hardware.tv.tuner.FrontendTransmissionMode;
 import android.hardware.tv.tuner.LnbVoltage;
@@ -91,11 +92,19 @@
 
     /**
      * AGC value is normalized from 0 to 255.
+     * Larger AGC values indicate it is applying more gain.
      */
     int agc;
 
     boolean isLnaOn;
 
+    /**
+     * Layer Error status.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, isLayerError[0] is the
+     * information of layer A. isLayerError[1] is the information of layer B.
+     */
     boolean[] isLayerError;
 
     /**
@@ -119,16 +128,28 @@
 
     /**
      * Modulation status.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, modulations[0] is the information
+     * of layer A. modulations[1] is the information of layer B.
      */
     FrontendModulation[] modulations;
 
     /**
      * Bit error ratio status.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, bers[0] is the information of
+     * layer A. bers[1] is the information of layer B.
      */
     int[] bers;
 
     /**
      * Code rate status.
+     *
+     * The order of the vectors is in ascending order of the required CN. The most robust layer is
+     * the first. For example, in ISDB-T, codeRates[0] is the information of layer A. codeRates[1]
+     * is the information of layer B.
      */
     FrontendInnerFec[] codeRates;
 
@@ -160,11 +181,19 @@
 
     /**
      * Frontend Interleaving Modes.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, interleaving[0] is the
+     * information of layer A. interleaving[1] is the information of layer B.
      */
     FrontendInterleaveMode[] interleaving;
 
     /**
      * Segments in ISDB-T Specification of all the channels.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, isdbtSegment[0] is the
+     * information of layer A. isdbtSegment[1] is the information of layer B.
      */
     int[] isdbtSegment;
 
@@ -202,4 +231,20 @@
      * ISDB-T Partial Reception Flag.
      */
     FrontendIsdbtPartialReceptionFlag partialReceptionFlag;
+
+    /**
+     * Stream ID list included in a transponder.
+     */
+    int[] streamIdList;
+
+    /**
+     * DVB-T Cell Id.
+     */
+    int[] dvbtCellIds;
+
+    /**
+     * A list of all PLPs in the frequency band for ATSC3 frontend, which includes both tuned
+     * and not tuned PLPs for currently watching service.
+     */
+    FrontendScanAtsc3PlpInfo[] allPlpInfo;
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusReadiness.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
new file mode 100644
index 0000000..a9e3080
--- /dev/null
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.tv.tuner;
+
+/**
+ * FrontendStatus readiness status.
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum FrontendStatusReadiness {
+    /**
+     * The FrontendStatus’ readiness status for the given FrontendStatusType is
+     * undefined.
+     */
+    UNDEFINED,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType is currently
+     * unavailable.
+     */
+    UNAVAILABLE,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType can be read, but it’s
+     * unstable.
+     */
+    UNSTABLE,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType can be ready, and it’s
+     * stable.
+     */
+    STABLE,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType is not supported.
+     */
+    UNSUPPORTED,
+}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
index 103a4ab..8f3f2c5 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
@@ -130,7 +130,7 @@
     RF_LOCK,
 
     /**
-     * PLP information in a frequency band for ATSC3.0 frontend.
+     * Current tuned PLP information in a frequency band for ATSC3 frontend.
      */
     ATSC3_PLP_INFO,
 
@@ -218,4 +218,20 @@
      * ISDB-T Partial Reception Flag.
      */
     ISDBT_PARTIAL_RECEPTION_FLAG,
+
+    /**
+     * Stream ID list included in a transponder.
+     */
+    STREAM_ID_LIST,
+
+    /**
+     * DVB-T Cell Id.
+     */
+    DVBT_CELL_IDS,
+
+    /**
+     * All PLP information in a frequency band for ATSC3 frontend, which includes both tuned
+     * and not tuned PLPs for currently watching service.
+     */
+    ATSC3_ALL_PLP_INFO,
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
index b2717db..12f2692 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
@@ -19,6 +19,7 @@
 import android.hardware.tv.tuner.FrontendScanType;
 import android.hardware.tv.tuner.FrontendSettings;
 import android.hardware.tv.tuner.FrontendStatus;
+import android.hardware.tv.tuner.FrontendStatusReadiness;
 import android.hardware.tv.tuner.FrontendStatusType;
 import android.hardware.tv.tuner.IFrontendCallback;
 
@@ -117,13 +118,6 @@
     void setLnb(in int lnbId);
 
     /**
-     * Enable or Disable Low Noise Amplifier (LNA).
-     *
-     * @param bEnable true if activate LNA module; false if deactivate LNA
-     */
-    void setLna(in boolean bEnable);
-
-    /**
      * Link Conditional Access Modules (CAM) to Frontend support Common
      * Interface (CI) bypass mode.
      *
@@ -143,4 +137,33 @@
      * @param ciCamId specify CI-CAM Id to unlink.
      */
     void unlinkCiCam(in int ciCamId);
+
+    /**
+     * Request Hardware information about the frontend.
+     *
+     * The client may use this to collect vendor specific hardware information, e.g. RF
+     * chip version, Demod chip version, detailed status of dvbs blind scan, etc.
+     *
+     * @return the frontend hardware information.
+     */
+    String getHardwareInfo();
+
+    /**
+     * Filter out unnecessary PID from frontend output.
+     *
+     * @param pid specify the PID will be filtered out.
+     *
+     * @return UNAVAILABLE if the frontend doesn’t support PID filtering out.
+     */
+    void removeOutputPid(int pid);
+
+    /**
+     * Gets FrontendStatus’ readiness statuses for given status types.
+     *
+     * @param statusTypes an array of status types.
+     *
+     * @return an array of current readiness statuses. The ith readiness status in
+     *         the array presents fronted type statusTypes[i]’s readiness status.
+     */
+    FrontendStatusReadiness[] getFrontendStatusReadiness(in FrontendStatusType[] statusTypes);
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
index ab8b0b8..03def33 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.tv.tuner.DemuxCapabilities;
 import android.hardware.tv.tuner.FrontendInfo;
+import android.hardware.tv.tuner.FrontendType;
 import android.hardware.tv.tuner.IDemux;
 import android.hardware.tv.tuner.IDescrambler;
 import android.hardware.tv.tuner.IFrontend;
@@ -120,4 +121,31 @@
      * @return the newly opened Lnb iterface.
      */
     ILnb openLnbByName(in String lnbName, out int[] lnbId);
+
+    /**
+     * Enable or Disable Low Noise Amplifier (LNA).
+     *
+     * @param bEnable true if activate LNA module; false if deactivate LNA
+     */
+    void setLna(in boolean bEnable);
+
+    /**
+     * Set the maximum usable frontends number of a given frontend type.
+     *
+     * It is used by the client to enable or disable frontends when cable connection status
+     * is changed by user.
+     *
+     * @param frontendType the frontend type which the maximum usable number will be set.
+     * @param maxNumber the new maximum usable number.
+     */
+    void setMaxNumberOfFrontends(in FrontendType frontendType, in int maxNumber);
+
+    /**
+     * Get the maximum usable frontends number of a given frontend type.
+     *
+     * @param frontendType the frontend type which the maximum usable number will be queried.
+     *
+     * @return the maximum usable number of the queried frontend type.
+     */
+    int getMaxNumberOfFrontends(in FrontendType frontendType);
 }
diff --git a/tv/tuner/aidl/default/Demux.cpp b/tv/tuner/aidl/default/Demux.cpp
index 4385461..a94b4ad 100644
--- a/tv/tuner/aidl/default/Demux.cpp
+++ b/tv/tuner/aidl/default/Demux.cpp
@@ -410,6 +410,37 @@
     return mIsRecording;
 }
 
+binder_status_t Demux::dump(int fd, const char** args, uint32_t numArgs) {
+    dprintf(fd, " Demux %d:\n", mDemuxId);
+    dprintf(fd, "  mIsRecording %d\n", mIsRecording);
+    {
+        dprintf(fd, "  Filters:\n");
+        map<int64_t, std::shared_ptr<Filter>>::iterator it;
+        for (it = mFilters.begin(); it != mFilters.end(); it++) {
+            it->second->dump(fd, args, numArgs);
+        }
+    }
+    {
+        dprintf(fd, "  TimeFilter:\n");
+        if (mTimeFilter != nullptr) {
+            mTimeFilter->dump(fd, args, numArgs);
+        }
+    }
+    {
+        dprintf(fd, "  DvrPlayback:\n");
+        if (mDvrPlayback != nullptr) {
+            mDvrPlayback->dump(fd, args, numArgs);
+        }
+    }
+    {
+        dprintf(fd, "  DvrRecord:\n");
+        if (mDvrRecord != nullptr) {
+            mDvrRecord->dump(fd, args, numArgs);
+        }
+    }
+    return STATUS_OK;
+}
+
 bool Demux::attachRecordFilter(int64_t filterId) {
     if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
         !mFilters[filterId]->isRecordFilter()) {
diff --git a/tv/tuner/aidl/default/Demux.h b/tv/tuner/aidl/default/Demux.h
index 1b789bd..7f0b0a7 100644
--- a/tv/tuner/aidl/default/Demux.h
+++ b/tv/tuner/aidl/default/Demux.h
@@ -71,6 +71,8 @@
     ::ndk::ScopedAStatus connectCiCam(int32_t in_ciCamId) override;
     ::ndk::ScopedAStatus disconnectCiCam() override;
 
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
     // Functions interacts with Tuner Service
     void stopFrontendInput();
     ::ndk::ScopedAStatus removeFilter(int64_t filterId);
diff --git a/tv/tuner/aidl/default/Dvr.cpp b/tv/tuner/aidl/default/Dvr.cpp
index 4f34b8e..c591d07 100644
--- a/tv/tuner/aidl/default/Dvr.cpp
+++ b/tv/tuner/aidl/default/Dvr.cpp
@@ -177,6 +177,13 @@
     return mDvrEventFlag;
 }
 
+binder_status_t Dvr::dump(int fd, const char** /* args */, uint32_t /* numArgs */) {
+    dprintf(fd, "    Dvr:\n");
+    dprintf(fd, "      mType: %hhd\n", mType);
+    dprintf(fd, "      mDvrThreadRunning: %d\n", (bool)mDvrThreadRunning);
+    return STATUS_OK;
+}
+
 void Dvr::playbackThreadLoop() {
     ALOGD("[Dvr] playback threadLoop start.");
 
diff --git a/tv/tuner/aidl/default/Dvr.h b/tv/tuner/aidl/default/Dvr.h
index ad8728e..6ff71cd 100644
--- a/tv/tuner/aidl/default/Dvr.h
+++ b/tv/tuner/aidl/default/Dvr.h
@@ -71,6 +71,8 @@
     ::ndk::ScopedAStatus flush() override;
     ::ndk::ScopedAStatus close() override;
 
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
     /**
      * To create a DvrMQ and its Event Flag.
      *
diff --git a/tv/tuner/aidl/default/Filter.cpp b/tv/tuner/aidl/default/Filter.cpp
index 54037be..769ebe2 100644
--- a/tv/tuner/aidl/default/Filter.cpp
+++ b/tv/tuner/aidl/default/Filter.cpp
@@ -22,6 +22,7 @@
 #include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
 #include <aidl/android/hardware/tv/tuner/Result.h>
 #include <aidlcommonsupport/NativeHandle.h>
+#include <inttypes.h>
 #include <utils/Log.h>
 
 #include "Filter.h"
@@ -655,6 +656,17 @@
     mSharedAvMemHandle = nullptr;
 }
 
+binder_status_t Filter::dump(int fd, const char** /* args */, uint32_t /* numArgs */) {
+    dprintf(fd, "    Filter %" PRIu64 ":\n", mFilterId);
+    dprintf(fd, "      Main type: %d\n", mType.mainType);
+    dprintf(fd, "      mIsMediaFilter: %d\n", mIsMediaFilter);
+    dprintf(fd, "      mIsPcrFilter: %d\n", mIsPcrFilter);
+    dprintf(fd, "      mIsRecordFilter: %d\n", mIsRecordFilter);
+    dprintf(fd, "      mIsUsingFMQ: %d\n", mIsUsingFMQ);
+    dprintf(fd, "      mFilterThreadRunning: %d\n", (bool)mFilterThreadRunning);
+    return STATUS_OK;
+}
+
 void Filter::maySendFilterStatusCallback() {
     if (!mIsUsingFMQ) {
         return;
@@ -1148,6 +1160,7 @@
     DemuxFilterMediaEvent mediaEvent;
     mediaEvent.streamId = 1;
     mediaEvent.isPtsPresent = true;
+    mediaEvent.isDtsPresent = false;
     mediaEvent.dataLength = 3;
     mediaEvent.offset = 4;
     mediaEvent.isSecureMemory = true;
@@ -1238,6 +1251,7 @@
 void Filter::createDownloadEvent(vector<DemuxFilterEvent>& events) {
     DemuxFilterDownloadEvent download;
     download.itemId = 1;
+    download.downloadId = 1;
     download.mpuSequenceNumber = 2;
     download.itemFragmentIndex = 3;
     download.lastItemFragmentIndex = 4;
diff --git a/tv/tuner/aidl/default/Filter.h b/tv/tuner/aidl/default/Filter.h
index 8388c98..e301249 100644
--- a/tv/tuner/aidl/default/Filter.h
+++ b/tv/tuner/aidl/default/Filter.h
@@ -126,6 +126,8 @@
     ::ndk::ScopedAStatus setDataSource(const std::shared_ptr<IFilter>& in_filter) override;
     ::ndk::ScopedAStatus setDelayHint(const FilterDelayHint& in_hint) override;
 
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
     /**
      * To create a FilterMQ and its Event Flag.
      *
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 77d20e2..056d014 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -34,6 +34,140 @@
     mTuner = tuner;
     // Init callback to nullptr
     mCallback = nullptr;
+
+    switch (mType) {
+        case FrontendType::ISDBS: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::isdbsCaps>(FrontendIsdbsCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::DEMOD_LOCK,
+                    FrontendStatusType::SNR,
+                    FrontendStatusType::FEC,
+                    FrontendStatusType::MODULATION,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::ROLL_OFF,
+                    FrontendStatusType::STREAM_ID_LIST,
+            };
+            break;
+        }
+        case FrontendType::ATSC3: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::atsc3Caps>(FrontendAtsc3Capabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::BER,
+                    FrontendStatusType::PER,
+                    FrontendStatusType::ATSC3_PLP_INFO,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::BERS,
+                    FrontendStatusType::INTERLEAVINGS,
+                    FrontendStatusType::BANDWIDTH,
+                    FrontendStatusType::ATSC3_ALL_PLP_INFO,
+            };
+            break;
+        }
+        case FrontendType::DVBC: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dvbcCaps>(FrontendDvbcCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::PRE_BER,       FrontendStatusType::SIGNAL_QUALITY,
+                    FrontendStatusType::MODULATION,    FrontendStatusType::SPECTRAL,
+                    FrontendStatusType::MODULATIONS,   FrontendStatusType::CODERATES,
+                    FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH,
+            };
+            break;
+        }
+        case FrontendType::DVBS: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dvbsCaps>(FrontendDvbsCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::SIGNAL_STRENGTH, FrontendStatusType::SYMBOL_RATE,
+                    FrontendStatusType::MODULATION,      FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::ROLL_OFF,        FrontendStatusType::IS_MISO,
+            };
+            break;
+        }
+        case FrontendType::DVBT: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dvbtCaps>(FrontendDvbtCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::EWBS,
+                    FrontendStatusType::PLP_ID,
+                    FrontendStatusType::HIERARCHY,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::BANDWIDTH,
+                    FrontendStatusType::GUARD_INTERVAL,
+                    FrontendStatusType::TRANSMISSION_MODE,
+                    FrontendStatusType::T2_SYSTEM_ID,
+                    FrontendStatusType::DVBT_CELL_IDS,
+            };
+            break;
+        }
+        case FrontendType::ISDBT: {
+            FrontendIsdbtCapabilities isdbtCaps{
+                    .modeCap = (int)FrontendIsdbtMode::MODE_1 | (int)FrontendIsdbtMode::MODE_2,
+                    .bandwidthCap = (int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
+                    .modulationCap = (int)FrontendIsdbtModulation::MOD_16QAM,
+                    .coderateCap = (int)FrontendIsdbtCoderate::CODERATE_4_5 |
+                                   (int)FrontendIsdbtCoderate::CODERATE_6_7,
+                    .guardIntervalCap = (int)FrontendIsdbtGuardInterval::INTERVAL_1_128,
+                    .timeInterleaveCap = (int)FrontendIsdbtTimeInterleaveMode::AUTO |
+                                         (int)FrontendIsdbtTimeInterleaveMode::INTERLEAVE_1_0,
+                    .isSegmentAuto = true,
+                    .isFullSegment = true,
+            };
+            mFrontendCaps.set<FrontendCapabilities::Tag::isdbtCaps>(isdbtCaps);
+            mFrontendStatusCaps = {
+                    FrontendStatusType::AGC,
+                    FrontendStatusType::LNA,
+                    FrontendStatusType::MODULATION,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::BANDWIDTH,
+                    FrontendStatusType::GUARD_INTERVAL,
+                    FrontendStatusType::TRANSMISSION_MODE,
+                    FrontendStatusType::ISDBT_SEGMENTS,
+                    FrontendStatusType::ISDBT_MODE,
+                    FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG,
+                    FrontendStatusType::INTERLEAVINGS,
+            };
+            break;
+        }
+        case FrontendType::ANALOG: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::analogCaps>(FrontendAnalogCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::LAYER_ERROR,
+                    FrontendStatusType::MER,
+                    FrontendStatusType::UEC,
+                    FrontendStatusType::TS_DATA_RATES,
+            };
+            break;
+        }
+        case FrontendType::ATSC: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::atscCaps>(FrontendAtscCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::FREQ_OFFSET,
+                    FrontendStatusType::RF_LOCK,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::IS_LINEAR,
+            };
+            break;
+        }
+        case FrontendType::ISDBS3: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::isdbs3Caps>(FrontendIsdbs3Capabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::DEMOD_LOCK,      FrontendStatusType::MODULATION,
+                    FrontendStatusType::MODULATIONS,     FrontendStatusType::ROLL_OFF,
+                    FrontendStatusType::IS_SHORT_FRAMES, FrontendStatusType::STREAM_ID_LIST,
+            };
+            break;
+        }
+        case FrontendType::DTMB: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dtmbCaps>(FrontendDtmbCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::MODULATIONS,       FrontendStatusType::INTERLEAVINGS,
+                    FrontendStatusType::BANDWIDTH,         FrontendStatusType::GUARD_INTERVAL,
+                    FrontendStatusType::TRANSMISSION_MODE,
+            };
+            break;
+        }
+        default: {
+            break;
+        }
+    }
 }
 
 Frontend::~Frontend() {}
@@ -87,47 +221,60 @@
 ::ndk::ScopedAStatus Frontend::scan(const FrontendSettings& in_settings, FrontendScanType in_type) {
     ALOGV("%s", __FUNCTION__);
 
+    // If it's in middle of scanning, stop it first.
+    if (mScanThread.joinable()) {
+        mScanThread.join();
+    }
+
+    mFrontendSettings = in_settings;
+    mFrontendScanType = in_type;
+    mScanThread = std::thread(&Frontend::scanThreadLoop, this);
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+void Frontend::scanThreadLoop() {
     if (mIsLocked) {
         FrontendScanMessage msg;
         msg.set<FrontendScanMessage::Tag::isEnd>(true);
         mCallback->onScanMessage(FrontendScanMessageType::END, msg);
-        return ::ndk::ScopedAStatus::ok();
+        return;
     }
 
     int64_t frequency = 0;
-    switch (in_settings.getTag()) {
+    switch (mFrontendSettings.getTag()) {
         case FrontendSettings::Tag::analog:
-            frequency = in_settings.get<FrontendSettings::Tag::analog>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::analog>().frequency;
             break;
         case FrontendSettings::Tag::atsc:
-            frequency = in_settings.get<FrontendSettings::Tag::atsc>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::atsc>().frequency;
             break;
         case FrontendSettings::Tag::atsc3:
-            frequency = in_settings.get<FrontendSettings::Tag::atsc3>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::atsc3>().frequency;
             break;
         case FrontendSettings::Tag::dvbs:
-            frequency = in_settings.get<FrontendSettings::Tag::dvbs>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::dvbs>().frequency;
             break;
         case FrontendSettings::Tag::dvbc:
-            frequency = in_settings.get<FrontendSettings::Tag::dvbc>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::dvbc>().frequency;
             break;
         case FrontendSettings::Tag::dvbt:
-            frequency = in_settings.get<FrontendSettings::Tag::dvbt>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::dvbt>().frequency;
             break;
         case FrontendSettings::Tag::isdbs:
-            frequency = in_settings.get<FrontendSettings::Tag::isdbs>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::isdbs>().frequency;
             break;
         case FrontendSettings::Tag::isdbs3:
-            frequency = in_settings.get<FrontendSettings::Tag::isdbs3>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::isdbs3>().frequency;
             break;
         case FrontendSettings::Tag::isdbt:
-            frequency = in_settings.get<FrontendSettings::Tag::isdbt>().frequency;
+            frequency = mFrontendSettings.get<FrontendSettings::Tag::isdbt>().frequency;
             break;
         default:
             break;
     }
 
-    if (in_type == FrontendScanType::SCAN_BLIND) {
+    if (mFrontendScanType == FrontendScanType::SCAN_BLIND) {
         frequency += 100 * 1000;
     }
 
@@ -237,19 +384,28 @@
         mCallback->onScanMessage(FrontendScanMessageType::HIGH_PRIORITY, msg);
     }
 
+    if (mType == FrontendType::DVBT) {
+        FrontendScanMessage msg;
+        vector<int32_t> dvbtCellIds = {0, 1};
+        msg.set<FrontendScanMessage::Tag::dvbtCellIds>(dvbtCellIds);
+        mCallback->onScanMessage(FrontendScanMessageType::DVBT_CELL_IDS, msg);
+    }
+
     {
         FrontendScanMessage msg;
         msg.set<FrontendScanMessage::Tag::isLocked>(true);
         mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
         mIsLocked = true;
     }
-
-    return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus Frontend::stopScan() {
     ALOGV("%s", __FUNCTION__);
 
+    if (mScanThread.joinable()) {
+        mScanThread.join();
+    }
+
     mIsLocked = false;
     return ::ndk::ScopedAStatus::ok();
 }
@@ -676,6 +832,30 @@
                         FrontendIsdbtPartialReceptionFlag::AUTO);
                 break;
             }
+            case FrontendStatusType::STREAM_ID_LIST: {
+                vector<int32_t> streamIds = {0, 1};
+                status.set<FrontendStatus::streamIdList>(streamIds);
+                break;
+            }
+            case FrontendStatusType::DVBT_CELL_IDS: {
+                vector<int32_t> dvbtCellIds = {0, 1};
+                status.set<FrontendStatus::dvbtCellIds>(dvbtCellIds);
+                break;
+            }
+            case FrontendStatusType::ATSC3_ALL_PLP_INFO: {
+                FrontendScanAtsc3PlpInfo info1;
+                info1.plpId = 1;
+                info1.bLlsFlag = false;
+                FrontendScanAtsc3PlpInfo info2;
+                info2.plpId = 2;
+                info2.bLlsFlag = true;
+                FrontendScanAtsc3PlpInfo info3;
+                info3.plpId = 3;
+                info3.bLlsFlag = false;
+                vector<FrontendScanAtsc3PlpInfo> infos = {info1, info2, info3};
+                status.set<FrontendStatus::allPlpInfo>(infos);
+                break;
+            }
             default: {
                 continue;
             }
@@ -686,12 +866,6 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus Frontend::setLna(bool /* in_bEnable */) {
-    ALOGV("%s", __FUNCTION__);
-
-    return ::ndk::ScopedAStatus::ok();
-}
-
 ::ndk::ScopedAStatus Frontend::setLnb(int32_t /* in_lnbId */) {
     ALOGV("%s", __FUNCTION__);
     if (!supportsSatellite()) {
@@ -718,6 +892,55 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+binder_status_t Frontend::dump(int fd, const char** /* args */, uint32_t /* numArgs */) {
+    dprintf(fd, "  Frontend %d\n", mId);
+    dprintf(fd, "    mType: %d\n", mType);
+    dprintf(fd, "    mIsLocked: %d\n", mIsLocked);
+    dprintf(fd, "    mCiCamId: %d\n", mCiCamId);
+    dprintf(fd, "    mFrontendStatusCaps:");
+    for (int i = 0; i < mFrontendStatusCaps.size(); i++) {
+        dprintf(fd, "        %d\n", mFrontendStatusCaps[i]);
+    }
+    return STATUS_OK;
+}
+
+::ndk::ScopedAStatus Frontend::getHardwareInfo(std::string* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    *_aidl_return = "Sample Frontend";
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Frontend::removeOutputPid(int32_t /* in_pid */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(
+            static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
+::ndk::ScopedAStatus Frontend::getFrontendStatusReadiness(
+        const std::vector<FrontendStatusType>& in_statusTypes,
+        std::vector<FrontendStatusReadiness>* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    _aidl_return->resize(in_statusTypes.size());
+    for (int i = 0; i < in_statusTypes.size(); i++) {
+        int j = 0;
+        while (j < mFrontendStatusCaps.size()) {
+            if (in_statusTypes[i] == mFrontendStatusCaps[j]) {
+                (*_aidl_return)[i] = FrontendStatusReadiness::STABLE;
+                break;
+            }
+            j++;
+        }
+        if (j >= mFrontendStatusCaps.size()) {
+            (*_aidl_return)[i] = FrontendStatusReadiness::UNSUPPORTED;
+        }
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
 FrontendType Frontend::getFrontendType() {
     return mType;
 }
@@ -735,6 +958,21 @@
     return mIsLocked;
 }
 
+void Frontend::getFrontendInfo(FrontendInfo* _aidl_return) {
+    // assign randomly selected values for testing.
+    *_aidl_return = {
+            .type = mType,
+            .minFrequency = 139000000,
+            .maxFrequency = 1139000000,
+            .minSymbolRate = 45,
+            .maxSymbolRate = 1145,
+            .acquireRange = 30,
+            .exclusiveGroupId = 57,
+            .statusCaps = mFrontendStatusCaps,
+            .frontendCaps = mFrontendCaps,
+    };
+}
+
 }  // namespace tuner
 }  // namespace tv
 }  // namespace hardware
diff --git a/tv/tuner/aidl/default/Frontend.h b/tv/tuner/aidl/default/Frontend.h
index 3c602cf..1d9ab53 100644
--- a/tv/tuner/aidl/default/Frontend.h
+++ b/tv/tuner/aidl/default/Frontend.h
@@ -19,6 +19,7 @@
 #include <aidl/android/hardware/tv/tuner/BnFrontend.h>
 #include <fstream>
 #include <iostream>
+#include <thread>
 #include "Tuner.h"
 
 using namespace std;
@@ -46,26 +47,39 @@
     ::ndk::ScopedAStatus getStatus(const std::vector<FrontendStatusType>& in_statusTypes,
                                    std::vector<FrontendStatus>* _aidl_return) override;
     ::ndk::ScopedAStatus setLnb(int32_t in_lnbId) override;
-    ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
     ::ndk::ScopedAStatus linkCiCam(int32_t in_ciCamId, int32_t* _aidl_return) override;
     ::ndk::ScopedAStatus unlinkCiCam(int32_t in_ciCamId) override;
+    ::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+    ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
+    ::ndk::ScopedAStatus getFrontendStatusReadiness(
+            const std::vector<FrontendStatusType>& in_statusTypes,
+            std::vector<FrontendStatusReadiness>* _aidl_return) override;
+
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
     FrontendType getFrontendType();
     int32_t getFrontendId();
     string getSourceFile();
     bool isLocked();
+    void getFrontendInfo(FrontendInfo* _aidl_return);
 
   private:
     virtual ~Frontend();
     bool supportsSatellite();
+    void scanThreadLoop();
+
     std::shared_ptr<IFrontendCallback> mCallback;
     std::shared_ptr<Tuner> mTuner;
     FrontendType mType = FrontendType::UNDEFINED;
     int32_t mId = 0;
     bool mIsLocked = false;
     int32_t mCiCamId;
-
+    std::thread mScanThread;
+    FrontendSettings mFrontendSettings;
+    FrontendScanType mFrontendScanType;
     std::ifstream mFrontendData;
+    FrontendCapabilities mFrontendCaps;
+    vector<FrontendStatusType> mFrontendStatusCaps;
 };
 
 }  // namespace tuner
diff --git a/tv/tuner/aidl/default/Lnb.cpp b/tv/tuner/aidl/default/Lnb.cpp
index 35d2da6..f9343ae 100644
--- a/tv/tuner/aidl/default/Lnb.cpp
+++ b/tv/tuner/aidl/default/Lnb.cpp
@@ -34,9 +34,11 @@
 
 Lnb::~Lnb() {}
 
-::ndk::ScopedAStatus Lnb::setCallback(const std::shared_ptr<ILnbCallback>& /* in_callback */) {
+::ndk::ScopedAStatus Lnb::setCallback(const std::shared_ptr<ILnbCallback>& in_callback) {
     ALOGV("%s", __FUNCTION__);
 
+    mCallback = in_callback;
+
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -58,9 +60,17 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus Lnb::sendDiseqcMessage(const std::vector<uint8_t>& /* in_diseqcMessage */) {
+::ndk::ScopedAStatus Lnb::sendDiseqcMessage(const std::vector<uint8_t>& in_diseqcMessage) {
     ALOGV("%s", __FUNCTION__);
 
+    if (mCallback != nullptr) {
+        // The correct implementation should be to return the response from the
+        // device via onDiseqcMessage(). The below implementation is only to enable
+        // testing for LnbCallbacks.
+        ALOGV("[aidl] %s - this is for test purpose only, and must be replaced!", __FUNCTION__);
+        mCallback->onDiseqcMessage(in_diseqcMessage);
+    }
+
     return ::ndk::ScopedAStatus::ok();
 }
 
diff --git a/tv/tuner/aidl/default/Lnb.h b/tv/tuner/aidl/default/Lnb.h
index bfe3097..464f9a4 100644
--- a/tv/tuner/aidl/default/Lnb.h
+++ b/tv/tuner/aidl/default/Lnb.h
@@ -44,6 +44,7 @@
   private:
     int mId;
     virtual ~Lnb();
+    std::shared_ptr<ILnbCallback> mCallback;
 };
 
 }  // namespace tuner
diff --git a/tv/tuner/aidl/default/TimeFilter.cpp b/tv/tuner/aidl/default/TimeFilter.cpp
index dde7be3..9611ed9 100644
--- a/tv/tuner/aidl/default/TimeFilter.cpp
+++ b/tv/tuner/aidl/default/TimeFilter.cpp
@@ -83,6 +83,12 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+binder_status_t TimeFilter::dump(int fd, const char** /* args */, uint32_t /* numArgs */) {
+    dprintf(fd, "    TimeFilter:\n");
+    dprintf(fd, "      mTimeStamp: %" PRIu64 "\n", mTimeStamp);
+    return STATUS_OK;
+}
+
 }  // namespace tuner
 }  // namespace tv
 }  // namespace hardware
diff --git a/tv/tuner/aidl/default/TimeFilter.h b/tv/tuner/aidl/default/TimeFilter.h
index ff35c47..5f4c2d4 100644
--- a/tv/tuner/aidl/default/TimeFilter.h
+++ b/tv/tuner/aidl/default/TimeFilter.h
@@ -44,8 +44,10 @@
     ::ndk::ScopedAStatus getSourceTime(int64_t* _aidl_return) override;
     ::ndk::ScopedAStatus close() override;
 
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
   private:
-    std::shared_ptr<Demux> mDemux;
+    ::std::shared_ptr<Demux> mDemux;
     uint64_t mTimeStamp = INVALID_TIME_STAMP;
     time_t mBeginTime;
 };
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index badb08f..fa74288 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -49,139 +49,16 @@
     mFrontends[8] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS3, 8, this->ref<Tuner>());
     mFrontends[9] = ndk::SharedRefBase::make<Frontend>(FrontendType::DTMB, 9, this->ref<Tuner>());
 
-    vector<FrontendStatusType> statusCaps;
-
-    FrontendCapabilities capsIsdbs;
-    capsIsdbs.set<FrontendCapabilities::Tag::isdbsCaps>(FrontendIsdbsCapabilities());
-    mFrontendCaps[0] = capsIsdbs;
-    statusCaps = {
-            FrontendStatusType::DEMOD_LOCK,  FrontendStatusType::SNR,
-            FrontendStatusType::FEC,         FrontendStatusType::MODULATION,
-            FrontendStatusType::MODULATIONS, FrontendStatusType::ROLL_OFF,
-    };
-    mFrontendStatusCaps[0] = statusCaps;
-
-    FrontendCapabilities capsAtsc3;
-    capsAtsc3.set<FrontendCapabilities::Tag::atsc3Caps>(FrontendAtsc3Capabilities());
-    mFrontendCaps[1] = capsAtsc3;
-    statusCaps = {
-            FrontendStatusType::BER,
-            FrontendStatusType::PER,
-            FrontendStatusType::ATSC3_PLP_INFO,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::BERS,
-            FrontendStatusType::INTERLEAVINGS,
-            FrontendStatusType::BANDWIDTH,
-    };
-    mFrontendStatusCaps[1] = statusCaps;
-
-    FrontendCapabilities capsDvbc;
-    capsDvbc.set<FrontendCapabilities::Tag::dvbcCaps>(FrontendDvbcCapabilities());
-    mFrontendCaps[2] = capsDvbc;
-    statusCaps = {
-            FrontendStatusType::PRE_BER,       FrontendStatusType::SIGNAL_QUALITY,
-            FrontendStatusType::MODULATION,    FrontendStatusType::SPECTRAL,
-            FrontendStatusType::MODULATIONS,   FrontendStatusType::CODERATES,
-            FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH,
-    };
-    mFrontendStatusCaps[2] = statusCaps;
-
-    FrontendCapabilities capsDvbs;
-    capsDvbs.set<FrontendCapabilities::Tag::dvbsCaps>(FrontendDvbsCapabilities());
-    mFrontendCaps[3] = capsDvbs;
-    statusCaps = {
-            FrontendStatusType::SIGNAL_STRENGTH, FrontendStatusType::SYMBOL_RATE,
-            FrontendStatusType::MODULATION,      FrontendStatusType::MODULATIONS,
-            FrontendStatusType::ROLL_OFF,        FrontendStatusType::IS_MISO,
-    };
-    mFrontendStatusCaps[3] = statusCaps;
-
-    FrontendCapabilities capsDvbt;
-    capsDvbt.set<FrontendCapabilities::Tag::dvbtCaps>(FrontendDvbtCapabilities());
-    mFrontendCaps[4] = capsDvbt;
-    statusCaps = {
-            FrontendStatusType::EWBS,
-            FrontendStatusType::PLP_ID,
-            FrontendStatusType::HIERARCHY,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::BANDWIDTH,
-            FrontendStatusType::GUARD_INTERVAL,
-            FrontendStatusType::TRANSMISSION_MODE,
-            FrontendStatusType::T2_SYSTEM_ID,
-    };
-    mFrontendStatusCaps[4] = statusCaps;
-
-    FrontendCapabilities capsIsdbt;
-    FrontendIsdbtCapabilities isdbtCaps{
-            .modeCap = (int)FrontendIsdbtMode::MODE_1 | (int)FrontendIsdbtMode::MODE_2,
-            .bandwidthCap = (int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
-            .modulationCap = (int)FrontendIsdbtModulation::MOD_16QAM,
-            .coderateCap = (int)FrontendIsdbtCoderate::CODERATE_4_5 |
-                           (int)FrontendIsdbtCoderate::CODERATE_6_7,
-            .guardIntervalCap = (int)FrontendIsdbtGuardInterval::INTERVAL_1_128,
-            .timeInterleaveCap = (int)FrontendIsdbtTimeInterleaveMode::AUTO |
-                                 (int)FrontendIsdbtTimeInterleaveMode::INTERLEAVE_1_0,
-            .isSegmentAuto = true,
-            .isFullSegment = true,
-    };
-    capsIsdbt.set<FrontendCapabilities::Tag::isdbtCaps>(isdbtCaps);
-    mFrontendCaps[5] = capsIsdbt;
-    statusCaps = {
-            FrontendStatusType::AGC,
-            FrontendStatusType::LNA,
-            FrontendStatusType::MODULATION,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::BANDWIDTH,
-            FrontendStatusType::GUARD_INTERVAL,
-            FrontendStatusType::TRANSMISSION_MODE,
-            FrontendStatusType::ISDBT_SEGMENTS,
-            FrontendStatusType::ISDBT_MODE,
-            FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG,
-            FrontendStatusType::INTERLEAVINGS,
-    };
-    mFrontendStatusCaps[5] = statusCaps;
-
-    FrontendCapabilities capsAnalog;
-    capsAnalog.set<FrontendCapabilities::Tag::analogCaps>(FrontendAnalogCapabilities());
-    mFrontendCaps[6] = capsAnalog;
-    statusCaps = {
-            FrontendStatusType::LAYER_ERROR,
-            FrontendStatusType::MER,
-            FrontendStatusType::UEC,
-            FrontendStatusType::TS_DATA_RATES,
-    };
-    mFrontendStatusCaps[6] = statusCaps;
-
-    FrontendCapabilities capsAtsc;
-    capsAtsc.set<FrontendCapabilities::Tag::atscCaps>(FrontendAtscCapabilities());
-    mFrontendCaps[7] = capsAtsc;
-    statusCaps = {
-            FrontendStatusType::FREQ_OFFSET,
-            FrontendStatusType::RF_LOCK,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::IS_LINEAR,
-    };
-    mFrontendStatusCaps[7] = statusCaps;
-
-    FrontendCapabilities capsIsdbs3;
-    capsIsdbs3.set<FrontendCapabilities::Tag::isdbs3Caps>(FrontendIsdbs3Capabilities());
-    mFrontendCaps[8] = capsIsdbs3;
-    statusCaps = {
-            FrontendStatusType::DEMOD_LOCK,      FrontendStatusType::MODULATION,
-            FrontendStatusType::MODULATIONS,     FrontendStatusType::ROLL_OFF,
-            FrontendStatusType::IS_SHORT_FRAMES,
-    };
-    mFrontendStatusCaps[8] = statusCaps;
-
-    FrontendCapabilities capsDtmb;
-    capsDtmb.set<FrontendCapabilities::Tag::dtmbCaps>(FrontendDtmbCapabilities());
-    mFrontendCaps[9] = capsDtmb;
-    statusCaps = {
-            FrontendStatusType::MODULATIONS,       FrontendStatusType::INTERLEAVINGS,
-            FrontendStatusType::BANDWIDTH,         FrontendStatusType::GUARD_INTERVAL,
-            FrontendStatusType::TRANSMISSION_MODE,
-    };
-    mFrontendStatusCaps[9] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ISDBS] = 1;
+    mMaxUsableFrontends[FrontendType::ATSC3] = 1;
+    mMaxUsableFrontends[FrontendType::DVBC] = 1;
+    mMaxUsableFrontends[FrontendType::DVBS] = 1;
+    mMaxUsableFrontends[FrontendType::DVBT] = 1;
+    mMaxUsableFrontends[FrontendType::ISDBT] = 1;
+    mMaxUsableFrontends[FrontendType::ANALOG] = 1;
+    mMaxUsableFrontends[FrontendType::ATSC] = 1;
+    mMaxUsableFrontends[FrontendType::ISDBS3] = 1;
+    mMaxUsableFrontends[FrontendType::DTMB] = 1;
 
     mLnbs.resize(2);
     mLnbs[0] = ndk::SharedRefBase::make<Lnb>(0);
@@ -251,24 +128,12 @@
 ::ndk::ScopedAStatus Tuner::getFrontendInfo(int32_t in_frontendId, FrontendInfo* _aidl_return) {
     ALOGV("%s", __FUNCTION__);
 
-    if (in_frontendId >= mFrontendSize) {
+    if (in_frontendId < 0 || in_frontendId >= mFrontendSize) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(Result::INVALID_ARGUMENT));
     }
 
-    // assign randomly selected values for testing.
-    *_aidl_return = {
-            .type = mFrontends[in_frontendId]->getFrontendType(),
-            .minFrequency = 139000000,
-            .maxFrequency = 1139000000,
-            .minSymbolRate = 45,
-            .maxSymbolRate = 1145,
-            .acquireRange = 30,
-            .exclusiveGroupId = 57,
-            .statusCaps = mFrontendStatusCaps[in_frontendId],
-            .frontendCaps = mFrontendCaps[in_frontendId],
-    };
-
+    mFrontends[in_frontendId]->getFrontendInfo(_aidl_return);
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -313,6 +178,55 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus Tuner::setLna(bool /* in_bEnable */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Tuner::setMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                    int32_t in_maxNumber) {
+    ALOGV("%s", __FUNCTION__);
+
+    // In the default implementation, every type only has one frontend.
+    if (in_maxNumber < 0 || in_maxNumber > 1) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+    mMaxUsableFrontends[in_frontendType] = in_maxNumber;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Tuner::getMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                    int32_t* _aidl_return) {
+    *_aidl_return = mMaxUsableFrontends[in_frontendType];
+    return ::ndk::ScopedAStatus::ok();
+}
+
+binder_status_t Tuner::dump(int fd, const char** args, uint32_t numArgs) {
+    ALOGV("%s", __FUNCTION__);
+    {
+        dprintf(fd, "Frontends:\n");
+        for (int i = 0; i < mFrontendSize; i++) {
+            mFrontends[i]->dump(fd, args, numArgs);
+        }
+    }
+    {
+        dprintf(fd, "Demuxs:\n");
+        map<int32_t, std::shared_ptr<Demux>>::iterator it;
+        for (it = mDemuxes.begin(); it != mDemuxes.end(); it++) {
+            it->second->dump(fd, args, numArgs);
+        }
+    }
+    {
+        dprintf(fd, "Lnbs:\n");
+        for (int i = 0; i < mLnbs.size(); i++) {
+            mLnbs[i]->dump(fd, args, numArgs);
+        }
+    }
+    return STATUS_OK;
+}
+
 void Tuner::setFrontendAsDemuxSource(int32_t frontendId, int32_t demuxId) {
     mFrontendToDemux[frontendId] = demuxId;
     if (mFrontends[frontendId] != nullptr && mFrontends[frontendId]->isLocked()) {
@@ -332,6 +246,10 @@
 }
 
 void Tuner::removeFrontend(int32_t frontendId) {
+    map<int32_t, int32_t>::iterator it = mFrontendToDemux.find(frontendId);
+    if (it != mFrontendToDemux.end()) {
+        mDemuxes.erase(it->second);
+    }
     mFrontendToDemux.erase(frontendId);
 }
 
diff --git a/tv/tuner/aidl/default/Tuner.h b/tv/tuner/aidl/default/Tuner.h
index 7af7ab8..ad73003 100644
--- a/tv/tuner/aidl/default/Tuner.h
+++ b/tv/tuner/aidl/default/Tuner.h
@@ -56,6 +56,13 @@
     ::ndk::ScopedAStatus openLnbByName(const std::string& in_lnbName,
                                        std::vector<int32_t>* out_lnbId,
                                        std::shared_ptr<ILnb>* _aidl_return) override;
+    ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
+    ::ndk::ScopedAStatus setMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                 int32_t in_maxNumber) override;
+    ::ndk::ScopedAStatus getMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                 int32_t* _aidl_return) override;
+
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
     std::shared_ptr<Frontend> getFrontendById(int32_t frontendId);
     void setFrontendAsDemuxSource(int32_t frontendId, int32_t demuxId);
@@ -68,8 +75,6 @@
   private:
     // Static mFrontends array to maintain local frontends information
     map<int32_t, std::shared_ptr<Frontend>> mFrontends;
-    map<int32_t, FrontendCapabilities> mFrontendCaps;
-    map<int32_t, vector<FrontendStatusType>> mFrontendStatusCaps;
     map<int32_t, int32_t> mFrontendToDemux;
     map<int32_t, std::shared_ptr<Demux>> mDemuxes;
     // To maintain how many Frontends we have
@@ -78,6 +83,7 @@
     // First used id will be 0.
     int32_t mLastUsedId = -1;
     vector<std::shared_ptr<Lnb>> mLnbs;
+    map<FrontendType, int32_t> mMaxUsableFrontends;
 };
 
 }  // namespace tuner
diff --git a/tv/tuner/aidl/vts/functional/FilterTests.cpp b/tv/tuner/aidl/vts/functional/FilterTests.cpp
index a5acdc1..53afef7 100644
--- a/tv/tuner/aidl/vts/functional/FilterTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FilterTests.cpp
@@ -17,6 +17,7 @@
 #include "FilterTests.h"
 
 #include <inttypes.h>
+#include <algorithm>
 
 #include <aidl/android/hardware/tv/tuner/DemuxFilterMonitorEventType.h>
 #include <aidlcommonsupport/NativeHandle.h>
@@ -31,23 +32,24 @@
     mPidFilterOutputCount++;
     mMsgCondition.signal();
 
-    // HACK: we need to cast the const away as DemuxFilterEvent contains a ScopedFileDescriptor
-    // that cannot be copied.
-    for (auto&& e : const_cast<std::vector<DemuxFilterEvent>&>(events)) {
-        auto it = mFilterEventPromises.find(e.getTag());
-        if (it != mFilterEventPromises.cend()) {
-            it->second.set_value(std::move(e));
-            mFilterEventPromises.erase(it);
+    for (auto it = mFilterCallbackVerifiers.begin(); it != mFilterCallbackVerifiers.end();) {
+        auto& [verifier, promise] = *it;
+        if (verifier(events)) {
+            promise.set_value();
+            it = mFilterCallbackVerifiers.erase(it);
+        } else {
+            ++it;
         }
-    }
+    };
 
     return ::ndk::ScopedAStatus::ok();
 }
 
-std::future<DemuxFilterEvent> FilterCallback::getNextFilterEventWithTag(DemuxFilterEvent::Tag tag) {
-    // Note: this currently only supports one future per DemuxFilterEvent::Tag.
-    mFilterEventPromises[tag] = std::promise<DemuxFilterEvent>();
-    return mFilterEventPromises[tag].get_future();
+std::future<void> FilterCallback::verifyFilterCallback(FilterCallbackVerifier&& verifier) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    mFilterCallbackVerifiers.emplace_back(std::move(verifier), std::move(promise));
+    return future;
 }
 
 void FilterCallback::testFilterDataOutput() {
diff --git a/tv/tuner/aidl/vts/functional/FilterTests.h b/tv/tuner/aidl/vts/functional/FilterTests.h
index 6258bac..f579441 100644
--- a/tv/tuner/aidl/vts/functional/FilterTests.h
+++ b/tv/tuner/aidl/vts/functional/FilterTests.h
@@ -60,9 +60,18 @@
 
 class FilterCallback : public BnFilterCallback {
   public:
+    /**
+     * A FilterCallbackVerifier is used to test and verify filter callbacks.
+     * The function should return true when a callback has been handled by this
+     * filter verifier. This will cause the associated future to be unblocked.
+     * If the function returns false, we continue to wait for future callbacks
+     * (the future remains blocked).
+     */
+    using FilterCallbackVerifier = std::function<bool(const std::vector<DemuxFilterEvent>&)>;
+
     virtual ::ndk::ScopedAStatus onFilterEvent(const vector<DemuxFilterEvent>& events) override;
 
-    std::future<DemuxFilterEvent> getNextFilterEventWithTag(DemuxFilterEvent::Tag tag);
+    std::future<void> verifyFilterCallback(FilterCallbackVerifier&& verifier);
 
     virtual ::ndk::ScopedAStatus onFilterStatus(const DemuxFilterStatus /*status*/) override {
         return ::ndk::ScopedAStatus::ok();
@@ -85,7 +94,7 @@
     int32_t mFilterId;
     std::shared_ptr<IFilter> mFilter;
 
-    std::unordered_map<DemuxFilterEvent::Tag, std::promise<DemuxFilterEvent>> mFilterEventPromises;
+    std::vector<std::pair<FilterCallbackVerifier, std::promise<void>>> mFilterCallbackVerifiers;
     native_handle_t* mAvSharedHandle = nullptr;
     uint64_t mAvSharedMemSize = -1;
 
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 6204803..a1f51df 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <aidl/android/hardware/tv/tuner/Result.h>
+
 #include "FrontendTests.h"
 
 ndk::ScopedAStatus FrontendCallback::onEvent(FrontendEventType frontendEventType) {
@@ -296,6 +298,13 @@
     return AssertionResult(status.isOk());
 }
 
+AssertionResult FrontendTests::removeOutputPid(int32_t removePid) {
+    ndk::ScopedAStatus status;
+    status = mFrontend->removeOutputPid(removePid);
+    return AssertionResult(status.isOk() || status.getServiceSpecificError() ==
+                                                    static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
 AssertionResult FrontendTests::unlinkCiCam(int32_t ciCamId) {
     ndk::ScopedAStatus status = mFrontend->unlinkCiCam(ciCamId);
     return AssertionResult(status.isOk());
@@ -398,6 +407,27 @@
                             expectStatuses[i].get<FrontendStatus::Tag::partialReceptionFlag>());
                 break;
             }
+            case FrontendStatusType::STREAM_ID_LIST: {
+                ASSERT_TRUE(std::equal(
+                        realStatuses[i].get<FrontendStatus::Tag::streamIdList>().begin(),
+                        realStatuses[i].get<FrontendStatus::Tag::streamIdList>().end(),
+                        expectStatuses[i].get<FrontendStatus::Tag::streamIdList>().begin()));
+                break;
+            }
+            case FrontendStatusType::DVBT_CELL_IDS: {
+                ASSERT_TRUE(std::equal(
+                        realStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().begin(),
+                        realStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().end(),
+                        expectStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().begin()));
+                break;
+            }
+            case FrontendStatusType::ATSC3_ALL_PLP_INFO: {
+                ASSERT_TRUE(std::equal(
+                        realStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().begin(),
+                        realStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().end(),
+                        expectStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().begin()));
+                break;
+            }
             default: {
                 continue;
             }
@@ -430,6 +460,7 @@
         getDvrTests()->startPlaybackInputThread(
                 mDvrConfig.playbackInputFile,
                 mDvrConfig.settings.get<DvrSettings::Tag::playback>());
+        getDvrTests()->startDvrPlayback();
     }
     mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
     return AssertionResult(true);
@@ -441,6 +472,7 @@
     status = mFrontend->stopTune();
     if (mIsSoftwareFe && testWithDemux) {
         getDvrTests()->stopPlaybackThread();
+        getDvrTests()->stopDvrPlayback();
         getDvrTests()->closeDvrPlayback();
     }
     return AssertionResult(status.isOk());
@@ -468,6 +500,13 @@
     feId = INVALID_ID;
 }
 
+AssertionResult FrontendTests::verifyHardwareInfo() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    std::string info;
+    ndk::ScopedAStatus status = mFrontend->getHardwareInfo(&info);
+    return AssertionResult(status.isOk() && !info.empty());
+}
+
 void FrontendTests::tuneTest(FrontendConfig frontendConf) {
     int32_t feId;
     getFrontendIdByType(frontendConf.type, feId);
@@ -476,6 +515,7 @@
     ASSERT_TRUE(setFrontendCallback());
     if (frontendConf.canConnectToCiCam) {
         ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
+        ASSERT_TRUE(removeOutputPid(frontendConf.removePid));
         ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
     }
     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
@@ -484,6 +524,53 @@
     ASSERT_TRUE(closeFrontend());
 }
 
+void FrontendTests::debugInfoTest(FrontendConfig frontendConf) {
+    int32_t feId;
+    getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(openFrontendById(feId));
+    ASSERT_TRUE(setFrontendCallback());
+    ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
+    ASSERT_TRUE(verifyHardwareInfo());
+    ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
+    ASSERT_TRUE(closeFrontend());
+}
+
+void FrontendTests::maxNumberOfFrontendsTest() {
+    ASSERT_TRUE(getFrontendIds());
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        int32_t defaultMax = -1;
+        ndk::ScopedAStatus status;
+        // Check default value
+        status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &defaultMax);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_TRUE(defaultMax > 0);
+        // Set to -1
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, -1);
+        ASSERT_TRUE(status.getServiceSpecificError() ==
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        // Set to defaultMax + 1
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, defaultMax + 1);
+        ASSERT_TRUE(status.getServiceSpecificError() ==
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        // Set to 0
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, 0);
+        ASSERT_TRUE(status.isOk());
+        // Check after set
+        int32_t currentMax = -1;
+        status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &currentMax);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_TRUE(currentMax == 0);
+        // Reset to default
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, defaultMax);
+        ASSERT_TRUE(status.isOk());
+        status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &currentMax);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_TRUE(defaultMax == currentMax);
+    }
+}
+
 void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
     int32_t feId;
     getFrontendIdByType(frontendConf.type, feId);
@@ -494,3 +581,47 @@
     ASSERT_TRUE(stopScanFrontend());
     ASSERT_TRUE(closeFrontend());
 }
+
+void FrontendTests::statusReadinessTest(FrontendConfig frontendConf) {
+    int32_t feId;
+    vector<FrontendStatusType> allTypes;
+    vector<FrontendStatusReadiness> readiness;
+    getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(openFrontendById(feId));
+    ASSERT_TRUE(setFrontendCallback());
+    if (frontendConf.canConnectToCiCam) {
+        ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
+        ASSERT_TRUE(removeOutputPid(frontendConf.removePid));
+        ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
+    }
+    ASSERT_TRUE(getFrontendInfo(feId));
+    ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
+
+    // TODO: find a better way to push all frontend status types
+    for (int32_t i = 0; i < static_cast<int32_t>(FrontendStatusType::ATSC3_ALL_PLP_INFO); i++) {
+        allTypes.push_back(static_cast<FrontendStatusType>(i));
+    }
+    ndk::ScopedAStatus status = mFrontend->getFrontendStatusReadiness(allTypes, &readiness);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(readiness.size() == allTypes.size());
+    for (int32_t i = 0; i < readiness.size(); i++) {
+        int32_t j = 0;
+        while (j < mFrontendInfo.statusCaps.size()) {
+            if (allTypes[i] == mFrontendInfo.statusCaps[j]) {
+                ASSERT_TRUE(readiness[i] == FrontendStatusReadiness::UNAVAILABLE ||
+                            readiness[i] == FrontendStatusReadiness::UNSTABLE ||
+                            readiness[i] == FrontendStatusReadiness::STABLE);
+                break;
+            }
+            j++;
+        }
+
+        if (j >= mFrontendInfo.statusCaps.size()) {
+            ASSERT_TRUE(readiness[i] == FrontendStatusReadiness::UNSUPPORTED);
+        }
+    }
+
+    ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
+    ASSERT_TRUE(closeFrontend());
+}
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.h b/tv/tuner/aidl/vts/functional/FrontendTests.h
index e5a9cd3..1746c8e 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.h
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.h
@@ -94,10 +94,15 @@
 
     AssertionResult linkCiCam(int32_t ciCamId);
     AssertionResult unlinkCiCam(int32_t ciCamId);
+    AssertionResult verifyHardwareInfo();
+    AssertionResult removeOutputPid(int32_t removePid);
 
     void getFrontendIdByType(FrontendType feType, int32_t& feId);
     void tuneTest(FrontendConfig frontendConf);
     void scanTest(FrontendConfig frontend, FrontendScanType type);
+    void debugInfoTest(FrontendConfig frontendConf);
+    void maxNumberOfFrontendsTest();
+    void statusReadinessTest(FrontendConfig frontendConf);
 
     void setDvrTests(DvrTests* dvrTests) { mExternalDvrTests = dvrTests; }
     void setDemux(std::shared_ptr<IDemux> demux) { getDvrTests()->setDemux(demux); }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 88890e4..c99da41 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -640,10 +640,51 @@
     testTimeFilter(timeFilterMap[timeFilter.timeFilterId]);
 }
 
-// TODO: move boilerplate into text fixture
-TEST_P(TunerFilterAidlTest, FilterTimeDelayHintTest) {
-    description("Test filter delay hint.");
+static bool isMediaFilter(const FilterConfig& filterConfig) {
+    switch (filterConfig.type.mainType) {
+        case DemuxFilterMainType::TS: {
+            // TS Audio and Video filters are media filters
+            auto tsFilterType =
+                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::tsFilterType>();
+            return (tsFilterType == DemuxTsFilterType::AUDIO ||
+                    tsFilterType == DemuxTsFilterType::VIDEO);
+        }
+        case DemuxFilterMainType::MMTP: {
+            // MMTP Audio and Video filters are media filters
+            auto mmtpFilterType =
+                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>();
+            return (mmtpFilterType == DemuxMmtpFilterType::AUDIO ||
+                    mmtpFilterType == DemuxMmtpFilterType::VIDEO);
+        }
+        default:
+            return false;
+    }
+}
 
+static int getDemuxFilterEventDataLength(const DemuxFilterEvent& event) {
+    switch (event.getTag()) {
+        case DemuxFilterEvent::Tag::section:
+            return event.get<DemuxFilterEvent::Tag::section>().dataLength;
+        case DemuxFilterEvent::Tag::media:
+            return event.get<DemuxFilterEvent::Tag::media>().dataLength;
+        case DemuxFilterEvent::Tag::pes:
+            return event.get<DemuxFilterEvent::Tag::pes>().dataLength;
+        case DemuxFilterEvent::Tag::download:
+            return event.get<DemuxFilterEvent::Tag::download>().dataLength;
+        case DemuxFilterEvent::Tag::ipPayload:
+            return event.get<DemuxFilterEvent::Tag::ipPayload>().dataLength;
+
+        case DemuxFilterEvent::Tag::tsRecord:
+        case DemuxFilterEvent::Tag::mmtpRecord:
+        case DemuxFilterEvent::Tag::temi:
+        case DemuxFilterEvent::Tag::monitorEvent:
+        case DemuxFilterEvent::Tag::startId:
+            return 0;
+    }
+}
+
+// TODO: move boilerplate into text fixture
+void TunerFilterAidlTest::testDelayHint(const FilterConfig& filterConf) {
     int32_t feId;
     int32_t demuxId;
     std::shared_ptr<IDemux> demux;
@@ -657,40 +698,95 @@
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
     mFilterTests.setDemux(demux);
 
-    const auto& filterConf = filterMap[live.ipFilterId];
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
-    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
-    ASSERT_TRUE(mFilterTests.configIpFilterCid(filterConf.ipCid, filterId));
 
+    bool mediaFilter = isMediaFilter(filterConf);
     auto filter = mFilterTests.getFilterById(filterId);
 
-    auto delayValue = std::chrono::milliseconds(5000);
-    FilterDelayHint delayHint;
-    delayHint.hintType = FilterDelayHintType::TIME_DELAY_IN_MS;
-    delayHint.hintValue = delayValue.count();
-
-    auto status = filter->setDelayHint(delayHint);
-    ASSERT_TRUE(status.isOk());
-
+    // startTime needs to be set before calling setDelayHint.
     auto startTime = std::chrono::steady_clock::now();
-    ASSERT_TRUE(mFilterTests.startFilter(filterId));
 
+    auto timeDelayInMs = std::chrono::milliseconds(filterConf.timeDelayInMs);
+    if (timeDelayInMs.count() > 0) {
+        FilterDelayHint delayHint;
+        delayHint.hintType = FilterDelayHintType::TIME_DELAY_IN_MS;
+        delayHint.hintValue = timeDelayInMs.count();
+
+        // setDelayHint should fail for media filters.
+        ASSERT_EQ(filter->setDelayHint(delayHint).isOk(), !mediaFilter);
+    }
+
+    int dataDelayInBytes = filterConf.dataDelayInBytes;
+    if (dataDelayInBytes > 0) {
+        FilterDelayHint delayHint;
+        delayHint.hintType = FilterDelayHintType::DATA_SIZE_DELAY_IN_BYTES;
+        delayHint.hintValue = dataDelayInBytes;
+
+        // setDelayHint should fail for media filters.
+        ASSERT_EQ(filter->setDelayHint(delayHint).isOk(), !mediaFilter);
+    }
+
+    // start and stop filter (and wait for first callback) in order to
+    // circumvent callback scheduler race conditions after adjusting filter
+    // delays.
     auto cb = mFilterTests.getFilterCallbacks().at(filterId);
-    auto future = cb->getNextFilterEventWithTag(DemuxFilterEvent::Tag::ipPayload);
+    auto future =
+            cb->verifyFilterCallback([](const std::vector<DemuxFilterEvent>&) { return true; });
+    mFilterTests.startFilter(filterId);
 
-    // block and wait for callback to be received.
-    ASSERT_EQ(future.wait_for(std::chrono::seconds(10)), std::future_status::ready);
-    auto duration = std::chrono::steady_clock::now() - startTime;
-    ASSERT_GE(duration, delayValue);
+    auto timeout = std::chrono::seconds(30);
+    ASSERT_EQ(future.wait_for(timeout), std::future_status::ready);
 
-    // cleanup
-    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    mFilterTests.stopFilter(filterId);
+
+    if (!mediaFilter) {
+        int callbackSize = 0;
+        future = cb->verifyFilterCallback(
+                [&callbackSize](const std::vector<DemuxFilterEvent>& events) {
+                    for (const auto& event : events) {
+                        callbackSize += getDemuxFilterEventDataLength(event);
+                    }
+                    return true;
+                });
+
+        // The configure stage can also produce events, so we should set the delay
+        // hint beforehand.
+        ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+
+        ASSERT_TRUE(mFilterTests.startFilter(filterId));
+
+        // block and wait for callback to be received.
+        ASSERT_EQ(future.wait_for(timeout), std::future_status::ready);
+        auto duration = std::chrono::steady_clock::now() - startTime;
+
+        bool delayHintTest = duration >= timeDelayInMs;
+        bool dataSizeTest = callbackSize >= dataDelayInBytes;
+
+        if (timeDelayInMs.count() > 0 && dataDelayInBytes > 0) {
+            ASSERT_TRUE(delayHintTest || dataSizeTest);
+        } else {
+            // if only one of time delay / data delay is configured, one of them
+            // holds true by default, so we want both assertions to be true.
+            ASSERT_TRUE(delayHintTest && dataSizeTest);
+        }
+
+        ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    }
+
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
     ASSERT_TRUE(mDemuxTests.closeDemux());
     ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
 
+TEST_P(TunerFilterAidlTest, FilterDelayHintTest) {
+    description("Test filter time delay hint.");
+
+    for (const auto& obj : filterMap) {
+        testDelayHint(obj.second);
+    }
+}
+
 TEST_P(TunerPlaybackAidlTest, PlaybackDataFlowWithTsSectionFilterTest) {
     description("Feed ts data from playback and configure Ts section filter to get output");
     if (!playback.support || playback.sectionFilterId.compare(emptyHardwareId) == 0) {
@@ -795,6 +891,30 @@
     mFrontendTests.tuneTest(frontendMap[live.frontendId]);
 }
 
+TEST_P(TunerFrontendAidlTest, getHardwareInfo) {
+    description("Test Frontend get hardware info");
+    if (!live.hasFrontendConnection) {
+        return;
+    }
+    mFrontendTests.debugInfoTest(frontendMap[live.frontendId]);
+}
+
+TEST_P(TunerFrontendAidlTest, maxNumberOfFrontends) {
+    description("Test Max Frontend number");
+    if (!live.hasFrontendConnection) {
+        return;
+    }
+    mFrontendTests.maxNumberOfFrontendsTest();
+}
+
+TEST_P(TunerFrontendAidlTest, statusReadinessTest) {
+    description("Test Max Frontend status readiness");
+    if (!live.hasFrontendConnection) {
+        return;
+    }
+    mFrontendTests.statusReadinessTest(frontendMap[live.frontendId]);
+}
+
 TEST_P(TunerBroadcastAidlTest, BroadcastDataFlowVideoFilterTest) {
     description("Test Video Filter functionality in Broadcast use case.");
     if (!live.hasFrontendConnection) {
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index 13c5a80..7f80d90 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -140,6 +140,7 @@
     void reconfigSingleFilterInDemuxTest(FilterConfig filterConf, FilterConfig filterReconf,
                                          FrontendConfig frontendConf);
     void testTimeFilter(TimeFilterConfig filterConf);
+    void testDelayHint(const FilterConfig& filterConf);
 
     DemuxFilterType getLinkageFilterType(int bit) {
         DemuxFilterType type;
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 7ccf31a..3009c4a 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -83,6 +83,7 @@
     FrontendType type;
     bool canConnectToCiCam;
     int32_t ciCamId;
+    int32_t removePid;
     FrontendSettings settings;
     vector<FrontendStatusType> tuneStatusTypes;
     vector<FrontendStatus> expectTuneStatuses;
@@ -96,6 +97,8 @@
     AvStreamType streamType;
     int32_t ipCid;
     int32_t monitorEventTypes;
+    int timeDelayInMs = 0;
+    int dataDelayInBytes = 0;
 
     bool operator<(const FilterConfig& /*c*/) const { return false; }
 };
@@ -302,7 +305,8 @@
                 // TODO: b/182519645 complete the tune status config
                 frontendMap[id].tuneStatusTypes = types;
                 frontendMap[id].expectTuneStatuses = statuses;
-                getCiCamInfo(feConfig, frontendMap[id].canConnectToCiCam, frontendMap[id].ciCamId);
+                getCiCamInfo(feConfig, frontendMap[id].canConnectToCiCam, frontendMap[id].ciCamId,
+                             frontendMap[id].removePid);
             }
         }
     }
@@ -336,6 +340,12 @@
                 if (filterConfig.hasMonitorEventTypes()) {
                     filterMap[id].monitorEventTypes = (int32_t)filterConfig.getMonitorEventTypes();
                 }
+                if (filterConfig.hasTimeDelayInMs()) {
+                    filterMap[id].timeDelayInMs = filterConfig.getTimeDelayInMs();
+                }
+                if (filterConfig.hasDataDelayInBytes()) {
+                    filterMap[id].dataDelayInBytes = filterConfig.getDataDelayInBytes();
+                }
                 if (filterConfig.hasAvFilterSettings_optional()) {
                     auto av = filterConfig.getFirstAvFilterSettings_optional();
                     if (av->hasAudioStreamType_optional()) {
@@ -946,6 +956,7 @@
         settings.isCheckCrc = section->getIsCheckCrc();
         settings.isRepeat = section->getIsRepeat();
         settings.isRaw = section->getIsRaw();
+        settings.bitWidthOfLengthField = section->getBitWidthOfLengthField();
         return settings;
     }
 
@@ -995,13 +1006,16 @@
         return recordSettings;
     }
 
-    static void getCiCamInfo(Frontend feConfig, bool& canConnectToCiCam, int32_t& ciCamId) {
+    static void getCiCamInfo(Frontend feConfig, bool& canConnectToCiCam, int32_t& ciCamId,
+                             int32_t& removePid) {
         if (!feConfig.hasConnectToCicamId()) {
             canConnectToCiCam = false;
             ciCamId = -1;
+            removePid = -1;
             return;
         }
         canConnectToCiCam = true;
         ciCamId = static_cast<int32_t>(feConfig.getConnectToCicamId());
+        removePid = static_cast<int32_t>(feConfig.getRemoveOutputPid());
     }
 };
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index 6c637a4..383d49f 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -256,6 +256,7 @@
     ctor public Filter();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.AvFilterSettings getAvFilterSettings_optional();
     method @Nullable public java.math.BigInteger getBufferSize();
+    method @Nullable public java.math.BigInteger getDataDelayInBytes();
     method @Nullable public String getId();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.IpFilterConfig getIpFilterConfig_optional();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum getMainType();
@@ -264,9 +265,11 @@
     method @Nullable public android.media.tuner.testing.configuration.V1_0.RecordFilterSettings getRecordFilterSettings_optional();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.SectionFilterSettings getSectionFilterSettings_optional();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum getSubType();
+    method @Nullable public java.math.BigInteger getTimeDelayInMs();
     method @Nullable public boolean getUseFMQ();
     method public void setAvFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AvFilterSettings);
     method public void setBufferSize(@Nullable java.math.BigInteger);
+    method public void setDataDelayInBytes(@Nullable java.math.BigInteger);
     method public void setId(@Nullable String);
     method public void setIpFilterConfig_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IpFilterConfig);
     method public void setMainType(@Nullable android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum);
@@ -275,6 +278,7 @@
     method public void setRecordFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.RecordFilterSettings);
     method public void setSectionFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.SectionFilterSettings);
     method public void setSubType(@Nullable android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum);
+    method public void setTimeDelayInMs(@Nullable java.math.BigInteger);
     method public void setUseFMQ(@Nullable boolean);
   }
 
@@ -313,6 +317,7 @@
     method @Nullable public java.math.BigInteger getFrequency();
     method @Nullable public String getId();
     method @Nullable public boolean getIsSoftwareFrontend();
+    method @Nullable public java.math.BigInteger getRemoveOutputPid();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
     method public void setConnectToCicamId(@Nullable java.math.BigInteger);
     method public void setDvbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings);
@@ -321,6 +326,7 @@
     method public void setFrequency(@Nullable java.math.BigInteger);
     method public void setId(@Nullable String);
     method public void setIsSoftwareFrontend(@Nullable boolean);
+    method public void setRemoveOutputPid(@Nullable java.math.BigInteger);
     method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
   }
 
@@ -473,9 +479,11 @@
 
   public class SectionFilterSettings {
     ctor public SectionFilterSettings();
+    method @Nullable public java.math.BigInteger getBitWidthOfLengthField();
     method @Nullable public boolean getIsCheckCrc();
     method @Nullable public boolean getIsRaw();
     method @Nullable public boolean getIsRepeat();
+    method public void setBitWidthOfLengthField(@Nullable java.math.BigInteger);
     method public void setIsCheckCrc(@Nullable boolean);
     method public void setIsRaw(@Nullable boolean);
     method public void setIsRepeat(@Nullable boolean);
diff --git a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
index 8a6229e..fefe86e 100644
--- a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
@@ -42,6 +42,8 @@
                 "softwareFeInputPath": used as the source of the software frontend.
                 "connectToCicamId": if the device supports frontend connecting to cicam, the target
                     cicam id needs to be configured here. Supported in Tuner 1.1 or higher.
+                "removeOutputPid": the unnecessary PID will be filtered out from frontend
+                    output. Supported in Tuner 2.0 or higher.
                 "frequency": the frequency used to configure tune and scan.
                 "endFrequency": the end frequency of scan. Supported in Tuner 1.1 or higher.
 
@@ -53,11 +55,13 @@
         -->
         <frontends>
             <frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
-                      connectToCicamId="0" frequency="578000000" endFrequency="800000000">
+                      connectToCicamId="0" removeOutputPid="10" frequency="578000000"
+                      endFrequency="800000000">
                 <dvbtFrontendSettings bandwidth="8" transmissionMode="128" isHighPriority="1"/>
             </frontend>
             <frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
-                      connectToCicamId="0" frequency="578000000" endFrequency="800000000">
+                      connectToCicamId="0" removeOutputPid="10" frequency="578000000"
+                      endFrequency="800000000">
             </frontend>
         </frontends>
         <!-- Filter section:
@@ -101,7 +105,7 @@
                     bufferSize="16777216" pid="257" useFMQ="false">
                 <recordFilterSettings tsIndexMask="1" scIndexType="NONE"/>
             </filter>
-            <filter id="FILTER_IP_IP_0" mainType="IP" subType="IP" bufferSize="16777216" useFMQ="false">
+            <filter id="FILTER_IP_IP_0" mainType="IP" subType="IP" bufferSize="16777216" useFMQ="false" timeDelayInMs="5000">
                 <ipFilterConfig ipCid="1">
                     <srcIpAddress isIpV4="true" ip="192 168 1 1"/>
                     <destIpAddress isIpV4="true" ip="192 168 1 1"/>
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index fc2827f..59abd9a 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -94,6 +94,8 @@
                     "connectToCicamId": if the device supports frontend connecting to cicam, the
                         target cicam id needs to be configured here. Supported in Tuner 1.1 or
                         higher.
+                    "removeOutputPid": the unnecessary PID will be filtered out from frontend
+                        output. Supported in Tuner 2.0 or higher.
                     "frequency": the frequency used to configure tune and scan.
                     "endFrequency": the end frequency of scan. Supported in Tuner 1.1 or higher.
 
@@ -125,6 +127,7 @@
         <xs:attribute name="isSoftwareFrontend" type="xs:boolean" use="required"/>
         <xs:attribute name="frequency" type="xs:nonNegativeInteger" use="required"/>
         <xs:attribute name="connectToCicamId" type="xs:nonNegativeInteger" use="optional"/>
+        <xs:attribute name="removeOutputPid" type="xs:nonNegativeInteger" use="optional"/>
         <xs:attribute name="endFrequency" type="xs:nonNegativeInteger" use="optional"/>
     </xs:complexType>
 
@@ -226,6 +229,7 @@
         <xs:attribute name="isCheckCrc" type="xs:boolean" use="required"/>
         <xs:attribute name="isRepeat" type="xs:boolean" use="required"/>
         <xs:attribute name="isRaw" type="xs:boolean" use="required"/>
+        <xs:attribute name="bitWidthOfLengthField" type="xs:nonNegativeInteger" use="required"/>
     </xs:complexType>
     <xs:complexType name="recordFilterSettings">
         <xs:attribute name="tsIndexMask" type="tsIndexMask" use="required"/>
@@ -243,6 +247,10 @@
                     "bufferSize": the buffer size of the filter in hex.
                     "pid": the pid that would be used to configure the filter.
                     "useFMQ": if the filter uses FMQ.
+                    "timeDelayInMs": the filter's time delay hint. 0 by default.  Must not be
+                        longer than 30 seconds.
+                    "dataDelayInBytes": the filter's data delay hint. 0 by default. Configured data
+                        size must be received within 30 seconds.
 
                 Each filter element also contains at most one type-related "filterSettings".
                     - The settings type should match the filter "subType" attribute.
@@ -274,6 +282,8 @@
         <xs:attribute name="pid" type="xs:nonNegativeInteger" use="optional"/>
         <xs:attribute name="useFMQ" type="xs:boolean" use="required"/>
         <xs:attribute name="monitorEventTypes" type="monitoEvents" use="optional"/>
+        <xs:attribute name="timeDelayInMs" type="xs:nonNegativeInteger" use="optional"/>
+        <xs:attribute name="dataDelayInBytes" type="xs:nonNegativeInteger" use="optional"/>
     </xs:complexType>
 
     <!-- DVR SESSION -->
diff --git a/usb/1.0/default/Android.bp b/usb/1.0/default/Android.bp
index 5f56fe0..4bed2c7 100644
--- a/usb/1.0/default/Android.bp
+++ b/usb/1.0/default/Android.bp
@@ -21,11 +21,21 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+filegroup {
+    name: "android.hardware.usb@1.0-service.xml",
+    srcs: ["android.hardware.usb@1.0-service.xml"],
+}
+
+filegroup {
+    name: "android.hardware.usb@1.0-service.rc",
+    srcs: ["android.hardware.usb@1.0-service.rc"],
+}
+
 cc_binary {
     name: "android.hardware.usb@1.0-service",
     defaults: ["hidl_defaults"],
-    init_rc: ["android.hardware.usb@1.0-service.rc"],
-    vintf_fragments: ["android.hardware.usb@1.0-service.xml"],
+    init_rc: [":android.hardware.usb@1.0-service.rc"],
+    vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
     relative_install_path: "hw",
     vendor: true,
     srcs: [
diff --git a/usb/1.0/default/apex/Android.bp b/usb/1.0/default/apex/Android.bp
new file mode 100644
index 0000000..ee50fdf
--- /dev/null
+++ b/usb/1.0/default/apex/Android.bp
@@ -0,0 +1,59 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+apex_key {
+    name: "com.android.hardware.usb.key",
+    public_key: "com.android.hardware.usb.avbpubkey",
+    private_key: "com.android.hardware.usb.pem",
+}
+
+android_app_certificate {
+    name: "com.android.hardware.usb.certificate",
+    certificate: "com.android.hardware.usb",
+}
+
+genrule {
+    name: "com.android.hardware.usb.rc-gen",
+    srcs: [":android.hardware.usb@1.0-service.rc"],
+    out: ["com.android.hardware.usb.rc"],
+    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
+}
+
+prebuilt_etc {
+    name: "com.android.hardware.usb.rc",
+    src: ":com.android.hardware.usb.rc-gen",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.usb",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.usb.key",
+    certificate: ":com.android.hardware.usb.certificate",
+    updatable: false,
+    soc_specific: true,
+    use_vndk_as_stable: true,
+    binaries: ["android.hardware.usb@1.0-service"],
+    prebuilts: [
+        "com.android.hardware.usb.rc",
+        "android.hardware.usb.accessory.prebuilt.xml",
+        "android.hardware.usb.host.prebuilt.xml",
+    ],
+    vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
+}
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.avbpubkey b/usb/1.0/default/apex/com.android.hardware.usb.avbpubkey
new file mode 100644
index 0000000..0302d63
--- /dev/null
+++ b/usb/1.0/default/apex/com.android.hardware.usb.avbpubkey
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pem b/usb/1.0/default/apex/com.android.hardware.usb.pem
new file mode 100644
index 0000000..e1e57da
--- /dev/null
+++ b/usb/1.0/default/apex/com.android.hardware.usb.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAwdimmHgIZHrep3H3YfVaNYEAGg45LUEPIiwHV6aIC9V7zjBS
+SftD30Z21jGyk7hmtas6WMI2vRBDNGrZWDgPeiEQoxXQinuU4Ug5S5X2F8LpWs0y
+ZeNFwQkqZwqGdQlkmy8upfb6T7rDxqRv+C0AtGP1r4r36+Xh5ld5stVaMK0UNhZt
+VW0nQAxyeJL3tm0zfiEA9Zu7FF2IyHm+bo9+eJ7WXfjiJfkclLgqlX3ec2cvVqAf
+NHisj18PEd/qtC64b+FnkgbsdHzWbo8HW5x4STkGXNnH+O3dvkWBX60MOfywfZFw
++yaz5mt7K+ft/V4UA7zKiAEFM+J1lND9/UMJnd0XMYYtcRQF8lmu4dlcjfbbAm0k
+VgoUEsizIeMPLrMj837uVloKKzIXmPsVsfMarP/MrX6TJfzdUhdm01pVO1g0wtHJ
+J3eYQsEnOI7RjL+uZDQvPWAnr71pvacn66PAJC1UPulEEla5lhd30RDItbJkngXp
+3UggW32ZOQt3Oc8P0eo9SCnBlHtCVr8wfxAbxCoPR9qIdX3azkQRqcKqGbBbPnkc
+hSCzeIofUkYGibfbZg4k1yY82xEqZuN7J1zycoGP4wyhXeRLTRWxfPR5dxxmQZaS
+67A1LWrYvAzF8Rd44VMRlI/Qk6zuBsL01j2dfBqit+le+viQmTYb3BpV+1kCAwEA
+AQKCAgAmSfX2LddyiXaLWo6DsePkp5tuihqvHqevl0TIAmPi+oMe4hqO9GueoZt9
+iYl9djILdkvrFkmbpKexpd1SeJhOBlPz8q4jfG+W5B41GOToIp7XSarHx1GS5I2U
+ltaiLX3KzVIIhDVDJF/hT7+yJKl7+DaiOu/nj5vEVMj8EvpinP1eBaYI9quHEi5W
+NKlrRjyikEBRQzZ7ulH3T1zXF87iYnVzUGLTH1aO5aW7q4YSA3KtSKmBQsjK9PrU
+DAefGY9iwgIkLOvtwm7UnbnVVZ3I0NO56WZ/e/SNzcrVLCg7F/eAhgbsBOQKAnbs
+4D35CuknJ9ZVcOYnLncNMw7IRMKULKYLAuLLN1X33y22qaVxYA42rq13mZrijlua
+CMQ2Ur+GNcq8OI3mRDO38yKeJ5b4885LQdlrXXyoGnSjlkU5n8U9Jw6q2rZGiWlk
+4Q71g+KUl0rtXSnFSIJLNTK6Cd3ETStxswLvvCvfLTrRQcO8f2SdVxblmsc9eCDs
+JUxz6Sahkpb9hsY8fozu6laXC/5Ezy0TinRgGjQM/DQqbXtFXgse56mDxzSho5oh
+Spy3X7Q/v4VUtrSKsEZEIEVWCpplzVULpHenCDbU58rHyEcS7ew+kwlfHC73iEhX
+HPujSIKvStO7yCEeY6IdhON8iVX34uvQeAgEe4+rehQHLZUg0QKCAQEA9AS3imKF
+yEt0yNRLcdXSqYkak+OM2kfhBBcLndCT7Terr6yluv/SkPGYjUbmr2XiygMv8IwO
+8f+KbWsNwYCaB22HVYVGL0oUYAlCvWhnia3Iwn6ZZuXuJv5mmfqt/GMlaIfohNLy
+zI2OlcpcAuRfNlenjNyd+inxwdXL28Z86kbabnUlijgqpu4KFOYOlxbTRv93IlfM
+Ico1pZkLS1glDMFLetF+IWq4zqpXrdgNUk1KX3sofOCfZQnlWFrrHbXJPCgPAtlv
+xP4dmJQgtWkWwxUlelfz34LcCUVX2aTlgKjuvgvyCt2ZPWixXbDtjsCBTn3xBhoY
+kDp2OyMC+d543QKCAQEAy11GpYOQvTMKbV07EmN9jTRYg7gRrxsT3Kd4Xy+NpIY8
+v6J5Keeppk9t6WBrJi2cQU/EoHcd3fRkWMnWMNorZDiCu34VG5bfa4pTqnSLdLC4
+/e5UHdHqCy9deAwhlHYWbAx0KnxXWGxkq05dXvQsVuOtAs528NcujnLpwDONQt5P
+e3RIZmOOjr+7rqGp3vA9SuNOINOQpeKxQT6GRGw4mlYofdwOPaE1wCsO8vQCNmCJ
+DEfdm+hWjTLAV2IBCfi5BKRsIAXrABPzkzDeLGDmaQkJTDpK8UQcrFnqItGeo+yl
+fDjxA0zAPWYGcyXcXbtvayX+zCk/SKwQABqUtaumrQKCAQEA0mdizwsGqd8OMsCC
+0QP64j4a0Zvqbqh9yCYK2Sfo9SkEe7SVLnm5WUtIK8EP1fs3ItK+ul454MZj2Nbv
+BINbzL3PbJk/HDV2/hveFS154UgcjD/XC9eEktDXLTvuW2ot7kUJ48V0n5YLdPMI
+hWHfCx9nlFkCSptyHp23aqhqOyOe4pFWLikh9c/Yl46K1BJVWKmcUtt7Y0NVIJWn
+HG9Dew0MhTkv1aaM9X4Bnh9l1SpZz5yFG7AfIGL5A0dZ5cNCYgF0eBN+gVBPuqk2
+ztVvUATizOwblwThr4jAKCU70sVXHj10lZPftwiXrt6I54brt/92HLnRpkMSgQk+
+Xq9KbQKCAQAXxPM47UPBmXGijr8UyyQlmPSvkJggi12q8LgVCA3aKQZ4r5jR2Q3v
+LmF+YZKkh7g3ugcValbHVoVUC2NJmnZv5FsDZx04eE3s1+Inji+ul+lHZM/YHGzq
+mcKnAWP7YkIEpv/850OeRi0OCL7JFmkITtwt88vbIouCgtPnbx8XrbxEhbbgoMpM
+zQQ2yRZ9xD6lviOnmpLRkMl/ArvWy39iKqfY7huMAIezylSY+QQ5LtdV5CB21JUp
+M8FfdUkBzVxyunUY2Rg6jhpuHcwaC8lihXfcvQN9Z6SiUHAZWb7dEg/VkSI6bIIb
+qw0d8FLtcbb4IxzA6CFJcTL9kB3JjiKRAoIBAQC15t3mQHb9iCM4P4U9fpR4syvN
+46vDMhtj3vejerzOro2R7UUCJDvT59DrCQvtKO/ZCyhdTyuyResu6r1vbwq3KWiB
+i0RIeW87cKgJRr6w+KivB+a805WfI9zNRz778b7ajEpBkOs4vRPWu6S1306tdvgM
+Dhj7GT9UFh/k7pNuoSbiuaPUqgZRP55nzgj/FoIN985wnxo/ugckSqZ1bFGFXhYt
+zfIdFvPkf1BlLCnLTE8yESsJ3P37Gfj2XRv9h2I2/8qAGZniKtbVWHlu+5LDJf6V
+x9VpDAH2ZQAqRC3za3gfTjMsglYi7mUDeMYlB4osURNt7jDtElEmsto7AAkI
+-----END RSA PRIVATE KEY-----
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pk8 b/usb/1.0/default/apex/com.android.hardware.usb.pk8
new file mode 100644
index 0000000..9f3f39b
--- /dev/null
+++ b/usb/1.0/default/apex/com.android.hardware.usb.pk8
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.x509.pem b/usb/1.0/default/apex/com.android.hardware.usb.x509.pem
new file mode 100644
index 0000000..210c30d
--- /dev/null
+++ b/usb/1.0/default/apex/com.android.hardware.usb.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF1TCCA70CFFEdsyLGoTRk+VIzqb6aDl1tXeuZMA0GCSqGSIb3DQEBCwUAMIGl
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEhMB8GA1UEAwwYY29t
+LmFuZHJvaWQuaGFyZHdhcmUudXNiMCAXDTIxMTExNzIyMzAwM1oYDzQ3NTkxMDE0
+MjIzMDAzWjCBpTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAU
+BgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNVBAsM
+B0FuZHJvaWQxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20xITAf
+BgNVBAMMGGNvbS5hbmRyb2lkLmhhcmR3YXJlLnVzYjCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBAM2E0E9ubNU/or7r9UIcFrC4l7CeM0HwtwSjTUKV1Z9K
+7rPFoUPE3cQ+cResnWQay8IGnomLYptAIMe8sLCC83LwU1ucTihxX87qq2W3V14w
+U4AkqDzNvYqKiD3yz9WofKxcu7ut8+1O4Pvp11X8UXuy5kNzf8WGpGB04k6U6KtA
+q8+U8+4h9h1Uvhaa0AeG9Yp22LzRLTb3J+eCoGHJnjoXYsd9T/gvedyXKkuf0lWB
+b3Aor3/CQrpdCW2/iJbuASdBdfilpQShaagxy2wmQsYxnT8ZWf+tIDYjg3xqqVPl
+GChFwCQBdaTuLI/k9gbaXkSxuzRkp5wc/ELhYbkhIS25yefAF2C6num++AHQBh1+
+qO0fHztsK80c5cVoDPWu17/nP7y3QloRyLFUrL3hVW1RQaFwE2Hmv4H0UwVAsleU
+ZIsz2ifTjiSl/tnkFTx0I6BVk7T87QhO3WXN4v6VDYZKeD4gQYS0NfwplahejrFw
+s3EcwKgt6f0KlIpzoEQBmNQBXxsRgL31GWCwCszb7+VrTMzgUpO41R3PyewbeaZk
+S/SHyEOwyf0WIvnZhZ/5CNd9qirClu6jS8kdLvwC2qA25VqSPw126EX1e2xUqm02
+C/6c7JDVocuQhvsJOnnpZt68Iwgw9g/xLCLA9RszH9ccRctZqRnzHB1AjTrBOq0P
+AgMBAAEwDQYJKoZIhvcNAQELBQADggIBAELbSot2Io/JZIYLTxgeReI4lk1KUzf8
+fGlDNlRm+goxOHXWQgvXgiftwM9IOB+H+EtNHAA9Q6ojAmfRe6rZC4p0ZxWOamtR
+V+pQj0c6Zvx8HJPMQdyoHx538iNXM093s2wnf+QuACb3BnvkK7uuLGAlIzWdImtL
+DKKFN05nppViY04tGP5HgT57b7YGwdkEp6euCJcyWIKjlyEH/bwTWM8ws/Px6uhw
++5W2K7KrBsdRKPBF7qwXoS8Ak8pS5de9Xd7mbGBLaUtjsZ0pJbq0aFpuT0GbLWUm
+wiD5Ljq3ea/2GZxbHGiXQ2yNjFSd/jpuxDnnm99t7+HGw1v5Jld+hUVqXXfVNhWe
+hUKIv5TOk1nttNdsaLyDtxyt22JX7NnoPM0MqrkYwA8Xqrbv0VC8D/CVjiBC9Tce
+crhpCISNfQSkdEn/c+q/naFUvQy8oYqXkg1TjeGlcxwJOpGliYbbYT6VAwuI/ssI
+yX3Fkr8f5KhfN2aFnOpidknmLp9EyL2j5bxAtSD9xAHtczMn10uCUdLELjRB1L4f
+1qY+EjpIgK0NIFuEt9K5uZXirXq3K3eixKeJFNji3x/X8NgDALSdnT8JIlSg4DMg
+iWupLrQ9CSHMlgh5P43ALamiRIHQNqEwgj8OIGzsvQTSLbRjbPWYcDZa+Q1hosiA
+Fv7vjDI6oySM
+-----END CERTIFICATE-----
diff --git a/usb/1.0/default/apex/file_contexts b/usb/1.0/default/apex/file_contexts
new file mode 100644
index 0000000..bc84ac4
--- /dev/null
+++ b/usb/1.0/default/apex/file_contexts
@@ -0,0 +1,5 @@
+(/.*)?                                         u:object_r:vendor_file:s0
+# Permission XMLs
+/etc/permissions(/.*)?                         u:object_r:vendor_configs_file:s0
+# binary
+/bin/hw/android\.hardware\.usb@1\.0-service    u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/1.0/default/apex/manifest.json b/usb/1.0/default/apex/manifest.json
new file mode 100644
index 0000000..6a1095f
--- /dev/null
+++ b/usb/1.0/default/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.hardware.usb",
+  "version": 1
+}
diff --git a/usb/aidl/OWNERS b/usb/aidl/OWNERS
new file mode 100644
index 0000000..fefae56
--- /dev/null
+++ b/usb/aidl/OWNERS
@@ -0,0 +1 @@
+badhri@google.com
diff --git a/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp
index 8402853..4c40bf8 100644
--- a/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp
+++ b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp
@@ -178,6 +178,9 @@
 
 Status addAdb(MonitorFfs* monitorFfs, int* functionCount) {
     ALOGI("setCurrentUsbFunctions Adb");
+    if (!WriteStringToFile("1", DESC_USE_PATH))
+        return Status::ERROR;
+
     if (!monitorFfs->addInotifyFd("/dev/usb-ffs/adb/")) return Status::ERROR;
 
     if (linkFunction("ffs.adb", (*functionCount)++)) return Status::ERROR;
diff --git a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
index 8986556..fa50821 100644
--- a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
+++ b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
@@ -190,6 +190,9 @@
 
 Status addAdb(MonitorFfs* monitorFfs, int* functionCount) {
     ALOGI("setCurrentUsbFunctions Adb");
+    if (!WriteStringToFile("1", DESC_USE_PATH))
+        return Status::ERROR;
+
     if (!monitorFfs->addInotifyFd("/dev/usb-ffs/adb/")) return Status::ERROR;
 
     if (linkFunction("ffs.adb", (*functionCount)++)) return Status::ERROR;
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 99fd094..2cc1e6a 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -16,7 +16,7 @@
     stability: "vintf",
     backend: {
         java: {
-            sdk_version: "module_current",
+            sdk_version: "module_Tiramisu",
             enabled: false,
         },
         ndk: {
@@ -27,7 +27,7 @@
                 "//apex_available:platform",
                 "com.android.uwb",
             ],
-            min_sdk_version: "current",
+            min_sdk_version: "Tiramisu",
         },
         rust: {
             enabled: true,
@@ -35,7 +35,7 @@
                 "//apex_available:platform",
                 "com.android.uwb",
             ],
-            min_sdk_version: "current",
+            min_sdk_version: "Tiramisu",
         },
     },
 }
@@ -47,7 +47,7 @@
     stability: "vintf",
     backend: {
         java: {
-            sdk_version: "module_current",
+            sdk_version: "module_Tiramisu",
             enabled: true,
             apex_available: [
                 "com.android.uwb",
@@ -58,7 +58,7 @@
                 "//apex_available:platform",
                 "com.android.uwb",
             ],
-            min_sdk_version: "current",
+            min_sdk_version: "Tiramisu",
         },
     },
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl
index 774133e..7e3be56 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl
@@ -35,4 +35,5 @@
 @Backing(type="long") @VintfStability
 enum UwbAndroidCapabilities {
   POWER_STATS_QUERY = 1,
+  ANTENNAE_INTERLEAVING = 2,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index 4e3d4a2..cd2e122 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -35,4 +35,5 @@
 @Backing(type="byte") @VintfStability
 enum UwbVendorGidAndroidOids {
   ANDROID_GET_POWER_STATS = 0,
+  ANDROID_SET_COUNTRY_CODE = 1,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
index 37b7efb..f449c60 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
@@ -38,4 +38,7 @@
   CCC_UWB_CONFIG_ID = 164,
   CCC_PULSESHAPE_COMBO = 165,
   CCC_URSK_TTL = 166,
+  NB_OF_RANGE_MEASUREMENTS = 227,
+  NB_OF_AZIMUTH_MEASUREMENTS = 228,
+  NB_OF_ELEVATION_MEASUREMENTS = 229,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb/current/android/hardware/uwb/IUwbChip.aidl b/uwb/aidl/aidl_api/android.hardware.uwb/current/android/hardware/uwb/IUwbChip.aidl
index c4cb47b..c7708f1 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb/current/android/hardware/uwb/IUwbChip.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb/current/android/hardware/uwb/IUwbChip.aidl
@@ -40,6 +40,7 @@
   void open(in android.hardware.uwb.IUwbClientCallback clientCallback);
   void close();
   void coreInit();
+  void sessionInit(int sessionId);
   int getSupportedAndroidUciVersion();
   long getSupportedAndroidCapabilities();
   int sendUciMessage(in byte[] data);
diff --git a/uwb/aidl/android/hardware/uwb/IUwbChip.aidl b/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
index 0c98611..f2bb0f1 100644
--- a/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
+++ b/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
@@ -50,6 +50,14 @@
     void coreInit();
 
     /**
+     * Perform any necessary UWB session initializations.
+     * This must be invoked by the framework at the beginging of every new ranging session.
+     *
+     * @param sessionId Session identifier as defined in the UCI specification.
+     */
+    void sessionInit(int sessionId);
+
+    /**
      * Supported version of vendor UCI specification.
      *
      * @return Returns the version of the "android.hardware.uwb.fira_android" types-only
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl
index 3486d5a..0af99e0 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbAndroidCapabilities.aidl
@@ -26,6 +26,6 @@
 @VintfStability
 @Backing(type="long")
 enum UwbAndroidCapabilities {
-    /** TODO: Change the name if necessary when the corresponding vendor commands are added */
     POWER_STATS_QUERY = 0x1,
+    ANTENNAE_INTERLEAVING = 0x2,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index de4a2d8..1dfcd6f 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -27,4 +27,7 @@
     // Supported only if the value returned by getSupportedAndroidCapabilities()
     // has the bit of UwbAndroidCapabilities.POWER_STATS_QUERY set to 1.
     ANDROID_GET_POWER_STATS = 0x0,
+    // Used to set the current regulatory country code (determined usinag
+    // SIM or hardcoded by OEM).
+    ANDROID_SET_COUNTRY_CODE = 0x1,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
index 850e2da..f5e02c0 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
@@ -29,9 +29,29 @@
 enum UwbVendorSessionSetAppConfigCmdParams {
     /** CCC params for ranging start */
 
-    /** Added in vendor version 0. */
+    /**
+     * Added in vendor version 0.
+     * Range 0xA0 - 0xDF reserved for CCC use.
+     */
     CCC_RANGING_PROTOCOL_VER = 0xA3,
     CCC_UWB_CONFIG_ID = 0xA4,
     CCC_PULSESHAPE_COMBO = 0xA5,
     CCC_URSK_TTL = 0xA6,
+
+    /**
+     * Range 0xE3 - 0xFF is reserved for proprietary use in the FIRA spec.
+     * In Android, this range is reserved by the Android platform for Android-specific
+     * app config cmd params.
+     * Vendors must not define additional app config cmd params in this range.
+     */
+
+    /**
+     * Added in vendor version 0.
+     * Interleaving ratio if AOA_RESULT_REQ is set to 0xF0.
+     * Supported only if the value returned by getSupportedAndroidCapabilities()
+     * has the bit of UwbAndroidCapabilities.ANTENNAE_INTERLEAVING set to 1.
+     */
+    NB_OF_RANGE_MEASUREMENTS = 0xE3,
+    NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
+    NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
 }
diff --git a/uwb/aidl/default/uwb_chip.cpp b/uwb/aidl/default/uwb_chip.cpp
index 10dbdb6..a5a3f4a 100644
--- a/uwb/aidl/default/uwb_chip.cpp
+++ b/uwb/aidl/default/uwb_chip.cpp
@@ -51,6 +51,10 @@
     return ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus UwbChip::sessionInit(int /* sessionId */) {
+    return ndk::ScopedAStatus::ok();
+}
+
 ::ndk::ScopedAStatus UwbChip::getSupportedAndroidUciVersion(int32_t* version) {
     *version = kAndroidUciVersion;
     return ndk::ScopedAStatus::ok();
diff --git a/uwb/aidl/default/uwb_chip.h b/uwb/aidl/default/uwb_chip.h
index ca97120..46cecd4 100644
--- a/uwb/aidl/default/uwb_chip.h
+++ b/uwb/aidl/default/uwb_chip.h
@@ -37,6 +37,7 @@
     ::ndk::ScopedAStatus open(const std::shared_ptr<IUwbClientCallback>& clientCallback) override;
     ::ndk::ScopedAStatus close() override;
     ::ndk::ScopedAStatus coreInit() override;
+    ::ndk::ScopedAStatus sessionInit(int sesionId) override;
     ::ndk::ScopedAStatus getSupportedAndroidUciVersion(int32_t* version) override;
     ::ndk::ScopedAStatus getSupportedAndroidCapabilities(int64_t* capabilities) override;
     ::ndk::ScopedAStatus sendUciMessage(const std::vector<uint8_t>& data,
diff --git a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
index 3820c0f..1da4432 100644
--- a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
+++ b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
@@ -166,6 +166,11 @@
     EXPECT_TRUE(iuwb_chip->coreInit().isOk());
 }
 
+TEST_P(UwbAidl, ChipSessionInit) {
+    const auto iuwb_chip = getAnyChipAndOpen();
+    EXPECT_TRUE(iuwb_chip->sessionInit(0).isOk());
+}
+
 TEST_P(UwbAidl, ChipGetSupportedAndroidUciVersion) {
     const auto iuwb_chip = getAnyChipAndOpen();
     EXPECT_TRUE(iuwb_chip->coreInit().isOk());
diff --git a/vibrator/aidl/default/main.cpp b/vibrator/aidl/default/main.cpp
index bd834d2..feba2c7 100644
--- a/vibrator/aidl/default/main.cpp
+++ b/vibrator/aidl/default/main.cpp
@@ -31,14 +31,14 @@
     auto vib = ndk::SharedRefBase::make<Vibrator>();
     const std::string vibName = std::string() + Vibrator::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(vib->asBinder().get(), vibName.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     // make the vibrator manager service with a different vibrator
     auto managedVib = ndk::SharedRefBase::make<Vibrator>();
     auto vibManager = ndk::SharedRefBase::make<VibratorManager>(std::move(managedVib));
     const std::string vibManagerName = std::string() + VibratorManager::descriptor + "/default";
     status = AServiceManager_addService(vibManager->asBinder().get(), vibManagerName.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/weaver/aidl/default/Weaver.cpp b/weaver/aidl/default/Weaver.cpp
index 56d9c4d..6b77924 100644
--- a/weaver/aidl/default/Weaver.cpp
+++ b/weaver/aidl/default/Weaver.cpp
@@ -15,30 +15,52 @@
  */
 
 #include "Weaver.h"
+#include <array>
 
 namespace aidl {
 namespace android {
 namespace hardware {
 namespace weaver {
 
+struct Slotinfo {
+    int slot_id;
+    std::vector<uint8_t> key;
+    std::vector<uint8_t> value;
+};
+
+std::array<struct Slotinfo, 16> slot_array;
 // Methods from ::android::hardware::weaver::IWeaver follow.
 
 ::ndk::ScopedAStatus Weaver::getConfig(WeaverConfig* out_config) {
-    (void)out_config;
+    *out_config = {16, 16, 16};
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus Weaver::read(int32_t in_slotId, const std::vector<uint8_t>& in_key, WeaverReadResponse* out_response) {
-    (void)in_slotId;
-    (void)in_key;
-    (void)out_response;
+
+    if (in_slotId > 15 || in_key.size() > 16) {
+        *out_response = {0, {}};
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_FAILED));
+    }
+
+    if (slot_array[in_slotId].key != in_key) {
+        *out_response = {0, {}};
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_INCORRECT_KEY));
+    }
+
+    *out_response = {0, slot_array[in_slotId].value};
+
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus Weaver::write(int32_t in_slotId, const std::vector<uint8_t>& in_key, const std::vector<uint8_t>& in_value) {
-    (void)in_slotId;
-    (void)in_key;
-    (void)in_value;
+
+    if (in_slotId > 15 || in_key.size() > 16 || in_value.size() > 16)
+        return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
+
+    slot_array[in_slotId].key = in_key;
+    slot_array[in_slotId].value = in_value;
+
     return ::ndk::ScopedAStatus::ok();
 }
 
diff --git a/weaver/aidl/default/service.cpp b/weaver/aidl/default/service.cpp
index 1495bc9..2099ffd 100644
--- a/weaver/aidl/default/service.cpp
+++ b/weaver/aidl/default/service.cpp
@@ -28,7 +28,7 @@
 
     const std::string instance = std::string() + Weaver::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(weaver->asBinder().get(), instance.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
     return -1; // Should never be reached
diff --git a/wifi/.clang-format b/wifi/.clang-format
deleted file mode 100644
index 25ed932..0000000
--- a/wifi/.clang-format
+++ /dev/null
@@ -1,2 +0,0 @@
-BasedOnStyle: Google
-IndentWidth: 4
\ No newline at end of file
diff --git a/wifi/1.5/default/Android.mk b/wifi/1.5/default/Android.mk
deleted file mode 100644
index 1997b22..0000000
--- a/wifi/1.5/default/Android.mk
+++ /dev/null
@@ -1,198 +0,0 @@
-# Copyright (C) 2016 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.
-LOCAL_PATH := $(call my-dir)
-
-###
-### android.hardware.wifi static library
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-ifdef WIFI_HAL_INTERFACE_COMBINATIONS
-LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)"
-endif
-ifdef WIFI_HIDL_FEATURE_AWARE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
-endif
-ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-endif
-ifdef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
-LOCAL_CPPFLAGS += -DWIFI_AVOID_IFACE_RESET_MAC_CHANGE
-endif
-# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
-LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
-LOCAL_SRC_FILES := \
-    hidl_struct_util.cpp \
-    hidl_sync_util.cpp \
-    ringbuffer.cpp \
-    wifi.cpp \
-    wifi_ap_iface.cpp \
-    wifi_chip.cpp \
-    wifi_feature_flags.cpp \
-    wifi_iface_util.cpp \
-    wifi_legacy_hal.cpp \
-    wifi_legacy_hal_factory.cpp \
-    wifi_legacy_hal_stubs.cpp \
-    wifi_mode_controller.cpp \
-    wifi_nan_iface.cpp \
-    wifi_p2p_iface.cpp \
-    wifi_rtt_controller.cpp \
-    wifi_sta_iface.cpp \
-    wifi_status_util.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    libxml2 \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3 \
-    android.hardware.wifi@1.4 \
-    android.hardware.wifi@1.5
-LOCAL_C_INCLUDES += $(TOP)/external/libxml2/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-include $(BUILD_STATIC_LIBRARY)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
-    service.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    libxml2 \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3 \
-    android.hardware.wifi@1.4 \
-    android.hardware.wifi@1.5
-LOCAL_STATIC_LIBRARIES := \
-    android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
-LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service
-LOCAL_CFLAGS := -DLAZY_SERVICE
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
-    service.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    libxml2 \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3 \
-    android.hardware.wifi@1.4 \
-    android.hardware.wifi@1.5
-LOCAL_STATIC_LIBRARIES := \
-    android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi unit tests.
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
-    tests/hidl_struct_util_unit_tests.cpp \
-    tests/main.cpp \
-    tests/mock_interface_tool.cpp \
-    tests/mock_wifi_feature_flags.cpp \
-    tests/mock_wifi_iface_util.cpp \
-    tests/mock_wifi_legacy_hal.cpp \
-    tests/mock_wifi_mode_controller.cpp \
-    tests/ringbuffer_unit_tests.cpp \
-    tests/wifi_nan_iface_unit_tests.cpp \
-    tests/wifi_chip_unit_tests.cpp \
-    tests/wifi_iface_util_unit_tests.cpp
-LOCAL_STATIC_LIBRARIES := \
-    libgmock \
-    libgtest \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3 \
-    android.hardware.wifi@1.4 \
-    android.hardware.wifi@1.5 \
-    android.hardware.wifi@1.0-service-lib
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface
-include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
deleted file mode 100644
index bc6bb6a..0000000
--- a/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
+++ /dev/null
@@ -1,13 +0,0 @@
-service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service-lazy
-    interface android.hardware.wifi@1.0::IWifi default
-    interface android.hardware.wifi@1.1::IWifi default
-    interface android.hardware.wifi@1.2::IWifi default
-    interface android.hardware.wifi@1.3::IWifi default
-    interface android.hardware.wifi@1.4::IWifi default
-    interface android.hardware.wifi@1.5::IWifi default
-    oneshot
-    disabled
-    class hal
-    capabilities NET_ADMIN NET_RAW SYS_MODULE
-    user wifi
-    group wifi gps
diff --git a/wifi/1.5/default/android.hardware.wifi@1.0-service.rc b/wifi/1.5/default/android.hardware.wifi@1.0-service.rc
deleted file mode 100644
index 05706ef..0000000
--- a/wifi/1.5/default/android.hardware.wifi@1.0-service.rc
+++ /dev/null
@@ -1,11 +0,0 @@
-service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
-    interface android.hardware.wifi@1.0::IWifi default
-    interface android.hardware.wifi@1.1::IWifi default
-    interface android.hardware.wifi@1.2::IWifi default
-    interface android.hardware.wifi@1.3::IWifi default
-    interface android.hardware.wifi@1.4::IWifi default
-    interface android.hardware.wifi@1.5::IWifi default
-    class hal
-    capabilities NET_ADMIN NET_RAW SYS_MODULE
-    user wifi
-    group wifi gps
diff --git a/wifi/1.5/default/android.hardware.wifi@1.0-service.xml b/wifi/1.5/default/android.hardware.wifi@1.0-service.xml
deleted file mode 100644
index 88dd1e3..0000000
--- a/wifi/1.5/default/android.hardware.wifi@1.0-service.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="hidl">
-        <name>android.hardware.wifi</name>
-        <transport>hwbinder</transport>
-        <version>1.5</version>
-        <interface>
-            <name>IWifi</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/wifi/1.5/default/hidl_callback_util.h b/wifi/1.5/default/hidl_callback_util.h
deleted file mode 100644
index d144658..0000000
--- a/wifi/1.5/default/hidl_callback_util.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_CALLBACK_UTIL_H_
-#define HIDL_CALLBACK_UTIL_H_
-
-#include <set>
-
-#include <hidl/HidlSupport.h>
-
-namespace {
-// Type of callback invoked by the death handler.
-using on_death_cb_function = std::function<void(uint64_t)>;
-
-// Private class used to keep track of death of individual
-// callbacks stored in HidlCallbackHandler.
-template <typename CallbackType>
-class HidlDeathHandler : public android::hardware::hidl_death_recipient {
-   public:
-    HidlDeathHandler(const on_death_cb_function& user_cb_function)
-        : cb_function_(user_cb_function) {}
-    ~HidlDeathHandler() = default;
-
-    // Death notification for callbacks.
-    void serviceDied(
-        uint64_t cookie,
-        const android::wp<android::hidl::base::V1_0::IBase>& /* who */)
-        override {
-        cb_function_(cookie);
-    }
-
-   private:
-    on_death_cb_function cb_function_;
-
-    DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
-};
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace hidl_callback_util {
-template <typename CallbackType>
-// Provides a class to manage callbacks for the various HIDL interfaces and
-// handle the death of the process hosting each callback.
-class HidlCallbackHandler {
-   public:
-    HidlCallbackHandler()
-        : death_handler_(new HidlDeathHandler<CallbackType>(
-              std::bind(&HidlCallbackHandler::onObjectDeath, this,
-                        std::placeholders::_1))) {}
-    ~HidlCallbackHandler() = default;
-
-    bool addCallback(const sp<CallbackType>& cb) {
-        // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
-        // (callback proxy's raw pointer) to track the death of individual
-        // clients.
-        uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
-        if (cb_set_.find(cb) != cb_set_.end()) {
-            LOG(WARNING) << "Duplicate death notification registration";
-            return true;
-        }
-        if (!cb->linkToDeath(death_handler_, cookie)) {
-            LOG(ERROR) << "Failed to register death notification";
-            return false;
-        }
-        cb_set_.insert(cb);
-        return true;
-    }
-
-    const std::set<android::sp<CallbackType>>& getCallbacks() {
-        return cb_set_;
-    }
-
-    // Death notification for callbacks.
-    void onObjectDeath(uint64_t cookie) {
-        CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
-        const auto& iter = cb_set_.find(cb);
-        if (iter == cb_set_.end()) {
-            LOG(ERROR) << "Unknown callback death notification received";
-            return;
-        }
-        cb_set_.erase(iter);
-        LOG(DEBUG) << "Dead callback removed from list";
-    }
-
-    void invalidate() {
-        for (const sp<CallbackType>& cb : cb_set_) {
-            if (!cb->unlinkToDeath(death_handler_)) {
-                LOG(ERROR) << "Failed to deregister death notification";
-            }
-        }
-        cb_set_.clear();
-    }
-
-   private:
-    std::set<sp<CallbackType>> cb_set_;
-    sp<HidlDeathHandler<CallbackType>> death_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
-};
-
-}  // namespace hidl_callback_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.5/default/hidl_return_util.h b/wifi/1.5/default/hidl_return_util.h
deleted file mode 100644
index 4455185..0000000
--- a/wifi/1.5/default/hidl_return_util.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_RETURN_UTIL_H_
-#define HIDL_RETURN_UTIL_H_
-
-#include "hidl_sync_util.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace hidl_return_util {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * These utility functions are used to invoke a method on the provided
- * HIDL interface object.
- * These functions checks if the provided HIDL interface object is valid.
- * a) if valid, Invokes the corresponding internal implementation function of
- * the HIDL method. It then invokes the HIDL continuation callback with
- * the status and any returned values.
- * b) if invalid, invokes the HIDL continuation callback with the
- * provided error status and default values.
- */
-// Use for HIDL methods which return only an instance of WifiStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        hidl_cb((obj->*work)(std::forward<Args>(args)...));
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid));
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return only an instance of WifiStatus.
-// This version passes the global lock acquired to the body of the method.
-// Note: Only used by IWifi::stop() currently.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCallWithLock(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
-    auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid));
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and a single return
-// value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
-    Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
-        const WifiStatus& status = std::get<0>(ret_pair);
-        const auto& ret_value = std::get<1>(ret_pair);
-        hidl_cb(status, ret_value);
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid),
-                typename std::remove_reference<ReturnT>::type());
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and 2 return
-// values.
-template <typename ObjT, typename WorkFuncT, typename ReturnT1,
-          typename ReturnT2, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb,
-    Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
-        const WifiStatus& status = std::get<0>(ret_tuple);
-        const auto& ret_value1 = std::get<1>(ret_tuple);
-        const auto& ret_value2 = std::get<2>(ret_tuple);
-        hidl_cb(status, ret_value1, ret_value2);
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid),
-                typename std::remove_reference<ReturnT1>::type(),
-                typename std::remove_reference<ReturnT2>::type());
-    }
-    return Void();
-}
-
-}  // namespace hidl_return_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
deleted file mode 100644
index 338a8f1..0000000
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ /dev/null
@@ -1,3059 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-#include <utils/SystemClock.h>
-
-#include "hidl_struct_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace hidl_struct_util {
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
-    legacy_hal::wifi_channel_width type);
-
-hidl_string safeConvertChar(const char* str, size_t max_len) {
-    const char* c = str;
-    size_t size = 0;
-    while (*c && (unsigned char)*c < 128 && size < max_len) {
-        ++size;
-        ++c;
-    }
-    return hidl_string(str, size);
-}
-
-IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
-    uint32_t feature) {
-    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-    switch (feature) {
-        case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
-            return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
-        case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
-            return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
-        case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
-        case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
-        case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    switch (feature) {
-        case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
-            return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-V1_5::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
-    uint64_t feature) {
-    using HidlChipCaps = V1_5::IWifiChip::ChipCapabilityMask;
-    switch (feature) {
-        case WIFI_FEATURE_SET_TX_POWER_LIMIT:
-            return HidlChipCaps::SET_TX_POWER_LIMIT;
-        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
-            return HidlChipCaps::USE_BODY_HEAD_SAR;
-        case WIFI_FEATURE_D2D_RTT:
-            return HidlChipCaps::D2D_RTT;
-        case WIFI_FEATURE_D2AP_RTT:
-            return HidlChipCaps::D2AP_RTT;
-        case WIFI_FEATURE_INFRA_60G:
-            return HidlChipCaps::WIGIG;
-        case WIFI_FEATURE_SET_LATENCY_MODE:
-            return HidlChipCaps::SET_LATENCY_MODE;
-        case WIFI_FEATURE_P2P_RAND_MAC:
-            return HidlChipCaps::P2P_RAND_MAC;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) {
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    switch (feature) {
-        case WIFI_FEATURE_GSCAN:
-            return HidlStaIfaceCaps::BACKGROUND_SCAN;
-        case WIFI_FEATURE_LINK_LAYER_STATS:
-            return HidlStaIfaceCaps::LINK_LAYER_STATS;
-        case WIFI_FEATURE_RSSI_MONITOR:
-            return HidlStaIfaceCaps::RSSI_MONITOR;
-        case WIFI_FEATURE_CONTROL_ROAMING:
-            return HidlStaIfaceCaps::CONTROL_ROAMING;
-        case WIFI_FEATURE_IE_WHITELIST:
-            return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
-        case WIFI_FEATURE_SCAN_RAND:
-            return HidlStaIfaceCaps::SCAN_RAND;
-        case WIFI_FEATURE_INFRA_5G:
-            return HidlStaIfaceCaps::STA_5G;
-        case WIFI_FEATURE_HOTSPOT:
-            return HidlStaIfaceCaps::HOTSPOT;
-        case WIFI_FEATURE_PNO:
-            return HidlStaIfaceCaps::PNO;
-        case WIFI_FEATURE_TDLS:
-            return HidlStaIfaceCaps::TDLS;
-        case WIFI_FEATURE_TDLS_OFFCHANNEL:
-            return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
-        case WIFI_FEATURE_CONFIG_NDO:
-            return HidlStaIfaceCaps::ND_OFFLOAD;
-        case WIFI_FEATURE_MKEEP_ALIVE:
-            return HidlStaIfaceCaps::KEEP_ALIVE;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-    for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
-        if (feature & legacy_logger_feature_set) {
-            *hidl_caps |=
-                convertLegacyLoggerFeatureToHidlChipCapability(feature);
-        }
-    }
-    std::vector<uint64_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
-                                      WIFI_FEATURE_USE_BODY_HEAD_SAR,
-                                      WIFI_FEATURE_D2D_RTT,
-                                      WIFI_FEATURE_D2AP_RTT,
-                                      WIFI_FEATURE_INFRA_60G,
-                                      WIFI_FEATURE_SET_LATENCY_MODE,
-                                      WIFI_FEATURE_P2P_RAND_MAC};
-    for (const auto feature : features) {
-        if (feature & legacy_feature_set) {
-            *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
-        }
-    }
-
-    // There are no flags for these 3 in the legacy feature set. Adding them to
-    // the set because all the current devices support it.
-    *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
-    *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
-    *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
-    return true;
-}
-
-WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
-    uint32_t flag) {
-    switch (flag) {
-        case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
-            return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
-        case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
-            return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
-    };
-    CHECK(false) << "Unknown legacy flag: " << flag;
-    return {};
-}
-
-bool convertLegacyDebugRingBufferStatusToHidl(
-    const legacy_hal::wifi_ring_buffer_status& legacy_status,
-    WifiDebugRingBufferStatus* hidl_status) {
-    if (!hidl_status) {
-        return false;
-    }
-    *hidl_status = {};
-    hidl_status->ringName =
-        safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
-                        sizeof(legacy_status.name));
-    hidl_status->flags = 0;
-    for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
-                            WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
-        if (flag & legacy_status.flags) {
-            hidl_status->flags |= static_cast<
-                std::underlying_type<WifiDebugRingBufferFlags>::type>(
-                convertLegacyDebugRingBufferFlagsToHidl(flag));
-        }
-    }
-    hidl_status->ringId = legacy_status.ring_id;
-    hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
-    // Calculate free size of the ring the buffer. We don't need to send the
-    // exact read/write pointers that were there in the legacy HAL interface.
-    if (legacy_status.written_bytes >= legacy_status.read_bytes) {
-        hidl_status->freeSizeInBytes =
-            legacy_status.ring_buffer_byte_size -
-            (legacy_status.written_bytes - legacy_status.read_bytes);
-    } else {
-        hidl_status->freeSizeInBytes =
-            legacy_status.read_bytes - legacy_status.written_bytes;
-    }
-    hidl_status->verboseLevel = legacy_status.verbose_level;
-    return true;
-}
-
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
-    if (!hidl_status_vec) {
-        return false;
-    }
-    *hidl_status_vec = {};
-    for (const auto& legacy_status : legacy_status_vec) {
-        WifiDebugRingBufferStatus hidl_status;
-        if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
-                                                      &hidl_status)) {
-            return false;
-        }
-        hidl_status_vec->push_back(hidl_status);
-    }
-    return true;
-}
-
-bool convertLegacyWakeReasonStatsToHidl(
-    const legacy_hal::WakeReasonStats& legacy_stats,
-    WifiDebugHostWakeReasonStats* hidl_stats) {
-    if (!hidl_stats) {
-        return false;
-    }
-    *hidl_stats = {};
-    hidl_stats->totalCmdEventWakeCnt =
-        legacy_stats.wake_reason_cnt.total_cmd_event_wake;
-    hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
-    hidl_stats->totalDriverFwLocalWakeCnt =
-        legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
-    hidl_stats->driverFwLocalWakeCntPerType =
-        legacy_stats.driver_fw_local_wake_cnt;
-    hidl_stats->totalRxPacketWakeCnt =
-        legacy_stats.wake_reason_cnt.total_rx_data_wake;
-    hidl_stats->rxPktWakeDetails.rxUnicastCnt =
-        legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
-    hidl_stats->rxPktWakeDetails.rxMulticastCnt =
-        legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
-    hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
-        legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
-        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-            .ipv4_rx_multicast_addr_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
-        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-            .ipv6_rx_multicast_addr_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
-        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-            .other_rx_multicast_addr_cnt;
-    hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
-    return true;
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-    V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
-    switch (hidl_scenario) {
-        // This is the only supported scenario for V1_1
-        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
-            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-    V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
-    switch (hidl_scenario) {
-        // This is the only supported scenario for V1_1
-        case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
-            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
-        // Those are the supported scenarios for V1_2
-        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
-        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
-        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
-        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
-    V1_3::IWifiChip::LatencyMode hidl_latency_mode) {
-    switch (hidl_latency_mode) {
-        case V1_3::IWifiChip::LatencyMode::NORMAL:
-            return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
-        case V1_3::IWifiChip::LatencyMode::LOW:
-            return legacy_hal::WIFI_LATENCY_MODE_LOW;
-    }
-    CHECK(false);
-}
-
-bool convertLegacyWifiMacInfoToHidl(
-    const legacy_hal::WifiMacInfo& legacy_mac_info,
-    V1_4::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
-    if (!hidl_radio_mode_info) {
-        return false;
-    }
-    *hidl_radio_mode_info = {};
-
-    hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
-    // Convert from bitmask of bands in the legacy HAL to enum value in
-    // the HIDL interface.
-    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
-        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
-        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ_6GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
-               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ_6GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_6GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
-               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ;
-    } else {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_UNSPECIFIED;
-    }
-    std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
-    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
-        V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
-        iface_info.name = legacy_iface_info.name;
-        iface_info.channel = legacy_iface_info.channel;
-        iface_info_vec.push_back(iface_info);
-    }
-    hidl_radio_mode_info->ifaceInfos = iface_info_vec;
-    return true;
-}
-
-uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand hidl_band) {
-    switch (hidl_band) {
-        case V1_5::WifiBand::BAND_24GHZ:
-            return legacy_hal::WLAN_MAC_2_4_BAND;
-        case V1_5::WifiBand::BAND_5GHZ:
-        case V1_5::WifiBand::BAND_5GHZ_DFS:
-        case V1_5::WifiBand::BAND_5GHZ_WITH_DFS:
-            return legacy_hal::WLAN_MAC_5_0_BAND;
-        case V1_5::WifiBand::BAND_24GHZ_5GHZ:
-        case V1_5::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
-            return (legacy_hal::WLAN_MAC_2_4_BAND |
-                    legacy_hal::WLAN_MAC_5_0_BAND);
-        case V1_5::WifiBand::BAND_6GHZ:
-            return legacy_hal::WLAN_MAC_6_0_BAND;
-        case V1_5::WifiBand::BAND_5GHZ_6GHZ:
-            return (legacy_hal::WLAN_MAC_5_0_BAND |
-                    legacy_hal::WLAN_MAC_6_0_BAND);
-        case V1_5::WifiBand::BAND_24GHZ_5GHZ_6GHZ:
-        case V1_5::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS_6GHZ:
-            return (legacy_hal::WLAN_MAC_2_4_BAND |
-                    legacy_hal::WLAN_MAC_5_0_BAND |
-                    legacy_hal::WLAN_MAC_6_0_BAND);
-        case V1_5::WifiBand::BAND_60GHZ:
-            return legacy_hal::WLAN_MAC_60_0_BAND;
-        default:
-            return (
-                legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND |
-                legacy_hal::WLAN_MAC_6_0_BAND | legacy_hal::WLAN_MAC_60_0_BAND);
-    }
-}
-
-uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask) {
-    uint32_t legacy_iface_mask = 0;
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_STA) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_STA);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_SOFTAP);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_GO);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_NAN) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_NAN);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_TDLS) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_TDLS);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_MESH) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_MESH);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_IBSS) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_IBSS);
-    }
-    return legacy_iface_mask;
-}
-
-uint32_t convertLegacyWifiInterfaceModeToHidl(uint32_t legacy_iface_mask) {
-    uint32_t hidl_iface_mask = 0;
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_STA)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_STA;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_SOFTAP)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_GO)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_NAN)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_NAN;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_TDLS)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_TDLS;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_MESH)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_MESH;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_IBSS)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_IBSS;
-    }
-    return hidl_iface_mask;
-}
-
-uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask) {
-    uint32_t legacy_filter_mask = 0;
-    if (hidl_filter_mask &
-        IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) {
-        legacy_filter_mask |=
-            legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
-    }
-    if (hidl_filter_mask & IWifiChip::UsableChannelFilter::CONCURRENCY) {
-        legacy_filter_mask |=
-            legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
-    }
-    return legacy_filter_mask;
-}
-
-bool convertLegacyWifiUsableChannelToHidl(
-    const legacy_hal::wifi_usable_channel& legacy_usable_channel,
-    V1_5::WifiUsableChannel* hidl_usable_channel) {
-    if (!hidl_usable_channel) {
-        return false;
-    }
-    *hidl_usable_channel = {};
-    hidl_usable_channel->channel = legacy_usable_channel.freq;
-    hidl_usable_channel->channelBandwidth =
-        convertLegacyWifiChannelWidthToHidl(legacy_usable_channel.width);
-    hidl_usable_channel->ifaceModeMask = convertLegacyWifiInterfaceModeToHidl(
-        legacy_usable_channel.iface_mode_mask);
-
-    return true;
-}
-
-bool convertLegacyWifiUsableChannelsToHidl(
-    const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
-    std::vector<V1_5::WifiUsableChannel>* hidl_usable_channels) {
-    if (!hidl_usable_channels) {
-        return false;
-    }
-    *hidl_usable_channels = {};
-    for (const auto& legacy_usable_channel : legacy_usable_channels) {
-        V1_5::WifiUsableChannel hidl_usable_channel;
-        if (!convertLegacyWifiUsableChannelToHidl(legacy_usable_channel,
-                                                  &hidl_usable_channel)) {
-            return false;
-        }
-        hidl_usable_channels->push_back(hidl_usable_channel);
-    }
-    return true;
-}
-
-bool convertLegacyWifiMacInfosToHidl(
-    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>*
-        hidl_radio_mode_infos) {
-    if (!hidl_radio_mode_infos) {
-        return false;
-    }
-    *hidl_radio_mode_infos = {};
-
-    for (const auto& legacy_mac_info : legacy_mac_infos) {
-        V1_4::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
-        if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
-                                            &hidl_radio_mode_info)) {
-            return false;
-        }
-        hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
-    }
-    return true;
-}
-
-bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
-        if (feature & legacy_logger_feature_set) {
-            *hidl_caps |=
-                convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
-        }
-    }
-    for (const auto feature :
-         {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS,
-          WIFI_FEATURE_RSSI_MONITOR, WIFI_FEATURE_CONTROL_ROAMING,
-          WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
-          WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO,
-          WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL,
-          WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
-        if (feature & legacy_feature_set) {
-            *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
-        }
-    }
-    // There is no flag for this one in the legacy feature set. Adding it to the
-    // set because all the current devices support it.
-    *hidl_caps |= HidlStaIfaceCaps::APF;
-    return true;
-}
-
-bool convertLegacyApfCapabilitiesToHidl(
-    const legacy_hal::PacketFilterCapabilities& legacy_caps,
-    StaApfPacketFilterCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->version = legacy_caps.version;
-    hidl_caps->maxLength = legacy_caps.max_len;
-    return true;
-}
-
-uint8_t convertHidlGscanReportEventFlagToLegacy(
-    StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
-    using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-    switch (hidl_flag) {
-        case HidlFlag::EACH_SCAN:
-            return REPORT_EVENTS_EACH_SCAN;
-        case HidlFlag::FULL_RESULTS:
-            return REPORT_EVENTS_FULL_RESULTS;
-        case HidlFlag::NO_BATCH:
-            return REPORT_EVENTS_NO_BATCH;
-    };
-    CHECK(false);
-}
-
-StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
-    switch (legacy_flag) {
-        case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
-            return StaScanDataFlagMask::INTERRUPTED;
-    };
-    CHECK(false) << "Unknown legacy flag: " << legacy_flag;
-    // To silence the compiler warning about reaching the end of non-void
-    // function.
-    return {};
-}
-
-bool convertLegacyGscanCapabilitiesToHidl(
-    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-    StaBackgroundScanCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
-    hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
-    hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
-    hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
-    return true;
-}
-
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) {
-    switch (band) {
-        case V1_0::WifiBand::BAND_UNSPECIFIED:
-            return legacy_hal::WIFI_BAND_UNSPECIFIED;
-        case V1_0::WifiBand::BAND_24GHZ:
-            return legacy_hal::WIFI_BAND_BG;
-        case V1_0::WifiBand::BAND_5GHZ:
-            return legacy_hal::WIFI_BAND_A;
-        case V1_0::WifiBand::BAND_5GHZ_DFS:
-            return legacy_hal::WIFI_BAND_A_DFS;
-        case V1_0::WifiBand::BAND_5GHZ_WITH_DFS:
-            return legacy_hal::WIFI_BAND_A_WITH_DFS;
-        case V1_0::WifiBand::BAND_24GHZ_5GHZ:
-            return legacy_hal::WIFI_BAND_ABG;
-        case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
-            return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
-    };
-    CHECK(false);
-}
-
-bool convertHidlGscanParamsToLegacy(
-    const StaBackgroundScanParameters& hidl_scan_params,
-    legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
-    if (!legacy_scan_params) {
-        return false;
-    }
-    *legacy_scan_params = {};
-    legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
-    legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
-    legacy_scan_params->report_threshold_percent =
-        hidl_scan_params.reportThresholdPercent;
-    legacy_scan_params->report_threshold_num_scans =
-        hidl_scan_params.reportThresholdNumScans;
-    if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
-        return false;
-    }
-    legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
-    for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size();
-         bucket_idx++) {
-        const StaBackgroundScanBucketParameters& hidl_bucket_spec =
-            hidl_scan_params.buckets[bucket_idx];
-        legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
-            legacy_scan_params->buckets[bucket_idx];
-        if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
-            return false;
-        }
-        legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
-        legacy_bucket_spec.band =
-            convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
-        legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
-        legacy_bucket_spec.max_period =
-            hidl_bucket_spec.exponentialMaxPeriodInMs;
-        legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
-        legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
-        legacy_bucket_spec.report_events = 0;
-        using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-        for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS,
-                                HidlFlag::NO_BATCH}) {
-            if (hidl_bucket_spec.eventReportScheme &
-                static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
-                legacy_bucket_spec.report_events |=
-                    convertHidlGscanReportEventFlagToLegacy(flag);
-            }
-        }
-        if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
-            return false;
-        }
-        legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
-        for (uint32_t freq_idx = 0;
-             freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
-            legacy_bucket_spec.channels[freq_idx].channel =
-                hidl_bucket_spec.frequencies[freq_idx];
-        }
-    }
-    return true;
-}
-
-bool convertLegacyIeToHidl(
-    const legacy_hal::wifi_information_element& legacy_ie,
-    WifiInformationElement* hidl_ie) {
-    if (!hidl_ie) {
-        return false;
-    }
-    *hidl_ie = {};
-    hidl_ie->id = legacy_ie.id;
-    hidl_ie->data =
-        std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
-    return true;
-}
-
-bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
-                               std::vector<WifiInformationElement>* hidl_ies) {
-    if (!ie_blob || !hidl_ies) {
-        return false;
-    }
-    *hidl_ies = {};
-    const uint8_t* ies_begin = ie_blob;
-    const uint8_t* ies_end = ie_blob + ie_blob_len;
-    const uint8_t* next_ie = ies_begin;
-    using wifi_ie = legacy_hal::wifi_information_element;
-    constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
-    // Each IE should atleast have the header (i.e |id| & |len| fields).
-    while (next_ie + kIeHeaderLen <= ies_end) {
-        const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
-        uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
-        if (next_ie + curr_ie_len > ies_end) {
-            LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
-                       << ", Curr IE len: " << curr_ie_len
-                       << ", IEs End: " << (void*)ies_end;
-            break;
-        }
-        WifiInformationElement hidl_ie;
-        if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
-            LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
-                       << ", len: " << legacy_ie.len;
-            break;
-        }
-        hidl_ies->push_back(std::move(hidl_ie));
-        next_ie += curr_ie_len;
-    }
-    // Check if the blob has been fully consumed.
-    if (next_ie != ies_end) {
-        LOG(ERROR) << "Failed to fully parse IE blob. Next IE: "
-                   << (void*)next_ie << ", IEs End: " << (void*)ies_end;
-    }
-    return true;
-}
-
-bool convertLegacyGscanResultToHidl(
-    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
-    StaScanResult* hidl_scan_result) {
-    if (!hidl_scan_result) {
-        return false;
-    }
-    *hidl_scan_result = {};
-    hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
-    hidl_scan_result->ssid = std::vector<uint8_t>(
-        legacy_scan_result.ssid,
-        legacy_scan_result.ssid + strnlen(legacy_scan_result.ssid,
-                                          sizeof(legacy_scan_result.ssid) - 1));
-    memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
-           hidl_scan_result->bssid.size());
-    hidl_scan_result->frequency = legacy_scan_result.channel;
-    hidl_scan_result->rssi = legacy_scan_result.rssi;
-    hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
-    hidl_scan_result->capability = legacy_scan_result.capability;
-    if (has_ie_data) {
-        std::vector<WifiInformationElement> ies;
-        if (!convertLegacyIeBlobToHidl(
-                reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
-                legacy_scan_result.ie_length, &ies)) {
-            return false;
-        }
-        hidl_scan_result->informationElements = std::move(ies);
-    }
-    return true;
-}
-
-bool convertLegacyCachedGscanResultsToHidl(
-    const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
-    StaScanData* hidl_scan_data) {
-    if (!hidl_scan_data) {
-        return false;
-    }
-    *hidl_scan_data = {};
-    hidl_scan_data->flags = 0;
-    for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
-        if (legacy_cached_scan_result.flags & flag) {
-            hidl_scan_data->flags |=
-                static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
-                    convertLegacyGscanDataFlagToHidl(flag));
-        }
-    }
-    hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
-
-    CHECK(legacy_cached_scan_result.num_results >= 0 &&
-          legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
-    std::vector<StaScanResult> hidl_scan_results;
-    for (int32_t result_idx = 0;
-         result_idx < legacy_cached_scan_result.num_results; result_idx++) {
-        StaScanResult hidl_scan_result;
-        if (!convertLegacyGscanResultToHidl(
-                legacy_cached_scan_result.results[result_idx], false,
-                &hidl_scan_result)) {
-            return false;
-        }
-        hidl_scan_results.push_back(hidl_scan_result);
-    }
-    hidl_scan_data->results = std::move(hidl_scan_results);
-    return true;
-}
-
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-    const std::vector<legacy_hal::wifi_cached_scan_results>&
-        legacy_cached_scan_results,
-    std::vector<StaScanData>* hidl_scan_datas) {
-    if (!hidl_scan_datas) {
-        return false;
-    }
-    *hidl_scan_datas = {};
-    for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
-        StaScanData hidl_scan_data;
-        if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
-                                                   &hidl_scan_data)) {
-            return false;
-        }
-        hidl_scan_datas->push_back(hidl_scan_data);
-    }
-    return true;
-}
-
-WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
-    legacy_hal::wifi_tx_packet_fate fate) {
-    switch (fate) {
-        case legacy_hal::TX_PKT_FATE_ACKED:
-            return WifiDebugTxPacketFate::ACKED;
-        case legacy_hal::TX_PKT_FATE_SENT:
-            return WifiDebugTxPacketFate::SENT;
-        case legacy_hal::TX_PKT_FATE_FW_QUEUED:
-            return WifiDebugTxPacketFate::FW_QUEUED;
-        case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
-            return WifiDebugTxPacketFate::FW_DROP_INVALID;
-        case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
-            return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
-        case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
-            return WifiDebugTxPacketFate::FW_DROP_OTHER;
-        case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
-            return WifiDebugTxPacketFate::DRV_QUEUED;
-        case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
-            return WifiDebugTxPacketFate::DRV_DROP_INVALID;
-        case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
-            return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
-        case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
-            return WifiDebugTxPacketFate::DRV_DROP_OTHER;
-    };
-    CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
-    legacy_hal::wifi_rx_packet_fate fate) {
-    switch (fate) {
-        case legacy_hal::RX_PKT_FATE_SUCCESS:
-            return WifiDebugRxPacketFate::SUCCESS;
-        case legacy_hal::RX_PKT_FATE_FW_QUEUED:
-            return WifiDebugRxPacketFate::FW_QUEUED;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
-            return WifiDebugRxPacketFate::FW_DROP_FILTER;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
-            return WifiDebugRxPacketFate::FW_DROP_INVALID;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
-            return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
-            return WifiDebugRxPacketFate::FW_DROP_OTHER;
-        case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
-            return WifiDebugRxPacketFate::DRV_QUEUED;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
-            return WifiDebugRxPacketFate::DRV_DROP_FILTER;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
-            return WifiDebugRxPacketFate::DRV_DROP_INVALID;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
-            return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
-            return WifiDebugRxPacketFate::DRV_DROP_OTHER;
-    };
-    CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
-    legacy_hal::frame_type type) {
-    switch (type) {
-        case legacy_hal::FRAME_TYPE_UNKNOWN:
-            return WifiDebugPacketFateFrameType::UNKNOWN;
-        case legacy_hal::FRAME_TYPE_ETHERNET_II:
-            return WifiDebugPacketFateFrameType::ETHERNET_II;
-        case legacy_hal::FRAME_TYPE_80211_MGMT:
-            return WifiDebugPacketFateFrameType::MGMT_80211;
-    };
-    CHECK(false) << "Unknown legacy frame type: " << type;
-}
-
-bool convertLegacyDebugPacketFateFrameToHidl(
-    const legacy_hal::frame_info& legacy_frame,
-    WifiDebugPacketFateFrameInfo* hidl_frame) {
-    if (!hidl_frame) {
-        return false;
-    }
-    *hidl_frame = {};
-    hidl_frame->frameType =
-        convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
-    hidl_frame->frameLen = legacy_frame.frame_len;
-    hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
-    hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
-    const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
-        legacy_frame.frame_content.ethernet_ii_bytes);
-    hidl_frame->frameContent =
-        std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
-    return true;
-}
-
-bool convertLegacyDebugTxPacketFateToHidl(
-    const legacy_hal::wifi_tx_report& legacy_fate,
-    WifiDebugTxPacketFateReport* hidl_fate) {
-    if (!hidl_fate) {
-        return false;
-    }
-    *hidl_fate = {};
-    hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
-    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
-                                                   &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-    std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
-    if (!hidl_fates) {
-        return false;
-    }
-    *hidl_fates = {};
-    for (const auto& legacy_fate : legacy_fates) {
-        WifiDebugTxPacketFateReport hidl_fate;
-        if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-            return false;
-        }
-        hidl_fates->push_back(hidl_fate);
-    }
-    return true;
-}
-
-bool convertLegacyDebugRxPacketFateToHidl(
-    const legacy_hal::wifi_rx_report& legacy_fate,
-    WifiDebugRxPacketFateReport* hidl_fate) {
-    if (!hidl_fate) {
-        return false;
-    }
-    *hidl_fate = {};
-    hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
-    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
-                                                   &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-    std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
-    if (!hidl_fates) {
-        return false;
-    }
-    *hidl_fates = {};
-    for (const auto& legacy_fate : legacy_fates) {
-        WifiDebugRxPacketFateReport hidl_fate;
-        if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-            return false;
-        }
-        hidl_fates->push_back(hidl_fate);
-    }
-    return true;
-}
-
-bool convertLegacyLinkLayerRadioStatsToHidl(
-    const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
-    V1_5::StaLinkLayerRadioStats* hidl_radio_stat) {
-    if (!hidl_radio_stat) {
-        return false;
-    }
-    *hidl_radio_stat = {};
-
-    hidl_radio_stat->radioId = legacy_radio_stat.stats.radio;
-    hidl_radio_stat->V1_3.V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
-    hidl_radio_stat->V1_3.V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
-    hidl_radio_stat->V1_3.V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
-    hidl_radio_stat->V1_3.V1_0.onTimeInMsForScan =
-        legacy_radio_stat.stats.on_time_scan;
-    hidl_radio_stat->V1_3.V1_0.txTimeInMsPerLevel =
-        legacy_radio_stat.tx_time_per_levels;
-    hidl_radio_stat->V1_3.onTimeInMsForNanScan =
-        legacy_radio_stat.stats.on_time_nbd;
-    hidl_radio_stat->V1_3.onTimeInMsForBgScan =
-        legacy_radio_stat.stats.on_time_gscan;
-    hidl_radio_stat->V1_3.onTimeInMsForRoamScan =
-        legacy_radio_stat.stats.on_time_roam_scan;
-    hidl_radio_stat->V1_3.onTimeInMsForPnoScan =
-        legacy_radio_stat.stats.on_time_pno_scan;
-    hidl_radio_stat->V1_3.onTimeInMsForHs20Scan =
-        legacy_radio_stat.stats.on_time_hs20;
-
-    std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
-
-    for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
-        V1_3::WifiChannelStats hidl_channel_stat;
-        hidl_channel_stat.onTimeInMs = channel_stat.on_time;
-        hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
-        /*
-         * TODO once b/119142899 is fixed,
-         * replace below code with convertLegacyWifiChannelInfoToHidl()
-         */
-        hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
-        hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
-        hidl_channel_stat.channel.centerFreq0 =
-            channel_stat.channel.center_freq0;
-        hidl_channel_stat.channel.centerFreq1 =
-            channel_stat.channel.center_freq1;
-        hidl_channel_stats.push_back(hidl_channel_stat);
-    }
-
-    hidl_radio_stat->V1_3.channelStats = hidl_channel_stats;
-
-    return true;
-}
-
-bool convertLegacyLinkLayerStatsToHidl(
-    const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats) {
-    if (!hidl_stats) {
-        return false;
-    }
-    *hidl_stats = {};
-    // iface legacy_stats conversion.
-    hidl_stats->iface.V1_0.beaconRx = legacy_stats.iface.beacon_rx;
-    hidl_stats->iface.V1_0.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
-    hidl_stats->iface.V1_0.wmeBePktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeBePktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeBePktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeBePktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMinInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionNumSamples =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
-    hidl_stats->iface.V1_0.wmeBkPktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeBkPktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeBkPktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeBkPktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMinInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionNumSamples =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
-    hidl_stats->iface.V1_0.wmeViPktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeViPktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeViPktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeViPktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMinInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMaxInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeAvgInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionNumSamples =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
-    hidl_stats->iface.V1_0.wmeVoPktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeVoPktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeVoPktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeVoPktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMinInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionNumSamples =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
-    hidl_stats->iface.timeSliceDutyCycleInPercent =
-        legacy_stats.iface.info.time_slicing_duty_cycle_percent;
-    // peer info legacy_stats conversion.
-    std::vector<StaPeerInfo> hidl_peers_info_stats;
-    for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
-        StaPeerInfo hidl_peer_info_stats;
-        if (!convertLegacyPeerInfoStatsToHidl(legacy_peer_info_stats,
-                                              &hidl_peer_info_stats)) {
-            return false;
-        }
-        hidl_peers_info_stats.push_back(hidl_peer_info_stats);
-    }
-    hidl_stats->iface.peers = hidl_peers_info_stats;
-    // radio legacy_stats conversion.
-    std::vector<V1_5::StaLinkLayerRadioStats> hidl_radios_stats;
-    for (const auto& legacy_radio_stats : legacy_stats.radios) {
-        V1_5::StaLinkLayerRadioStats hidl_radio_stats;
-        if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats,
-                                                    &hidl_radio_stats)) {
-            return false;
-        }
-        hidl_radios_stats.push_back(hidl_radio_stats);
-    }
-    hidl_stats->radios = hidl_radios_stats;
-    // Timestamp in the HAL wrapper here since it's not provided in the legacy
-    // HAL API.
-    hidl_stats->timeStampInMs = uptimeMillis();
-    return true;
-}
-
-bool convertLegacyPeerInfoStatsToHidl(
-    const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
-    StaPeerInfo* hidl_peer_info_stats) {
-    if (!hidl_peer_info_stats) {
-        return false;
-    }
-    *hidl_peer_info_stats = {};
-    hidl_peer_info_stats->staCount =
-        legacy_peer_info_stats.peer_info.bssload.sta_count;
-    hidl_peer_info_stats->chanUtil =
-        legacy_peer_info_stats.peer_info.bssload.chan_util;
-
-    std::vector<StaRateStat> hidlRateStats;
-    for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
-        StaRateStat rateStat;
-        if (!convertLegacyWifiRateInfoToHidl(legacy_rate_stats.rate,
-                                             &rateStat.rateInfo)) {
-            return false;
-        }
-        rateStat.txMpdu = legacy_rate_stats.tx_mpdu;
-        rateStat.rxMpdu = legacy_rate_stats.rx_mpdu;
-        rateStat.mpduLost = legacy_rate_stats.mpdu_lost;
-        rateStat.retries = legacy_rate_stats.retries;
-        hidlRateStats.push_back(rateStat);
-    }
-    hidl_peer_info_stats->rateStats = hidlRateStats;
-    return true;
-}
-
-bool convertLegacyRoamingCapabilitiesToHidl(
-    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-    StaRoamingCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
-    hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
-    return true;
-}
-
-bool convertHidlRoamingConfigToLegacy(
-    const StaRoamingConfig& hidl_config,
-    legacy_hal::wifi_roaming_config* legacy_config) {
-    if (!legacy_config) {
-        return false;
-    }
-    *legacy_config = {};
-    if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
-        hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
-        return false;
-    }
-    legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
-    uint32_t i = 0;
-    for (const auto& bssid : hidl_config.bssidBlacklist) {
-        CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
-        memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
-    }
-    legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
-    i = 0;
-    for (const auto& ssid : hidl_config.ssidWhitelist) {
-        CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
-        legacy_config->whitelist_ssid[i].length = ssid.size();
-        memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(),
-               ssid.size());
-        i++;
-    }
-    return true;
-}
-
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
-    StaRoamingState state) {
-    switch (state) {
-        case StaRoamingState::ENABLED:
-            return legacy_hal::ROAMING_ENABLE;
-        case StaRoamingState::DISABLED:
-            return legacy_hal::ROAMING_DISABLE;
-    };
-    CHECK(false);
-}
-
-legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
-    switch (type) {
-        case NanMatchAlg::MATCH_ONCE:
-            return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
-        case NanMatchAlg::MATCH_CONTINUOUS:
-            return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
-        case NanMatchAlg::MATCH_NEVER:
-            return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(
-    NanPublishType type) {
-    switch (type) {
-        case NanPublishType::UNSOLICITED:
-            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
-        case NanPublishType::SOLICITED:
-            return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
-        case NanPublishType::UNSOLICITED_SOLICITED:
-            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
-    switch (type) {
-        case NanTxType::BROADCAST:
-            return legacy_hal::NAN_TX_TYPE_BROADCAST;
-        case NanTxType::UNICAST:
-            return legacy_hal::NAN_TX_TYPE_UNICAST;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(
-    NanSubscribeType type) {
-    switch (type) {
-        case NanSubscribeType::PASSIVE:
-            return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
-        case NanSubscribeType::ACTIVE:
-            return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
-    switch (type) {
-        case NanSrfType::BLOOM_FILTER:
-            return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
-        case NanSrfType::PARTIAL_MAC_ADDR:
-            return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
-    NanDataPathChannelCfg type) {
-    switch (type) {
-        case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
-            return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
-        case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
-            return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
-        case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
-            return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
-    }
-    CHECK(false);
-}
-
-NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
-    switch (type) {
-        case legacy_hal::NAN_STATUS_SUCCESS:
-            return NanStatusType::SUCCESS;
-        case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
-            return NanStatusType::INTERNAL_FAILURE;
-        case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
-            return NanStatusType::PROTOCOL_FAILURE;
-        case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
-            return NanStatusType::INVALID_SESSION_ID;
-        case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
-            return NanStatusType::NO_RESOURCES_AVAILABLE;
-        case legacy_hal::NAN_STATUS_INVALID_PARAM:
-            return NanStatusType::INVALID_ARGS;
-        case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
-            return NanStatusType::INVALID_PEER_ID;
-        case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
-            return NanStatusType::INVALID_NDP_ID;
-        case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
-            return NanStatusType::NAN_NOT_ALLOWED;
-        case legacy_hal::NAN_STATUS_NO_OTA_ACK:
-            return NanStatusType::NO_OTA_ACK;
-        case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
-            return NanStatusType::ALREADY_ENABLED;
-        case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
-            return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
-        case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
-            return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
-    }
-    CHECK(false);
-}
-
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
-                            size_t max_len, WifiNanStatus* wifiNanStatus) {
-    wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
-    wifiNanStatus->description = safeConvertChar(str, max_len);
-}
-
-bool convertHidlNanEnableRequestToLegacy(
-    const V1_4::NanEnableRequest& hidl_request,
-    legacy_hal::NanEnableRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanEnableRequestToLegacy: null legacy_request";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->config_2dot4g_support = 1;
-    legacy_request->support_2dot4g_val =
-        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_support_5g = 1;
-    legacy_request->support_5g_val =
-        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_hop_count_limit = 1;
-    legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
-    legacy_request->master_pref = hidl_request.configParams.masterPref;
-    legacy_request->discovery_indication_cfg = 0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1
-                                                                          : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
-    legacy_request->config_sid_beacon = 1;
-    if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "numberOfPublishServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->sid_beacon_val =
-        (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1
-                                                                    : 0x0) |
-        (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
-    legacy_request->config_subscribe_sid_beacon = 1;
-    if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "numberOfSubscribeServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->subscribe_sid_beacon_val =
-        (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1
-                                                                      : 0x0) |
-        (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
-    legacy_request->config_rssi_window_size = 1;
-    legacy_request->rssi_window_size_val =
-        hidl_request.configParams.rssiWindowSize;
-    legacy_request->config_disc_mac_addr_randomization = 1;
-    legacy_request->disc_mac_addr_rand_interval_sec =
-        hidl_request.configParams.macAddressRandomizationIntervalSec;
-    legacy_request->config_2dot4g_rssi_close = 1;
-    if (hidl_request.configParams.bandSpecificConfig.size() != 3) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "bandSpecificConfig.size() != 3";
-        return false;
-    }
-    legacy_request->rssi_close_2dot4g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .rssiClose;
-    legacy_request->config_2dot4g_rssi_middle = 1;
-    legacy_request->rssi_middle_2dot4g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .rssiMiddle;
-    legacy_request->config_2dot4g_rssi_proximity = 1;
-    legacy_request->rssi_proximity_2dot4g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .rssiCloseProximity;
-    legacy_request->config_scan_params = 1;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_2dot4g_dw_band =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_2dot4g_interval_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .discoveryWindowIntervalVal;
-    legacy_request->config_5g_rssi_close = 1;
-    legacy_request->rssi_close_5g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiClose;
-    legacy_request->config_5g_rssi_middle = 1;
-    legacy_request->rssi_middle_5g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiMiddle;
-    legacy_request->config_5g_rssi_close_proximity = 1;
-    legacy_request->rssi_close_proximity_5g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiCloseProximity;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_5g_dw_band =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_5g_interval_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .discoveryWindowIntervalVal;
-    if (hidl_request.debugConfigs.validClusterIdVals) {
-        legacy_request->cluster_low =
-            hidl_request.debugConfigs.clusterIdBottomRangeVal;
-        legacy_request->cluster_high =
-            hidl_request.debugConfigs.clusterIdTopRangeVal;
-    } else {  // need 'else' since not configurable in legacy HAL
-        legacy_request->cluster_low = 0x0000;
-        legacy_request->cluster_high = 0xFFFF;
-    }
-    legacy_request->config_intf_addr =
-        hidl_request.debugConfigs.validIntfAddrVal;
-    memcpy(legacy_request->intf_addr_val,
-           hidl_request.debugConfigs.intfAddrVal.data(), 6);
-    legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
-    legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
-    legacy_request->config_random_factor_force =
-        hidl_request.debugConfigs.validRandomFactorForceVal;
-    legacy_request->random_factor_force_val =
-        hidl_request.debugConfigs.randomFactorForceVal;
-    legacy_request->config_hop_count_force =
-        hidl_request.debugConfigs.validHopCountForceVal;
-    legacy_request->hop_count_force_val =
-        hidl_request.debugConfigs.hopCountForceVal;
-    legacy_request->config_24g_channel =
-        hidl_request.debugConfigs.validDiscoveryChannelVal;
-    legacy_request->channel_24g_val =
-        hidl_request.debugConfigs
-            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_channel =
-        hidl_request.debugConfigs.validDiscoveryChannelVal;
-    legacy_request->channel_5g_val =
-        hidl_request.debugConfigs
-            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_2dot4g_beacons =
-        hidl_request.debugConfigs.validUseBeaconsInBandVal;
-    legacy_request->beacon_2dot4g_val =
-        hidl_request.debugConfigs
-            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_beacons =
-        hidl_request.debugConfigs.validUseBeaconsInBandVal;
-    legacy_request->beacon_5g_val =
-        hidl_request.debugConfigs
-            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_2dot4g_sdf =
-        hidl_request.debugConfigs.validUseSdfInBandVal;
-    legacy_request->sdf_2dot4g_val =
-        hidl_request.debugConfigs
-            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_sdf =
-        hidl_request.debugConfigs.validUseSdfInBandVal;
-    legacy_request->sdf_5g_val =
-        hidl_request.debugConfigs
-            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-
-    /* TODO: b/145609058
-     * Missing updates needed to legacy_hal::NanEnableRequest and conversion to
-     * it for 6GHz band */
-
-    return true;
-}
-
-bool convertHidlNanEnableRequest_1_4ToLegacy(
-    const V1_4::NanEnableRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanEnableRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanEnableRequest_1_4ToLegacy: null legacy_request";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_discovery_beacon_int = 1;
-    legacy_request->discovery_beacon_interval =
-        hidl_request2.V1_2.discoveryBeaconIntervalMs;
-    legacy_request->config_nss = 1;
-    legacy_request->nss = hidl_request2.V1_2.numberOfSpatialStreamsInDiscovery;
-    legacy_request->config_dw_early_termination = 1;
-    legacy_request->enable_dw_termination =
-        hidl_request2.V1_2.enableDiscoveryWindowEarlyTermination;
-    legacy_request->config_enable_ranging = 1;
-    legacy_request->enable_ranging = hidl_request2.V1_2.enableRanging;
-
-    return true;
-}
-
-bool convertHidlNanEnableRequest_1_5ToLegacy(
-    const V1_4::NanEnableRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanEnableRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanEnableRequest_1_5ToLegacy: null legacy_request";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanEnableRequest_1_4ToLegacy(hidl_request1, hidl_request2,
-                                                 legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_enable_instant_mode = 1;
-    legacy_request->enable_instant_mode =
-        hidl_request2.enableInstantCommunicationMode;
-
-    return true;
-}
-
-bool convertHidlNanConfigRequest_1_5ToLegacy(
-    const V1_4::NanConfigRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanConfigRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanConfigRequest_1_5ToLegacy: null legacy_request";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanConfigRequest_1_4ToLegacy(hidl_request1, hidl_request2,
-                                                 legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_enable_instant_mode = 1;
-    legacy_request->enable_instant_mode =
-        hidl_request2.enableInstantCommunicationMode;
-
-    return true;
-}
-
-bool convertHidlNanPublishRequestToLegacy(
-    const NanPublishRequest& hidl_request,
-    legacy_hal::NanPublishRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanPublishRequestToLegacy: null legacy_request";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
-    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-    legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
-    legacy_request->service_name_len =
-        hidl_request.baseConfigs.serviceName.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
-                      "too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.baseConfigs.serviceName.data(),
-           legacy_request->service_name_len);
-    legacy_request->publish_match_indicator = convertHidlNanMatchAlgToLegacy(
-        hidl_request.baseConfigs.discoveryMatchIndicator);
-    legacy_request->service_specific_info_len =
-        hidl_request.baseConfigs.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len >
-        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.baseConfigs.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len >
-        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->rx_match_filter_len =
-        hidl_request.baseConfigs.rxMatchFilter.size();
-    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "rx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->rx_match_filter,
-           hidl_request.baseConfigs.rxMatchFilter.data(),
-           legacy_request->rx_match_filter_len);
-    legacy_request->tx_match_filter_len =
-        hidl_request.baseConfigs.txMatchFilter.size();
-    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "tx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->tx_match_filter,
-           hidl_request.baseConfigs.txMatchFilter.data(),
-           legacy_request->tx_match_filter_len);
-    legacy_request->rssi_threshold_flag =
-        hidl_request.baseConfigs.useRssiThreshold;
-    legacy_request->recv_indication_cfg = 0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
-                                                                       : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-    legacy_request->recv_indication_cfg |= 0x8;
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.baseConfigs.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR)
-                << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.baseConfigs.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.baseConfigs.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.baseConfigs.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->sdea_params.security_cfg =
-        (hidl_request.baseConfigs.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->sdea_params.ranging_state =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_ENABLE
-            : legacy_hal::NAN_RANGING_DISABLE;
-    legacy_request->ranging_cfg.ranging_interval_msec =
-        hidl_request.baseConfigs.rangingIntervalMsec;
-    legacy_request->ranging_cfg.config_ranging_indications =
-        hidl_request.baseConfigs.configRangingIndications;
-    legacy_request->ranging_cfg.distance_ingress_mm =
-        hidl_request.baseConfigs.distanceIngressCm * 10;
-    legacy_request->ranging_cfg.distance_egress_mm =
-        hidl_request.baseConfigs.distanceEgressCm * 10;
-    legacy_request->ranging_auto_response =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
-            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
-    legacy_request->sdea_params.range_report =
-        legacy_hal::NAN_DISABLE_RANGE_REPORT;
-    legacy_request->publish_type =
-        convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
-    legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
-    legacy_request->service_responder_policy =
-        hidl_request.autoAcceptDataPathRequests
-            ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
-            : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
-
-    return true;
-}
-
-bool convertHidlNanSubscribeRequestToLegacy(
-    const NanSubscribeRequest& hidl_request,
-    legacy_hal::NanSubscribeRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
-    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-    legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
-    legacy_request->service_name_len =
-        hidl_request.baseConfigs.serviceName.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.baseConfigs.serviceName.data(),
-           legacy_request->service_name_len);
-    legacy_request->subscribe_match_indicator = convertHidlNanMatchAlgToLegacy(
-        hidl_request.baseConfigs.discoveryMatchIndicator);
-    legacy_request->service_specific_info_len =
-        hidl_request.baseConfigs.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len >
-        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.baseConfigs.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len >
-        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->rx_match_filter_len =
-        hidl_request.baseConfigs.rxMatchFilter.size();
-    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "rx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->rx_match_filter,
-           hidl_request.baseConfigs.rxMatchFilter.data(),
-           legacy_request->rx_match_filter_len);
-    legacy_request->tx_match_filter_len =
-        hidl_request.baseConfigs.txMatchFilter.size();
-    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "tx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->tx_match_filter,
-           hidl_request.baseConfigs.txMatchFilter.data(),
-           legacy_request->tx_match_filter_len);
-    legacy_request->rssi_threshold_flag =
-        hidl_request.baseConfigs.useRssiThreshold;
-    legacy_request->recv_indication_cfg = 0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
-                                                                       : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.baseConfigs.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR)
-                << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.baseConfigs.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.baseConfigs.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.baseConfigs.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->sdea_params.security_cfg =
-        (hidl_request.baseConfigs.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->sdea_params.ranging_state =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_ENABLE
-            : legacy_hal::NAN_RANGING_DISABLE;
-    legacy_request->ranging_cfg.ranging_interval_msec =
-        hidl_request.baseConfigs.rangingIntervalMsec;
-    legacy_request->ranging_cfg.config_ranging_indications =
-        hidl_request.baseConfigs.configRangingIndications;
-    legacy_request->ranging_cfg.distance_ingress_mm =
-        hidl_request.baseConfigs.distanceIngressCm * 10;
-    legacy_request->ranging_cfg.distance_egress_mm =
-        hidl_request.baseConfigs.distanceEgressCm * 10;
-    legacy_request->ranging_auto_response =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
-            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
-    legacy_request->sdea_params.range_report =
-        legacy_hal::NAN_DISABLE_RANGE_REPORT;
-    legacy_request->subscribe_type =
-        convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
-    legacy_request->serviceResponseFilter =
-        convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
-    legacy_request->serviceResponseInclude =
-        hidl_request.srfRespondIfInAddressSet
-            ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
-            : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
-    legacy_request->useServiceResponseFilter =
-        hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF
-                                  : legacy_hal::NAN_DO_NOT_USE_SRF;
-    legacy_request->ssiRequiredForMatchIndication =
-        hidl_request.isSsiRequiredForMatch
-            ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
-            : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
-    legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
-    if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "num_intf_addr_present - too many";
-        return false;
-    }
-    for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
-        memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(),
-               6);
-    }
-
-    return true;
-}
-
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-    const NanTransmitFollowupRequest& hidl_request,
-    legacy_hal::NanTransmitFollowupRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
-    legacy_request->requestor_instance_id = hidl_request.peerId;
-    memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
-    legacy_request->priority = hidl_request.isHighPriority
-                                   ? legacy_hal::NAN_TX_PRIORITY_HIGH
-                                   : legacy_hal::NAN_TX_PRIORITY_NORMAL;
-    legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
-                                    ? legacy_hal::NAN_TRANSMIT_IN_DW
-                                    : legacy_hal::NAN_TRANSMIT_IN_FAW;
-    legacy_request->service_specific_info_len =
-        hidl_request.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len >
-        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-        hidl_request.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len >
-        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->recv_indication_cfg =
-        hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
-
-    return true;
-}
-
-bool convertHidlNanConfigRequestToLegacy(
-    const V1_4::NanConfigRequest& hidl_request,
-    legacy_hal::NanConfigRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
-    // defaults
-    legacy_request->master_pref = hidl_request.masterPref;
-    legacy_request->discovery_indication_cfg = 0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
-    legacy_request->config_sid_beacon = 1;
-    if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
-                      "numberOfPublishServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->sid_beacon =
-        (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
-        (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
-    legacy_request->config_subscribe_sid_beacon = 1;
-    if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
-                      "numberOfSubscribeServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->subscribe_sid_beacon_val =
-        (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
-        (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
-    legacy_request->config_rssi_window_size = 1;
-    legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
-    legacy_request->config_disc_mac_addr_randomization = 1;
-    legacy_request->disc_mac_addr_rand_interval_sec =
-        hidl_request.macAddressRandomizationIntervalSec;
-    /* TODO : missing
-    legacy_request->config_2dot4g_rssi_close = 1;
-    legacy_request->rssi_close_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
-    legacy_request->config_2dot4g_rssi_middle = 1;
-    legacy_request->rssi_middle_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
-    legacy_request->config_2dot4g_rssi_proximity = 1;
-    legacy_request->rssi_proximity_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
-    */
-    legacy_request->config_scan_params = 1;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_2dot4g_dw_band =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_2dot4g_interval_val =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .discoveryWindowIntervalVal;
-    /* TODO: missing
-    legacy_request->config_5g_rssi_close = 1;
-    legacy_request->rssi_close_5g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
-    legacy_request->config_5g_rssi_middle = 1;
-    legacy_request->rssi_middle_5g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
-    */
-    legacy_request->config_5g_rssi_close_proximity = 1;
-    legacy_request->rssi_close_proximity_5g_val =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiCloseProximity;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_5g_dw_band =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_5g_interval_val =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .discoveryWindowIntervalVal;
-    /* TODO: b/145609058
-     * Missing updates needed to legacy_hal::NanConfigRequest and conversion to
-     * it for 6GHz band */
-
-    return true;
-}
-
-bool convertHidlNanConfigRequest_1_4ToLegacy(
-    const V1_4::NanConfigRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanConfigRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanConfigRequest_1_4ToLegacy: legacy_request "
-                      "is null";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_discovery_beacon_int = 1;
-    legacy_request->discovery_beacon_interval =
-        hidl_request2.V1_2.discoveryBeaconIntervalMs;
-    legacy_request->config_nss = 1;
-    legacy_request->nss = hidl_request2.V1_2.numberOfSpatialStreamsInDiscovery;
-    legacy_request->config_dw_early_termination = 1;
-    legacy_request->enable_dw_termination =
-        hidl_request2.V1_2.enableDiscoveryWindowEarlyTermination;
-    legacy_request->config_enable_ranging = 1;
-    legacy_request->enable_ranging = hidl_request2.V1_2.enableRanging;
-
-    return true;
-}
-
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-    const NanInitiateDataPathRequest& hidl_request,
-    legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->requestor_instance_id = hidl_request.peerId;
-    memcpy(legacy_request->peer_disc_mac_addr,
-           hidl_request.peerDiscMacAddr.data(), 6);
-    legacy_request->channel_request_type =
-        convertHidlNanDataPathChannelCfgToLegacy(
-            hidl_request.channelRequestType);
-    legacy_request->channel = hidl_request.channel;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
-            IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-        (hidl_request.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-
-    return true;
-}
-
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-    const NanRespondToDataPathIndicationRequest& hidl_request,
-    legacy_hal::NanDataPathIndicationResponse* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->rsp_code = hidl_request.acceptRequest
-                                   ? legacy_hal::NAN_DP_REQUEST_ACCEPT
-                                   : legacy_hal::NAN_DP_REQUEST_REJECT;
-    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
-            IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-        (hidl_request.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-
-    return true;
-}
-
-bool convertLegacyNanResponseHeaderToHidl(
-    const legacy_hal::NanResponseMsg& legacy_response,
-    WifiNanStatus* wifiNanStatus) {
-    if (!wifiNanStatus) {
-        LOG(ERROR)
-            << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
-        return false;
-    }
-    *wifiNanStatus = {};
-
-    convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
-                           sizeof(legacy_response.nan_error), wifiNanStatus);
-    return true;
-}
-
-bool convertLegacyNanCapabilitiesResponseToHidl(
-    const legacy_hal::NanCapabilities& legacy_response,
-    NanCapabilities* hidl_response) {
-    if (!hidl_response) {
-        LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
-                      "hidl_response is null";
-        return false;
-    }
-    *hidl_response = {};
-
-    hidl_response->V1_0.maxConcurrentClusters =
-        legacy_response.max_concurrent_nan_clusters;
-    hidl_response->V1_0.maxPublishes = legacy_response.max_publishes;
-    hidl_response->V1_0.maxSubscribes = legacy_response.max_subscribes;
-    hidl_response->V1_0.maxServiceNameLen =
-        legacy_response.max_service_name_len;
-    hidl_response->V1_0.maxMatchFilterLen =
-        legacy_response.max_match_filter_len;
-    hidl_response->V1_0.maxTotalMatchFilterLen =
-        legacy_response.max_total_match_filter_len;
-    hidl_response->V1_0.maxServiceSpecificInfoLen =
-        legacy_response.max_service_specific_info_len;
-    hidl_response->V1_0.maxExtendedServiceSpecificInfoLen =
-        legacy_response.max_sdea_service_specific_info_len;
-    hidl_response->V1_0.maxNdiInterfaces = legacy_response.max_ndi_interfaces;
-    hidl_response->V1_0.maxNdpSessions = legacy_response.max_ndp_sessions;
-    hidl_response->V1_0.maxAppInfoLen = legacy_response.max_app_info_len;
-    hidl_response->V1_0.maxQueuedTransmitFollowupMsgs =
-        legacy_response.max_queued_transmit_followup_msgs;
-    hidl_response->V1_0.maxSubscribeInterfaceAddresses =
-        legacy_response.max_subscribe_address;
-    hidl_response->V1_0.supportedCipherSuites =
-        legacy_response.cipher_suites_supported;
-    hidl_response->instantCommunicationModeSupportFlag =
-        legacy_response.is_instant_mode_supported;
-
-    return true;
-}
-
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
-                                    NanMatchInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-    hidl_ind->peerId = legacy_ind.requestor_instance_id;
-    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-    hidl_ind->serviceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.service_specific_info,
-                             legacy_ind.service_specific_info +
-                                 legacy_ind.service_specific_info_len);
-    hidl_ind->extendedServiceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
-                             legacy_ind.sdea_service_specific_info +
-                                 legacy_ind.sdea_service_specific_info_len);
-    hidl_ind->matchFilter = std::vector<uint8_t>(
-        legacy_ind.sdf_match_filter,
-        legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
-    hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
-    hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
-    hidl_ind->rssiValue = legacy_ind.rssi_value;
-    hidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type;
-    hidl_ind->peerRequiresSecurityEnabledInNdp =
-        legacy_ind.peer_sdea_params.security_cfg ==
-        legacy_hal::NAN_DP_CONFIG_SECURITY;
-    hidl_ind->peerRequiresRanging = legacy_ind.peer_sdea_params.ranging_state ==
-                                    legacy_hal::NAN_RANGING_ENABLE;
-    hidl_ind->rangingMeasurementInCm =
-        legacy_ind.range_info.range_measurement_mm / 10;
-    hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
-
-    return true;
-}
-
-bool convertLegacyNanFollowupIndToHidl(
-    const legacy_hal::NanFollowupInd& legacy_ind,
-    NanFollowupReceivedInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-    hidl_ind->peerId = legacy_ind.requestor_instance_id;
-    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-    hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
-    hidl_ind->serviceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.service_specific_info,
-                             legacy_ind.service_specific_info +
-                                 legacy_ind.service_specific_info_len);
-    hidl_ind->extendedServiceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
-                             legacy_ind.sdea_service_specific_info +
-                                 legacy_ind.sdea_service_specific_info_len);
-
-    return true;
-}
-
-bool convertLegacyNanDataPathRequestIndToHidl(
-    const legacy_hal::NanDataPathRequestInd& legacy_ind,
-    NanDataPathRequestInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR)
-            << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
-    hidl_ind->peerDiscMacAddr =
-        hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
-    hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
-    hidl_ind->securityRequired =
-        legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
-    hidl_ind->appInfo =
-        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
-                             legacy_ind.app_info.ndp_app_info +
-                                 legacy_ind.app_info.ndp_app_info_len);
-
-    return true;
-}
-
-bool convertLegacyNdpChannelInfoToHidl(
-    const legacy_hal::NanChannelInfo& legacy_struct,
-    V1_2::NanDataPathChannelInfo* hidl_struct) {
-    if (!hidl_struct) {
-        LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
-        return false;
-    }
-    *hidl_struct = {};
-
-    hidl_struct->channelFreq = legacy_struct.channel;
-    hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
-        (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
-    hidl_struct->numSpatialStreams = legacy_struct.nss;
-
-    return true;
-}
-
-bool convertLegacyNanDataPathConfirmIndToHidl(
-    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    V1_2::NanDataPathConfirmInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR)
-            << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
-    hidl_ind->V1_0.dataPathSetupSuccess =
-        legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
-    hidl_ind->V1_0.peerNdiMacAddr =
-        hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
-    hidl_ind->V1_0.appInfo =
-        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
-                             legacy_ind.app_info.ndp_app_info +
-                                 legacy_ind.app_info.ndp_app_info_len);
-    hidl_ind->V1_0.status.status =
-        convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
-    hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
-
-    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
-    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        V1_2::NanDataPathChannelInfo hidl_struct;
-        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
-                                               &hidl_struct)) {
-            return false;
-        }
-        channelInfo.push_back(hidl_struct);
-    }
-    hidl_ind->channelInfo = channelInfo;
-
-    return true;
-}
-
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
-    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-    V1_2::NanDataPathScheduleUpdateInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
-                      "hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->peerDiscoveryAddress =
-        hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
-    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
-    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        V1_2::NanDataPathChannelInfo hidl_struct;
-        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
-                                               &hidl_struct)) {
-            return false;
-        }
-        channelInfo.push_back(hidl_struct);
-    }
-    hidl_ind->channelInfo = channelInfo;
-    std::vector<uint32_t> ndpInstanceIds;
-    for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
-        ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
-    }
-    hidl_ind->ndpInstanceIds = ndpInstanceIds;
-
-    return true;
-}
-
-legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
-    switch (type) {
-        case RttType::ONE_SIDED:
-            return legacy_hal::RTT_TYPE_1_SIDED;
-        case RttType::TWO_SIDED:
-            return legacy_hal::RTT_TYPE_2_SIDED;
-    };
-    CHECK(false);
-}
-
-RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
-    switch (type) {
-        case legacy_hal::RTT_TYPE_1_SIDED:
-            return RttType::ONE_SIDED;
-        case legacy_hal::RTT_TYPE_2_SIDED:
-            return RttType::TWO_SIDED;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
-    switch (type) {
-        case RttPeerType::AP:
-            return legacy_hal::RTT_PEER_AP;
-        case RttPeerType::STA:
-            return legacy_hal::RTT_PEER_STA;
-        case RttPeerType::P2P_GO:
-            return legacy_hal::RTT_PEER_P2P_GO;
-        case RttPeerType::P2P_CLIENT:
-            return legacy_hal::RTT_PEER_P2P_CLIENT;
-        case RttPeerType::NAN:
-            return legacy_hal::RTT_PEER_NAN;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
-    WifiChannelWidthInMhz type) {
-    switch (type) {
-        case WifiChannelWidthInMhz::WIDTH_20:
-            return legacy_hal::WIFI_CHAN_WIDTH_20;
-        case WifiChannelWidthInMhz::WIDTH_40:
-            return legacy_hal::WIFI_CHAN_WIDTH_40;
-        case WifiChannelWidthInMhz::WIDTH_80:
-            return legacy_hal::WIFI_CHAN_WIDTH_80;
-        case WifiChannelWidthInMhz::WIDTH_160:
-            return legacy_hal::WIFI_CHAN_WIDTH_160;
-        case WifiChannelWidthInMhz::WIDTH_80P80:
-            return legacy_hal::WIFI_CHAN_WIDTH_80P80;
-        case WifiChannelWidthInMhz::WIDTH_5:
-            return legacy_hal::WIFI_CHAN_WIDTH_5;
-        case WifiChannelWidthInMhz::WIDTH_10:
-            return legacy_hal::WIFI_CHAN_WIDTH_10;
-        case WifiChannelWidthInMhz::WIDTH_INVALID:
-            return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
-    };
-    CHECK(false);
-}
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
-    legacy_hal::wifi_channel_width type) {
-    switch (type) {
-        case legacy_hal::WIFI_CHAN_WIDTH_20:
-            return WifiChannelWidthInMhz::WIDTH_20;
-        case legacy_hal::WIFI_CHAN_WIDTH_40:
-            return WifiChannelWidthInMhz::WIDTH_40;
-        case legacy_hal::WIFI_CHAN_WIDTH_80:
-            return WifiChannelWidthInMhz::WIDTH_80;
-        case legacy_hal::WIFI_CHAN_WIDTH_160:
-            return WifiChannelWidthInMhz::WIDTH_160;
-        case legacy_hal::WIFI_CHAN_WIDTH_80P80:
-            return WifiChannelWidthInMhz::WIDTH_80P80;
-        case legacy_hal::WIFI_CHAN_WIDTH_5:
-            return WifiChannelWidthInMhz::WIDTH_5;
-        case legacy_hal::WIFI_CHAN_WIDTH_10:
-            return WifiChannelWidthInMhz::WIDTH_10;
-        default:
-            return WifiChannelWidthInMhz::WIDTH_INVALID;
-    };
-}
-
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(
-    V1_4::RttPreamble type) {
-    switch (type) {
-        case V1_4::RttPreamble::LEGACY:
-            return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
-        case V1_4::RttPreamble::HT:
-            return legacy_hal::WIFI_RTT_PREAMBLE_HT;
-        case V1_4::RttPreamble::VHT:
-            return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
-        case V1_4::RttPreamble::HE:
-            return legacy_hal::WIFI_RTT_PREAMBLE_HE;
-    };
-    CHECK(false);
-}
-
-V1_4::RttPreamble convertLegacyRttPreambleToHidl(
-    legacy_hal::wifi_rtt_preamble type) {
-    switch (type) {
-        case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
-            return V1_4::RttPreamble::LEGACY;
-        case legacy_hal::WIFI_RTT_PREAMBLE_HT:
-            return V1_4::RttPreamble::HT;
-        case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
-            return V1_4::RttPreamble::VHT;
-        case legacy_hal::WIFI_RTT_PREAMBLE_HE:
-            return V1_4::RttPreamble::HE;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
-    switch (type) {
-        case RttBw::BW_5MHZ:
-            return legacy_hal::WIFI_RTT_BW_5;
-        case RttBw::BW_10MHZ:
-            return legacy_hal::WIFI_RTT_BW_10;
-        case RttBw::BW_20MHZ:
-            return legacy_hal::WIFI_RTT_BW_20;
-        case RttBw::BW_40MHZ:
-            return legacy_hal::WIFI_RTT_BW_40;
-        case RttBw::BW_80MHZ:
-            return legacy_hal::WIFI_RTT_BW_80;
-        case RttBw::BW_160MHZ:
-            return legacy_hal::WIFI_RTT_BW_160;
-    };
-    CHECK(false);
-}
-
-RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
-    switch (type) {
-        case legacy_hal::WIFI_RTT_BW_5:
-            return RttBw::BW_5MHZ;
-        case legacy_hal::WIFI_RTT_BW_10:
-            return RttBw::BW_10MHZ;
-        case legacy_hal::WIFI_RTT_BW_20:
-            return RttBw::BW_20MHZ;
-        case legacy_hal::WIFI_RTT_BW_40:
-            return RttBw::BW_40MHZ;
-        case legacy_hal::WIFI_RTT_BW_80:
-            return RttBw::BW_80MHZ;
-        case legacy_hal::WIFI_RTT_BW_160:
-            return RttBw::BW_160MHZ;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
-    RttMotionPattern type) {
-    switch (type) {
-        case RttMotionPattern::NOT_EXPECTED:
-            return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
-        case RttMotionPattern::EXPECTED:
-            return legacy_hal::WIFI_MOTION_EXPECTED;
-        case RttMotionPattern::UNKNOWN:
-            return legacy_hal::WIFI_MOTION_UNKNOWN;
-    };
-    CHECK(false);
-}
-
-V1_4::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
-    switch (preamble) {
-        case 0:
-            return V1_4::WifiRatePreamble::OFDM;
-        case 1:
-            return V1_4::WifiRatePreamble::CCK;
-        case 2:
-            return V1_4::WifiRatePreamble::HT;
-        case 3:
-            return V1_4::WifiRatePreamble::VHT;
-        case 4:
-            return V1_4::WifiRatePreamble::HE;
-        default:
-            return V1_4::WifiRatePreamble::RESERVED;
-    };
-    CHECK(false) << "Unknown legacy preamble: " << preamble;
-}
-
-WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
-    switch (nss) {
-        case 0:
-            return WifiRateNss::NSS_1x1;
-        case 1:
-            return WifiRateNss::NSS_2x2;
-        case 2:
-            return WifiRateNss::NSS_3x3;
-        case 3:
-            return WifiRateNss::NSS_4x4;
-    };
-    CHECK(false) << "Unknown legacy nss: " << nss;
-    return {};
-}
-
-RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
-    switch (status) {
-        case legacy_hal::RTT_STATUS_SUCCESS:
-            return RttStatus::SUCCESS;
-        case legacy_hal::RTT_STATUS_FAILURE:
-            return RttStatus::FAILURE;
-        case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
-            return RttStatus::FAIL_NO_RSP;
-        case legacy_hal::RTT_STATUS_FAIL_REJECTED:
-            return RttStatus::FAIL_REJECTED;
-        case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
-            return RttStatus::FAIL_NOT_SCHEDULED_YET;
-        case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
-            return RttStatus::FAIL_TM_TIMEOUT;
-        case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
-            return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
-        case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
-            return RttStatus::FAIL_NO_CAPABILITY;
-        case legacy_hal::RTT_STATUS_ABORTED:
-            return RttStatus::ABORTED;
-        case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
-            return RttStatus::FAIL_INVALID_TS;
-        case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
-            return RttStatus::FAIL_PROTOCOL;
-        case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
-            return RttStatus::FAIL_SCHEDULE;
-        case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
-            return RttStatus::FAIL_BUSY_TRY_LATER;
-        case legacy_hal::RTT_STATUS_INVALID_REQ:
-            return RttStatus::INVALID_REQ;
-        case legacy_hal::RTT_STATUS_NO_WIFI:
-            return RttStatus::NO_WIFI;
-        case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
-            return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
-        case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
-            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
-        case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
-            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
-    };
-    CHECK(false) << "Unknown legacy status: " << status;
-}
-
-bool convertHidlWifiChannelInfoToLegacy(
-    const WifiChannelInfo& hidl_info,
-    legacy_hal::wifi_channel_info* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
-    legacy_info->center_freq = hidl_info.centerFreq;
-    legacy_info->center_freq0 = hidl_info.centerFreq0;
-    legacy_info->center_freq1 = hidl_info.centerFreq1;
-    return true;
-}
-
-bool convertLegacyWifiChannelInfoToHidl(
-    const legacy_hal::wifi_channel_info& legacy_info,
-    WifiChannelInfo* hidl_info) {
-    if (!hidl_info) {
-        return false;
-    }
-    *hidl_info = {};
-    hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
-    hidl_info->centerFreq = legacy_info.center_freq;
-    hidl_info->centerFreq0 = legacy_info.center_freq0;
-    hidl_info->centerFreq1 = legacy_info.center_freq1;
-    return true;
-}
-
-bool convertHidlRttConfigToLegacy(const V1_4::RttConfig& hidl_config,
-                                  legacy_hal::wifi_rtt_config* legacy_config) {
-    if (!legacy_config) {
-        return false;
-    }
-    *legacy_config = {};
-    CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
-    memcpy(legacy_config->addr, hidl_config.addr.data(),
-           hidl_config.addr.size());
-    legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
-    legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
-    if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
-                                            &legacy_config->channel)) {
-        return false;
-    }
-    legacy_config->burst_period = hidl_config.burstPeriod;
-    legacy_config->num_burst = hidl_config.numBurst;
-    legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
-    legacy_config->num_retries_per_rtt_frame =
-        hidl_config.numRetriesPerRttFrame;
-    legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
-    legacy_config->LCI_request = hidl_config.mustRequestLci;
-    legacy_config->LCR_request = hidl_config.mustRequestLcr;
-    legacy_config->burst_duration = hidl_config.burstDuration;
-    legacy_config->preamble =
-        convertHidlRttPreambleToLegacy(hidl_config.preamble);
-    legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
-    return true;
-}
-
-bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<V1_4::RttConfig>& hidl_configs,
-    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
-    if (!legacy_configs) {
-        return false;
-    }
-    *legacy_configs = {};
-    for (const auto& hidl_config : hidl_configs) {
-        legacy_hal::wifi_rtt_config legacy_config;
-        if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
-            return false;
-        }
-        legacy_configs->push_back(legacy_config);
-    }
-    return true;
-}
-
-bool convertHidlRttLciInformationToLegacy(
-    const RttLciInformation& hidl_info,
-    legacy_hal::wifi_lci_information* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    legacy_info->latitude = hidl_info.latitude;
-    legacy_info->longitude = hidl_info.longitude;
-    legacy_info->altitude = hidl_info.altitude;
-    legacy_info->latitude_unc = hidl_info.latitudeUnc;
-    legacy_info->longitude_unc = hidl_info.longitudeUnc;
-    legacy_info->altitude_unc = hidl_info.altitudeUnc;
-    legacy_info->motion_pattern =
-        convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
-    legacy_info->floor = hidl_info.floor;
-    legacy_info->height_above_floor = hidl_info.heightAboveFloor;
-    legacy_info->height_unc = hidl_info.heightUnc;
-    return true;
-}
-
-bool convertHidlRttLcrInformationToLegacy(
-    const RttLcrInformation& hidl_info,
-    legacy_hal::wifi_lcr_information* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
-    memcpy(legacy_info->country_code, hidl_info.countryCode.data(),
-           hidl_info.countryCode.size());
-    if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
-        return false;
-    }
-    legacy_info->length = hidl_info.civicInfo.size();
-    memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(),
-           hidl_info.civicInfo.size());
-    return true;
-}
-
-bool convertHidlRttResponderToLegacy(
-    const V1_4::RttResponder& hidl_responder,
-    legacy_hal::wifi_rtt_responder* legacy_responder) {
-    if (!legacy_responder) {
-        return false;
-    }
-    *legacy_responder = {};
-    if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
-                                            &legacy_responder->channel)) {
-        return false;
-    }
-    legacy_responder->preamble =
-        convertHidlRttPreambleToLegacy(hidl_responder.preamble);
-    return true;
-}
-
-bool convertLegacyRttResponderToHidl(
-    const legacy_hal::wifi_rtt_responder& legacy_responder,
-    V1_4::RttResponder* hidl_responder) {
-    if (!hidl_responder) {
-        return false;
-    }
-    *hidl_responder = {};
-    if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
-                                            &hidl_responder->channel)) {
-        return false;
-    }
-    hidl_responder->preamble =
-        convertLegacyRttPreambleToHidl(legacy_responder.preamble);
-    return true;
-}
-
-bool convertLegacyRttCapabilitiesToHidl(
-    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    V1_4::RttCapabilities* hidl_capabilities) {
-    if (!hidl_capabilities) {
-        return false;
-    }
-    *hidl_capabilities = {};
-    hidl_capabilities->rttOneSidedSupported =
-        legacy_capabilities.rtt_one_sided_supported;
-    hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
-    hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
-    hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
-    hidl_capabilities->responderSupported =
-        legacy_capabilities.responder_supported;
-    hidl_capabilities->preambleSupport = 0;
-    for (const auto flag :
-         {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
-          legacy_hal::WIFI_RTT_PREAMBLE_HT, legacy_hal::WIFI_RTT_PREAMBLE_VHT,
-          legacy_hal::WIFI_RTT_PREAMBLE_HE}) {
-        if (legacy_capabilities.preamble_support & flag) {
-            hidl_capabilities->preambleSupport |=
-                static_cast<std::underlying_type<V1_4::RttPreamble>::type>(
-                    convertLegacyRttPreambleToHidl(flag));
-        }
-    }
-    hidl_capabilities->bwSupport = 0;
-    for (const auto flag :
-         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10,
-          legacy_hal::WIFI_RTT_BW_20, legacy_hal::WIFI_RTT_BW_40,
-          legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160}) {
-        if (legacy_capabilities.bw_support & flag) {
-            hidl_capabilities->bwSupport |=
-                static_cast<std::underlying_type<RttBw>::type>(
-                    convertLegacyRttBwToHidl(flag));
-        }
-    }
-    hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
-    return true;
-}
-
-bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
-                                     V1_4::WifiRateInfo* hidl_rate) {
-    if (!hidl_rate) {
-        return false;
-    }
-    *hidl_rate = {};
-    hidl_rate->preamble =
-        convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
-    hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
-    hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
-        static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
-    hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
-    hidl_rate->bitRateInKbps = legacy_rate.bitrate;
-    return true;
-}
-
-bool convertLegacyRttResultToHidl(
-    const legacy_hal::wifi_rtt_result& legacy_result,
-    V1_4::RttResult* hidl_result) {
-    if (!hidl_result) {
-        return false;
-    }
-    *hidl_result = {};
-    CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
-    memcpy(hidl_result->addr.data(), legacy_result.addr,
-           sizeof(legacy_result.addr));
-    hidl_result->burstNum = legacy_result.burst_num;
-    hidl_result->measurementNumber = legacy_result.measurement_number;
-    hidl_result->successNumber = legacy_result.success_number;
-    hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
-    hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
-    hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
-    hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
-    hidl_result->rssi = legacy_result.rssi;
-    hidl_result->rssiSpread = legacy_result.rssi_spread;
-    if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
-                                         &hidl_result->txRate)) {
-        return false;
-    }
-    if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
-                                         &hidl_result->rxRate)) {
-        return false;
-    }
-    hidl_result->rtt = legacy_result.rtt;
-    hidl_result->rttSd = legacy_result.rtt_sd;
-    hidl_result->rttSpread = legacy_result.rtt_spread;
-    hidl_result->distanceInMm = legacy_result.distance_mm;
-    hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
-    hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
-    hidl_result->timeStampInUs = legacy_result.ts;
-    hidl_result->burstDurationInMs = legacy_result.burst_duration;
-    hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
-    if (legacy_result.LCI &&
-        !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
-        return false;
-    }
-    if (legacy_result.LCR &&
-        !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
-        return false;
-    }
-    return true;
-}
-
-bool convertLegacyVectorOfRttResultToHidl(
-    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<V1_4::RttResult>* hidl_results) {
-    if (!hidl_results) {
-        return false;
-    }
-    *hidl_results = {};
-    for (const auto legacy_result : legacy_results) {
-        V1_4::RttResult hidl_result;
-        if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
-            return false;
-        }
-        hidl_results->push_back(hidl_result);
-    }
-    return true;
-}
-
-legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
-    IfaceType hidl_interface_type) {
-    switch (hidl_interface_type) {
-        case IfaceType::STA:
-            return legacy_hal::WIFI_INTERFACE_TYPE_STA;
-        case IfaceType::AP:
-            return legacy_hal::WIFI_INTERFACE_TYPE_AP;
-        case IfaceType::P2P:
-            return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
-        case IfaceType::NAN:
-            return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
-    }
-    CHECK(false);
-}
-
-legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
-    IWifiChip::MultiStaUseCase use_case) {
-    switch (use_case) {
-        case IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY:
-            return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
-        case IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED:
-            return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
-    }
-    CHECK(false);
-}
-
-bool convertHidlCoexUnsafeChannelToLegacy(
-    const IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
-    legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) {
-    if (!legacy_unsafe_channel) {
-        return false;
-    }
-    *legacy_unsafe_channel = {};
-    switch (hidl_unsafe_channel.band) {
-        case WifiBand::BAND_24GHZ:
-            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND;
-            break;
-        case WifiBand::BAND_5GHZ:
-            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND;
-            break;
-        default:
-            return false;
-    };
-    legacy_unsafe_channel->channel = hidl_unsafe_channel.channel;
-    legacy_unsafe_channel->power_cap_dbm = hidl_unsafe_channel.powerCapDbm;
-    return true;
-}
-
-bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
-    const std::vector<IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
-    std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels) {
-    if (!legacy_unsafe_channels) {
-        return false;
-    }
-    *legacy_unsafe_channels = {};
-    for (const auto& hidl_unsafe_channel : hidl_unsafe_channels) {
-        legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel;
-        if (!hidl_struct_util::convertHidlCoexUnsafeChannelToLegacy(
-                hidl_unsafe_channel, &legacy_unsafe_channel)) {
-            return false;
-        }
-        legacy_unsafe_channels->push_back(legacy_unsafe_channel);
-    }
-    return true;
-}
-
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
deleted file mode 100644
index 352f213..0000000
--- a/wifi/1.5/default/hidl_struct_util.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_STRUCT_UTIL_H_
-#define HIDL_STRUCT_UTIL_H_
-
-#include <vector>
-
-#include <android/hardware/wifi/1.0/IWifiChip.h>
-#include <android/hardware/wifi/1.0/types.h>
-#include <android/hardware/wifi/1.2/types.h>
-#include <android/hardware/wifi/1.3/types.h>
-#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
-#include <android/hardware/wifi/1.4/types.h>
-#include <android/hardware/wifi/1.5/IWifiChip.h>
-#include <android/hardware/wifi/1.5/types.h>
-
-#include "wifi_legacy_hal.h"
-
-/**
- * This file contains a bunch of functions to convert structs from the legacy
- * HAL to HIDL and vice versa.
- * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
- * suite.
- */
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace hidl_struct_util {
-using namespace android::hardware::wifi::V1_0;
-
-// Chip conversion methods.
-bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps);
-bool convertLegacyDebugRingBufferStatusToHidl(
-    const legacy_hal::wifi_ring_buffer_status& legacy_status,
-    WifiDebugRingBufferStatus* hidl_status);
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
-bool convertLegacyWakeReasonStatsToHidl(
-    const legacy_hal::WakeReasonStats& legacy_stats,
-    WifiDebugHostWakeReasonStats* hidl_stats);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-    V1_1::IWifiChip::TxPowerScenario hidl_scenario);
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
-    V1_3::IWifiChip::LatencyMode hidl_latency_mode);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-    V1_2::IWifiChip::TxPowerScenario hidl_scenario);
-bool convertLegacyWifiMacInfosToHidl(
-    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>*
-        hidl_radio_mode_infos);
-legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
-    IfaceType hidl_interface_type);
-legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
-    IWifiChip::MultiStaUseCase use_case);
-bool convertHidlCoexUnsafeChannelToLegacy(
-    const IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
-    legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
-bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
-    const std::vector<IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
-    std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
-
-// STA iface conversion methods.
-bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps);
-bool convertLegacyApfCapabilitiesToHidl(
-    const legacy_hal::PacketFilterCapabilities& legacy_caps,
-    StaApfPacketFilterCapabilities* hidl_caps);
-bool convertLegacyGscanCapabilitiesToHidl(
-    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-    StaBackgroundScanCapabilities* hidl_caps);
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band);
-bool convertHidlGscanParamsToLegacy(
-    const StaBackgroundScanParameters& hidl_scan_params,
-    legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
-// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
-// Information Elements (IEs)
-bool convertLegacyGscanResultToHidl(
-    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
-    StaScanResult* hidl_scan_result);
-// |cached_results| is assumed to not include IEs.
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-    const std::vector<legacy_hal::wifi_cached_scan_results>&
-        legacy_cached_scan_results,
-    std::vector<StaScanData>* hidl_scan_datas);
-bool convertLegacyLinkLayerStatsToHidl(
-    const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats);
-bool convertLegacyRoamingCapabilitiesToHidl(
-    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-    StaRoamingCapabilities* hidl_caps);
-bool convertHidlRoamingConfigToLegacy(
-    const StaRoamingConfig& hidl_config,
-    legacy_hal::wifi_roaming_config* legacy_config);
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
-    StaRoamingState state);
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-    std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-    std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
-
-// NAN iface conversion methods.
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
-                            size_t max_len, WifiNanStatus* wifiNanStatus);
-bool convertHidlNanEnableRequestToLegacy(
-    const V1_4::NanEnableRequest& hidl_request,
-    legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequestToLegacy(
-    const V1_4::NanConfigRequest& hidl_request,
-    legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanEnableRequest_1_4ToLegacy(
-    const V1_4::NanEnableRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequest_1_4ToLegacy(
-    const V1_4::NanConfigRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanEnableRequest_1_5ToLegacy(
-    const V1_4::NanEnableRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequest_1_5ToLegacy(
-    const V1_4::NanConfigRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanPublishRequestToLegacy(
-    const NanPublishRequest& hidl_request,
-    legacy_hal::NanPublishRequest* legacy_request);
-bool convertHidlNanSubscribeRequestToLegacy(
-    const NanSubscribeRequest& hidl_request,
-    legacy_hal::NanSubscribeRequest* legacy_request);
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-    const NanTransmitFollowupRequest& hidl_request,
-    legacy_hal::NanTransmitFollowupRequest* legacy_request);
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-    const NanInitiateDataPathRequest& hidl_request,
-    legacy_hal::NanDataPathInitiatorRequest* legacy_request);
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-    const NanRespondToDataPathIndicationRequest& hidl_response,
-    legacy_hal::NanDataPathIndicationResponse* legacy_response);
-bool convertLegacyNanResponseHeaderToHidl(
-    const legacy_hal::NanResponseMsg& legacy_response,
-    WifiNanStatus* wifiNanStatus);
-bool convertLegacyNanCapabilitiesResponseToHidl(
-    const legacy_hal::NanCapabilities& legacy_response,
-    NanCapabilities* hidl_response);
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
-                                    NanMatchInd* hidl_ind);
-bool convertLegacyNanFollowupIndToHidl(
-    const legacy_hal::NanFollowupInd& legacy_ind,
-    NanFollowupReceivedInd* hidl_ind);
-bool convertLegacyNanDataPathRequestIndToHidl(
-    const legacy_hal::NanDataPathRequestInd& legacy_ind,
-    NanDataPathRequestInd* hidl_ind);
-bool convertLegacyNanDataPathConfirmIndToHidl(
-    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    V1_2::NanDataPathConfirmInd* hidl_ind);
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
-    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-    V1_2::NanDataPathScheduleUpdateInd* hidl_ind);
-
-// RTT controller conversion methods.
-bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<V1_4::RttConfig>& hidl_configs,
-    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
-bool convertHidlRttLciInformationToLegacy(
-    const RttLciInformation& hidl_info,
-    legacy_hal::wifi_lci_information* legacy_info);
-bool convertHidlRttLcrInformationToLegacy(
-    const RttLcrInformation& hidl_info,
-    legacy_hal::wifi_lcr_information* legacy_info);
-bool convertHidlRttResponderToLegacy(
-    const V1_4::RttResponder& hidl_responder,
-    legacy_hal::wifi_rtt_responder* legacy_responder);
-bool convertHidlWifiChannelInfoToLegacy(
-    const WifiChannelInfo& hidl_info,
-    legacy_hal::wifi_channel_info* legacy_info);
-bool convertLegacyRttResponderToHidl(
-    const legacy_hal::wifi_rtt_responder& legacy_responder,
-    V1_4::RttResponder* hidl_responder);
-bool convertLegacyRttCapabilitiesToHidl(
-    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    V1_4::RttCapabilities* hidl_capabilities);
-bool convertLegacyVectorOfRttResultToHidl(
-    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<V1_4::RttResult>* hidl_results);
-uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand band);
-uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask);
-uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask);
-bool convertLegacyWifiUsableChannelsToHidl(
-    const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
-    std::vector<V1_5::WifiUsableChannel>* hidl_usable_channels);
-bool convertLegacyPeerInfoStatsToHidl(
-    const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
-    StaPeerInfo* hidl_peer_info_stats);
-bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
-                                     V1_4::WifiRateInfo* hidl_rate);
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.5/default/hidl_sync_util.cpp b/wifi/1.5/default/hidl_sync_util.cpp
deleted file mode 100644
index 93eefe9..0000000
--- a/wifi/1.5/default/hidl_sync_util.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 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 "hidl_sync_util.h"
-
-namespace {
-std::recursive_mutex g_mutex;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace hidl_sync_util {
-
-std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
-    return std::unique_lock<std::recursive_mutex>{g_mutex};
-}
-
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/hidl_sync_util.h b/wifi/1.5/default/hidl_sync_util.h
deleted file mode 100644
index e706f4c..0000000
--- a/wifi/1.5/default/hidl_sync_util.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_SYNC_UTIL_H_
-#define HIDL_SYNC_UTIL_H_
-
-#include <mutex>
-
-// Utility that provides a global lock to synchronize access between
-// the HIDL thread and the legacy HAL's event loop.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace hidl_sync_util {
-std::unique_lock<std::recursive_mutex> acquireGlobalLock();
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.5/default/ringbuffer.cpp b/wifi/1.5/default/ringbuffer.cpp
deleted file mode 100644
index f554111..0000000
--- a/wifi/1.5/default/ringbuffer.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2018 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 <android-base/logging.h>
-
-#include "ringbuffer.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
-
-void Ringbuffer::append(const std::vector<uint8_t>& input) {
-    if (input.size() == 0) {
-        return;
-    }
-    if (input.size() > maxSize_) {
-        LOG(INFO) << "Oversized message of " << input.size()
-                  << " bytes is dropped";
-        return;
-    }
-    data_.push_back(input);
-    size_ += input.size() * sizeof(input[0]);
-    while (size_ > maxSize_) {
-        size_ -= data_.front().size() * sizeof(data_.front()[0]);
-        data_.pop_front();
-    }
-}
-
-const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
-    return data_;
-}
-
-void Ringbuffer::clear() {
-    data_.clear();
-    size_ = 0;
-}
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/ringbuffer.h b/wifi/1.5/default/ringbuffer.h
deleted file mode 100644
index 03fb37a..0000000
--- a/wifi/1.5/default/ringbuffer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RINGBUFFER_H_
-#define RINGBUFFER_H_
-
-#include <list>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-/**
- * Ringbuffer object used to store debug data.
- */
-class Ringbuffer {
-   public:
-    explicit Ringbuffer(size_t maxSize);
-
-    // Appends the data buffer and deletes from the front until buffer is
-    // within |maxSize_|.
-    void append(const std::vector<uint8_t>& input);
-    const std::list<std::vector<uint8_t>>& getData() const;
-    void clear();
-
-   private:
-    std::list<std::vector<uint8_t>> data_;
-    size_t size_;
-    size_t maxSize_;
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // RINGBUFFER_H_
diff --git a/wifi/1.5/default/service.cpp b/wifi/1.5/default/service.cpp
deleted file mode 100644
index 3de49b2..0000000
--- a/wifi/1.5/default/service.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-#include <hidl/HidlLazyUtils.h>
-#include <hidl/HidlTransportSupport.h>
-#include <signal.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
-
-#include "wifi.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_legacy_hal_factory.h"
-#include "wifi_mode_controller.h"
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::LazyServiceRegistrar;
-using android::hardware::wifi::V1_5::implementation::feature_flags::
-    WifiFeatureFlags;
-using android::hardware::wifi::V1_5::implementation::legacy_hal::WifiLegacyHal;
-using android::hardware::wifi::V1_5::implementation::legacy_hal::
-    WifiLegacyHalFactory;
-using android::hardware::wifi::V1_5::implementation::mode_controller::
-    WifiModeController;
-
-#ifdef LAZY_SERVICE
-const bool kLazyService = true;
-#else
-const bool kLazyService = false;
-#endif
-
-int main(int /*argc*/, char** argv) {
-    signal(SIGPIPE, SIG_IGN);
-    android::base::InitLogging(
-        argv, android::base::LogdLogger(android::base::SYSTEM));
-    LOG(INFO) << "Wifi Hal is booting up...";
-
-    configureRpcThreadpool(1, true /* callerWillJoin */);
-
-    const auto iface_tool =
-        std::make_shared<android::wifi_system::InterfaceTool>();
-    const auto legacy_hal_factory =
-        std::make_shared<WifiLegacyHalFactory>(iface_tool);
-
-    // Setup hwbinder service
-    android::sp<android::hardware::wifi::V1_5::IWifi> service =
-        new android::hardware::wifi::V1_5::implementation::Wifi(
-            iface_tool, legacy_hal_factory,
-            std::make_shared<WifiModeController>(),
-            std::make_shared<WifiFeatureFlags>());
-    if (kLazyService) {
-        auto registrar = LazyServiceRegistrar::getInstance();
-        CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
-            << "Failed to register wifi HAL";
-    } else {
-        CHECK_EQ(service->registerAsService(), android::NO_ERROR)
-            << "Failed to register wifi HAL";
-    }
-
-    joinRpcThreadpool();
-
-    LOG(INFO) << "Wifi Hal is terminating...";
-    return 0;
-}
diff --git a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
deleted file mode 100644
index 4b4ebd6..0000000
--- a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2017, 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 <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "hidl_struct_util.h"
-
-using testing::Test;
-
-namespace {
-constexpr uint32_t kMacId1 = 1;
-constexpr uint32_t kMacId2 = 2;
-constexpr uint32_t kIfaceChannel1 = 3;
-constexpr uint32_t kIfaceChannel2 = 5;
-constexpr char kIfaceName1[] = "wlan0";
-constexpr char kIfaceName2[] = "wlan1";
-}  // namespace
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
-
-class HidlStructUtilTest : public Test {};
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {
-        .wlan_mac_id = kMacId1,
-        .mac_band =
-            legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
-                                                    .channel = kIfaceChannel1};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
-                                                    .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-
-    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>
-        hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-        legacy_mac_infos, &hidl_radio_mode_infos));
-
-    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
-    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
-    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
-    EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
-    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
-              hidl_iface_info1.channel);
-    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
-              hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {
-        .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
-                                                    .channel = kIfaceChannel1};
-    legacy_hal::WifiMacInfo legacy_mac_info2 = {
-        .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
-                                                    .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info2);
-
-    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>
-        hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-        legacy_mac_infos, &hidl_radio_mode_infos));
-
-    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
-
-    // Find mac info 1.
-    const auto hidl_radio_mode_info1 =
-        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-                     [&legacy_mac_info1](
-                         const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
-                         return x.radioId == legacy_mac_info1.wlan_mac_id;
-                     });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
-    EXPECT_EQ(V1_4::WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
-              hidl_iface_info1.channel);
-
-    // Find mac info 2.
-    const auto hidl_radio_mode_info2 =
-        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-                     [&legacy_mac_info2](
-                         const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
-                         return x.radioId == legacy_mac_info2.wlan_mac_id;
-                     });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
-    EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
-    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
-              hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
-    legacy_hal::LinkLayerStats legacy_stats{};
-    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
-    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
-    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
-    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
-    legacy_stats.iface.beacon_rx = rand();
-    legacy_stats.iface.rssi_mgmt = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples =
-        rand();
-
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples =
-        rand();
-
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples =
-        rand();
-
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples =
-        rand();
-
-    legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
-    legacy_stats.iface.num_peers = 1;
-
-    for (auto& radio : legacy_stats.radios) {
-        radio.stats.radio = rand();
-        radio.stats.on_time = rand();
-        radio.stats.tx_time = rand();
-        radio.stats.rx_time = rand();
-        radio.stats.on_time_scan = rand();
-        radio.stats.on_time_nbd = rand();
-        radio.stats.on_time_gscan = rand();
-        radio.stats.on_time_roam_scan = rand();
-        radio.stats.on_time_pno_scan = rand();
-        radio.stats.on_time_hs20 = rand();
-        for (int i = 0; i < 4; i++) {
-            radio.tx_time_per_levels.push_back(rand());
-        }
-
-        legacy_hal::wifi_channel_stat channel_stat1 = {
-            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
-            .on_time = 0x1111,
-            .cca_busy_time = 0x55,
-        };
-        legacy_hal::wifi_channel_stat channel_stat2 = {
-            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
-            .on_time = 0x2222,
-            .cca_busy_time = 0x66,
-        };
-        radio.channel_stats.push_back(channel_stat1);
-        radio.channel_stats.push_back(channel_stat2);
-    }
-
-    for (auto& peer : legacy_stats.peers) {
-        peer.peer_info.bssload.sta_count = rand();
-        peer.peer_info.bssload.chan_util = rand();
-        wifi_rate_stat rate_stat1 = {
-            .rate = {3, 1, 2, 5, 0, 0},
-            .tx_mpdu = 0,
-            .rx_mpdu = 1,
-            .mpdu_lost = 2,
-            .retries = 3,
-            .retries_short = 4,
-            .retries_long = 5,
-        };
-        wifi_rate_stat rate_stat2 = {
-            .rate = {2, 2, 1, 6, 0, 1},
-            .tx_mpdu = 6,
-            .rx_mpdu = 7,
-            .mpdu_lost = 8,
-            .retries = 9,
-            .retries_short = 10,
-            .retries_long = 11,
-        };
-        peer.rate_stats.push_back(rate_stat1);
-        peer.rate_stats.push_back(rate_stat2);
-    }
-
-    V1_5::StaLinkLayerStats converted{};
-    hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
-                                                        &converted);
-    EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.V1_0.beaconRx);
-    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.V1_0.avgRssiMgmt);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
-              converted.iface.V1_0.wmeBePktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
-              converted.iface.V1_0.wmeBePktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
-              converted.iface.V1_0.wmeBePktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
-              converted.iface.V1_0.wmeBePktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
-              converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
-              converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
-              converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
-        converted.iface.wmeBeContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
-              converted.iface.V1_0.wmeBkPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
-              converted.iface.V1_0.wmeBkPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
-              converted.iface.V1_0.wmeBkPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
-              converted.iface.V1_0.wmeBkPktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
-              converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
-              converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
-              converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
-        converted.iface.wmeBkContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
-              converted.iface.V1_0.wmeViPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
-              converted.iface.V1_0.wmeViPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
-              converted.iface.V1_0.wmeViPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
-              converted.iface.V1_0.wmeViPktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
-              converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
-              converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
-              converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
-        converted.iface.wmeViContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
-              converted.iface.V1_0.wmeVoPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
-              converted.iface.V1_0.wmeVoPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
-              converted.iface.V1_0.wmeVoPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
-              converted.iface.V1_0.wmeVoPktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
-              converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
-              converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
-              converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
-        converted.iface.wmeVoContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
-              converted.iface.timeSliceDutyCycleInPercent);
-
-    EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
-    for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
-        EXPECT_EQ(legacy_stats.radios[i].stats.radio,
-                  converted.radios[i].radioId);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
-                  converted.radios[i].V1_3.V1_0.onTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
-                  converted.radios[i].V1_3.V1_0.txTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
-                  converted.radios[i].V1_3.V1_0.rxTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
-                  converted.radios[i].V1_3.V1_0.onTimeInMsForScan);
-        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
-                  converted.radios[i].V1_3.V1_0.txTimeInMsPerLevel.size());
-        for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
-             j++) {
-            EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
-                      converted.radios[i].V1_3.V1_0.txTimeInMsPerLevel[j]);
-        }
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
-                  converted.radios[i].V1_3.onTimeInMsForNanScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
-                  converted.radios[i].V1_3.onTimeInMsForBgScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
-                  converted.radios[i].V1_3.onTimeInMsForRoamScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
-                  converted.radios[i].V1_3.onTimeInMsForPnoScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
-                  converted.radios[i].V1_3.onTimeInMsForHs20Scan);
-        EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
-                  converted.radios[i].V1_3.channelStats.size());
-        for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size();
-             k++) {
-            auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
-            EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
-                      converted.radios[i].V1_3.channelStats[k].channel.width);
-            EXPECT_EQ(
-                WifiChannelInMhz(legacy_channel_st.channel.center_freq),
-                converted.radios[i].V1_3.channelStats[k].channel.centerFreq);
-            EXPECT_EQ(
-                WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
-                converted.radios[i].V1_3.channelStats[k].channel.centerFreq0);
-            EXPECT_EQ(
-                WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
-                converted.radios[i].V1_3.channelStats[k].channel.centerFreq1);
-            EXPECT_EQ(legacy_channel_st.cca_busy_time,
-                      converted.radios[i].V1_3.channelStats[k].ccaBusyTimeInMs);
-            EXPECT_EQ(legacy_channel_st.on_time,
-                      converted.radios[i].V1_3.channelStats[k].onTimeInMs);
-        }
-    }
-
-    EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size());
-    for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
-        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
-                  converted.iface.peers[i].staCount);
-        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
-                  converted.iface.peers[i].chanUtil);
-        for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
-                      (uint32_t)converted.iface.peers[i]
-                          .rateStats[j]
-                          .rateInfo.preamble);
-            EXPECT_EQ(
-                legacy_stats.peers[i].rate_stats[j].rate.nss,
-                (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
-            EXPECT_EQ(
-                legacy_stats.peers[i].rate_stats[j].rate.bw,
-                (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
-            EXPECT_EQ(
-                legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
-                converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
-                      converted.iface.peers[i].rateStats[j].txMpdu);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
-                      converted.iface.peers[i].rateStats[j].rxMpdu);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
-                      converted.iface.peers[i].rateStats[j].mpduLost);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
-                      converted.iface.peers[i].rateStats[j].retries);
-        }
-    }
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
-    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
-
-    uint32_t hidle_caps;
-
-    uint32_t legacy_feature_set =
-        WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
-    uint32_t legacy_logger_feature_set =
-        legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
-
-    ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
-        legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
-
-    EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
-                  HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
-                  HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
-                  HidlChipCaps::SET_LATENCY_MODE |
-                  HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
-              hidle_caps);
-}
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/mock_interface_tool.h b/wifi/1.5/default/tests/mock_interface_tool.h
deleted file mode 100644
index 0f17551..0000000
--- a/wifi/1.5/default/tests/mock_interface_tool.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_INTERFACE_TOOL_H
-#define MOCK_INTERFACE_TOOL_H
-
-#include <gmock/gmock.h>
-#include <wifi_system/interface_tool.h>
-
-namespace android {
-namespace wifi_system {
-
-class MockInterfaceTool : public InterfaceTool {
-   public:
-    MockInterfaceTool();
-
-    MOCK_METHOD1(GetUpState, bool(const char* if_name));
-    MOCK_METHOD2(SetUpState, bool(const char* if_name, bool request_up));
-    MOCK_METHOD1(SetWifiUpState, bool(bool request_up));
-    MOCK_METHOD2(SetMacAddress,
-                 bool(const char* if_name,
-                      const std::array<uint8_t, ETH_ALEN>& address));
-    MOCK_METHOD1(GetFactoryMacAddress,
-                 std::array<uint8_t, ETH_ALEN>(const char* if_name));
-
-};  // class MockInterfaceTool
-
-}  // namespace wifi_system
-}  // namespace android
-
-#endif  // MOCK_INTERFACE_TOOL_H
diff --git a/wifi/1.5/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
deleted file mode 100644
index 2f66ba1..0000000
--- a/wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 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 <gmock/gmock.h>
-
-#include "mock_wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace feature_flags {
-
-MockWifiFeatureFlags::MockWifiFeatureFlags() {}
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/mock_wifi_feature_flags.h b/wifi/1.5/default/tests/mock_wifi_feature_flags.h
deleted file mode 100644
index c3877ed..0000000
--- a/wifi/1.5/default/tests/mock_wifi_feature_flags.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
-#define MOCK_WIFI_FEATURE_FLAGS_H_
-
-#include <gmock/gmock.h>
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-
-#include "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace feature_flags {
-
-class MockWifiFeatureFlags : public WifiFeatureFlags {
-   public:
-    MockWifiFeatureFlags();
-
-    MOCK_METHOD1(getChipModes,
-                 std::vector<V1_0::IWifiChip::ChipMode>(bool is_primary));
-    MOCK_METHOD0(isApMacRandomizationDisabled, bool());
-};
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.5/default/tests/mock_wifi_iface_util.cpp b/wifi/1.5/default/tests/mock_wifi_iface_util.cpp
deleted file mode 100644
index b101c4a..0000000
--- a/wifi/1.5/default/tests/mock_wifi_iface_util.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace iface_util {
-
-MockWifiIfaceUtil::MockWifiIfaceUtil(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : WifiIfaceUtil(iface_tool, legacy_hal) {}
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/mock_wifi_iface_util.h b/wifi/1.5/default/tests/mock_wifi_iface_util.h
deleted file mode 100644
index 6d5f59c..0000000
--- a/wifi/1.5/default/tests/mock_wifi_iface_util.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_IFACE_UTIL_H_
-#define MOCK_WIFI_IFACE_UTIL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace iface_util {
-
-class MockWifiIfaceUtil : public WifiIfaceUtil {
-   public:
-    MockWifiIfaceUtil(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-    MOCK_METHOD1(getFactoryMacAddress,
-                 std::array<uint8_t, 6>(const std::string&));
-    MOCK_METHOD2(setMacAddress,
-                 bool(const std::string&, const std::array<uint8_t, 6>&));
-    MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
-    MOCK_METHOD2(registerIfaceEventHandlers,
-                 void(const std::string&, IfaceEventHandlers));
-    MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
-    MOCK_METHOD2(setUpState, bool(const std::string&, bool));
-    MOCK_METHOD1(ifNameToIndex, unsigned(const std::string&));
-};
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
deleted file mode 100644
index d13c556..0000000
--- a/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 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 <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace legacy_hal {
-
-MockWifiLegacyHal::MockWifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-    const wifi_hal_fn& fn, bool is_primary)
-    : WifiLegacyHal(iface_tool, fn, is_primary) {}
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/mock_wifi_legacy_hal.h b/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
deleted file mode 100644
index 826b35f..0000000
--- a/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_LEGACY_HAL_H_
-#define MOCK_WIFI_LEGACY_HAL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace legacy_hal {
-
-class MockWifiLegacyHal : public WifiLegacyHal {
-   public:
-    MockWifiLegacyHal(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-        const wifi_hal_fn& fn, bool is_primary);
-    MOCK_METHOD0(initialize, wifi_error());
-    MOCK_METHOD0(start, wifi_error());
-    MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
-                                  const std::function<void()>&));
-    MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
-    MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
-                 wifi_error(const std::string&,
-                            const on_radio_mode_change_callback&));
-    MOCK_METHOD1(getFirmwareVersion, std::pair<wifi_error, std::string>(
-                                         const std::string& iface_name));
-    MOCK_METHOD1(getDriverVersion, std::pair<wifi_error, std::string>(
-                                       const std::string& iface_name));
-
-    MOCK_METHOD2(selectTxPowerScenario,
-                 wifi_error(const std::string& iface_name,
-                            wifi_power_scenario scenario));
-    MOCK_METHOD1(resetTxPowerScenario,
-                 wifi_error(const std::string& iface_name));
-    MOCK_METHOD2(nanRegisterCallbackHandlers,
-                 wifi_error(const std::string&, const NanCallbackHandlers&));
-    MOCK_METHOD2(nanDisableRequest,
-                 wifi_error(const std::string&, transaction_id));
-    MOCK_METHOD3(nanDataInterfaceDelete,
-                 wifi_error(const std::string&, transaction_id,
-                            const std::string&));
-    MOCK_METHOD2(createVirtualInterface,
-                 wifi_error(const std::string& ifname,
-                            wifi_interface_type iftype));
-    MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname));
-    MOCK_METHOD0(waitForDriverReady, wifi_error());
-};
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.5/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
deleted file mode 100644
index e7ab22a..0000000
--- a/wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 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 <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace mode_controller {
-
-MockWifiModeController::MockWifiModeController() : WifiModeController() {}
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/mock_wifi_mode_controller.h b/wifi/1.5/default/tests/mock_wifi_mode_controller.h
deleted file mode 100644
index b9151f1..0000000
--- a/wifi/1.5/default/tests/mock_wifi_mode_controller.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
-#define MOCK_WIFI_MODE_CONTROLLER_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace mode_controller {
-
-class MockWifiModeController : public WifiModeController {
-   public:
-    MockWifiModeController();
-    MOCK_METHOD0(initialize, bool());
-    MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
-    MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
-    MOCK_METHOD0(deinitialize, bool());
-};
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.5/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
deleted file mode 100644
index 6fd34ee..0000000
--- a/wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2018, 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 <gmock/gmock.h>
-
-#include "ringbuffer.h"
-
-using testing::Return;
-using testing::Test;
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-class RingbufferTest : public Test {
-   public:
-    const uint32_t maxBufferSize_ = 10;
-    Ringbuffer buffer_{maxBufferSize_};
-};
-
-TEST_F(RingbufferTest, CreateEmptyBuffer) {
-    ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
-    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
-    buffer_.append(input);
-    buffer_.append(input2);
-    ASSERT_EQ(2u, buffer_.getData().size());
-    EXPECT_EQ(input, buffer_.getData().front());
-    EXPECT_EQ(input2, buffer_.getData().back());
-}
-
-TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
-    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
-    const std::vector<uint8_t> input3 = {'G'};
-    buffer_.append(input);
-    buffer_.append(input2);
-    buffer_.append(input3);
-    ASSERT_EQ(2u, buffer_.getData().size());
-    EXPECT_EQ(input2, buffer_.getData().front());
-    EXPECT_EQ(input3, buffer_.getData().back());
-}
-
-TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
-    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
-    const std::vector<uint8_t> input3(maxBufferSize_, '2');
-    buffer_.append(input);
-    buffer_.append(input2);
-    buffer_.append(input3);
-    ASSERT_EQ(1u, buffer_.getData().size());
-    EXPECT_EQ(input3, buffer_.getData().front());
-}
-
-TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
-    const std::vector<uint8_t> input = {};
-    buffer_.append(input);
-    ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, OversizedAppendIsDropped) {
-    const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
-    buffer_.append(input);
-    ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
-    const std::vector<uint8_t> input(maxBufferSize_, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
-    buffer_.append(input);
-    buffer_.append(input2);
-    ASSERT_EQ(1u, buffer_.getData().size());
-    EXPECT_EQ(input, buffer_.getData().front());
-}
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
deleted file mode 100644
index 0ad6f3e..0000000
--- a/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
+++ /dev/null
@@ -1,905 +0,0 @@
-/*
- * Copyright (C) 2017, 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 <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_chip.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-#include "mock_wifi_mode_controller.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-using android::hardware::wifi::V1_0::ChipId;
-
-constexpr ChipId kFakeChipId = 5;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-class WifiChipTest : public Test {
-   protected:
-    void setupV1IfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P}, 1}}}
-        };
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
-            {{{{IfaceType::AP}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
-            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes(true))
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV1_AwareIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
-            {{{{IfaceType::AP}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
-            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes(true))
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV1_AwareDisabledApIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes(true))
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV2_AwareIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::AP}, 1}}},
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV3, combinations}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes(true))
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV2_AwareDisabledApIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV3, combinations}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes(true))
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setup_MultiIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV3, combinations}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes(true))
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void assertNumberOfModes(uint32_t num_modes) {
-        chip_->getAvailableModes(
-            [num_modes](const WifiStatus& status,
-                        const std::vector<WifiChip::ChipMode>& modes) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                // V2_Aware has 1 mode of operation.
-                ASSERT_EQ(num_modes, modes.size());
-            });
-    }
-
-    void findModeAndConfigureForIfaceType(const IfaceType& type) {
-        // This should be aligned with kInvalidModeId in wifi_chip.cpp.
-        ChipModeId mode_id = UINT32_MAX;
-        chip_->getAvailableModes(
-            [&mode_id, &type](const WifiStatus& status,
-                              const std::vector<WifiChip::ChipMode>& modes) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                for (const auto& mode : modes) {
-                    for (const auto& combination : mode.availableCombinations) {
-                        for (const auto& limit : combination.limits) {
-                            if (limit.types.end() !=
-                                std::find(limit.types.begin(),
-                                          limit.types.end(), type)) {
-                                mode_id = mode.id;
-                            }
-                        }
-                    }
-                }
-            });
-        ASSERT_NE(UINT32_MAX, mode_id);
-
-        chip_->configureChip(mode_id, [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-    }
-
-    // Returns an empty string on error.
-    std::string createIface(const IfaceType& type) {
-        std::string iface_name;
-        if (type == IfaceType::AP) {
-            chip_->createApIface(
-                [&iface_name](const WifiStatus& status,
-                              const sp<V1_0::IWifiApIface>& iface) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(iface.get(), nullptr);
-                        iface->getName([&iface_name](const WifiStatus& status,
-                                                     const hidl_string& name) {
-                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                            iface_name = name.c_str();
-                        });
-                    }
-                });
-        } else if (type == IfaceType::NAN) {
-            chip_->createNanIface(
-                [&iface_name](
-                    const WifiStatus& status,
-                    const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
-                        iface) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(iface.get(), nullptr);
-                        iface->getName([&iface_name](const WifiStatus& status,
-                                                     const hidl_string& name) {
-                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                            iface_name = name.c_str();
-                        });
-                    }
-                });
-        } else if (type == IfaceType::P2P) {
-            chip_->createP2pIface(
-                [&iface_name](const WifiStatus& status,
-                              const sp<IWifiP2pIface>& iface) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(iface.get(), nullptr);
-                        iface->getName([&iface_name](const WifiStatus& status,
-                                                     const hidl_string& name) {
-                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                            iface_name = name.c_str();
-                        });
-                    }
-                });
-        } else if (type == IfaceType::STA) {
-            chip_->createStaIface(
-                [&iface_name](const WifiStatus& status,
-                              const sp<V1_0::IWifiStaIface>& iface) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(iface.get(), nullptr);
-                        iface->getName([&iface_name](const WifiStatus& status,
-                                                     const hidl_string& name) {
-                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                            iface_name = name.c_str();
-                        });
-                    }
-                });
-        }
-        return iface_name;
-    }
-
-    void removeIface(const IfaceType& type, const std::string& iface_name) {
-        if (type == IfaceType::AP) {
-            chip_->removeApIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::NAN) {
-            chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::P2P) {
-            chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::STA) {
-            chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        }
-    }
-
-    bool createRttController() {
-        bool success = false;
-        chip_->createRttController_1_4(
-            NULL, [&success](const WifiStatus& status,
-                             const sp<IWifiRttController>& rtt) {
-                if (WifiStatusCode::SUCCESS == status.code) {
-                    ASSERT_NE(rtt.get(), nullptr);
-                    success = true;
-                }
-            });
-        return success;
-    }
-
-    static void subsystemRestartHandler(const std::string& /*error*/) {}
-
-    sp<WifiChip> chip_;
-    ChipId chip_id_ = kFakeChipId;
-    legacy_hal::wifi_hal_fn fake_func_table_;
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-        new NiceMock<wifi_system::MockInterfaceTool>};
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
-                                                    fake_func_table_, true)};
-    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
-        mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
-    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
-        new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
-    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
-        feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
-
-   public:
-    void SetUp() override {
-        chip_ =
-            new WifiChip(chip_id_, true, legacy_hal_, mode_controller_,
-                         iface_util_, feature_flags_, subsystemRestartHandler);
-
-        EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
-            .WillRepeatedly(testing::Return(true));
-        EXPECT_CALL(*legacy_hal_, start())
-            .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
-    }
-
-    void TearDown() override {
-        // Restore default system iface names (This should ideally be using a
-        // mock).
-        property_set("wifi.interface", "wlan0");
-        property_set("wifi.concurrent.interface", "wlan1");
-        property_set("wifi.aware.interface", nullptr);
-    }
-};
-
-////////// V1 Iface Combinations ////////////
-// Mode 1 - STA + P2P
-// Mode 2 - AP
-class WifiChipV1IfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV1IfaceCombination();
-        WifiChipTest::SetUp();
-        // V1 has 2 modes of operation.
-        assertNumberOfModes(2u);
-    }
-};
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-////////// V1 + Aware Iface Combinations ////////////
-// Mode 1 - STA + P2P/NAN
-// Mode 2 - AP
-class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV1_AwareIfaceCombination();
-        WifiChipTest::SetUp();
-        // V1_Aware has 2 modes of operation.
-        assertNumberOfModes(2u);
-    }
-};
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2PNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, nan_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    const auto ap_iface_name = createIface(IfaceType::AP);
-    ASSERT_FALSE(ap_iface_name.empty());
-    ASSERT_FALSE(createRttController());
-
-    removeIface(IfaceType::AP, ap_iface_name);
-
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-////////// V2 + Aware Iface Combinations ////////////
-// Mode 1 - STA + STA/AP
-//        - STA + P2P/NAN
-class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV2_AwareIfaceCombination();
-        WifiChipTest::SetUp();
-        // V2_Aware has 1 mode of operation.
-        assertNumberOfModes(1u);
-    }
-};
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateSta_AfterStaApRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    const auto sta_iface_name = createIface(IfaceType::STA);
-    ASSERT_FALSE(sta_iface_name.empty());
-    const auto ap_iface_name = createIface(IfaceType::AP);
-    ASSERT_FALSE(ap_iface_name.empty());
-
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-
-    // After removing AP & STA iface, STA iface creation should succeed.
-    removeIface(IfaceType::STA, sta_iface_name);
-    removeIface(IfaceType::AP, ap_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, nan_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, nan_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateStaAp_EnsureDifferentIfaceNames) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    const auto sta_iface_name = createIface(IfaceType::STA);
-    const auto ap_iface_name = createIface(IfaceType::AP);
-    ASSERT_FALSE(sta_iface_name.empty());
-    ASSERT_FALSE(ap_iface_name.empty());
-    ASSERT_NE(sta_iface_name, ap_iface_name);
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       InvalidateAndRemoveNanOnStaRemove) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
-    // Create NAN iface
-    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
-
-    // We should have 1 nan iface.
-    chip_->getNanIfaceNames(
-        [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            ASSERT_EQ(iface_names.size(), 1u);
-            ASSERT_EQ(iface_names[0], "wlan0");
-        });
-    // Retrieve the exact iface object.
-    sp<android::hardware::wifi::V1_0::IWifiNanIface> nan_iface;
-    chip_->getNanIface(
-        "wlan0",
-        [&nan_iface](
-            const WifiStatus& status,
-            const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            ASSERT_NE(iface.get(), nullptr);
-            nan_iface = iface;
-        });
-
-    // Remove the STA iface.
-    removeIface(IfaceType::STA, "wlan0");
-    // We should have 0 nan iface now.
-    chip_->getNanIfaceNames(
-        [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            ASSERT_EQ(iface_names.size(), 0u);
-        });
-    // Any operation on the nan iface object should return error now.
-    nan_iface->getName(
-        [](const WifiStatus& status, const std::string& /* iface_name */) {
-            ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
-        });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       InvalidateAndRemoveRttControllerOnStaRemove) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
-    // Create RTT controller
-    sp<IWifiRttController> rtt_controller;
-    chip_->createRttController_1_4(
-        NULL, [&rtt_controller](const WifiStatus& status,
-                                const sp<IWifiRttController>& rtt) {
-            if (WifiStatusCode::SUCCESS == status.code) {
-                ASSERT_NE(rtt.get(), nullptr);
-                rtt_controller = rtt;
-            }
-        });
-
-    // Remove the STA iface.
-    removeIface(IfaceType::STA, "wlan0");
-
-    // Any operation on the rtt controller object should return error now.
-    rtt_controller->getBoundIface(
-        [](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
-            ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                      status.code);
-        });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) {
-    property_set("wifi.aware.interface", nullptr);
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
-    removeIface(IfaceType::NAN, "wlan0");
-    EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0);
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) {
-    property_set("wifi.aware.interface", "aware0");
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    EXPECT_CALL(*iface_util_, ifNameToIndex("aware0"))
-        .WillOnce(testing::Return(4));
-    EXPECT_CALL(*iface_util_, setUpState("aware0", true))
-        .WillOnce(testing::Return(true));
-    ASSERT_EQ(createIface(IfaceType::NAN), "aware0");
-
-    EXPECT_CALL(*iface_util_, setUpState("aware0", false))
-        .WillOnce(testing::Return(true));
-    removeIface(IfaceType::NAN, "aware0");
-}
-
-////////// V1 Iface Combinations when AP creation is disabled //////////
-class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV1_AwareDisabledApIfaceCombination();
-        WifiChipTest::SetUp();
-    }
-};
-
-TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest,
-       StaMode_CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-////////// V2 Iface Combinations when AP creation is disabled //////////
-class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV2_AwareDisabledApIfaceCombination();
-        WifiChipTest::SetUp();
-    }
-};
-
-TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest,
-       CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-////////// Hypothetical Iface Combination with multiple ifaces //////////
-class WifiChip_MultiIfaceTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setup_MultiIfaceCombination();
-        WifiChipTest::SetUp();
-    }
-};
-
-TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
-    property_set("wifi.interface.0", "");
-    property_set("wifi.interface.1", "");
-    property_set("wifi.interface.2", "");
-    property_set("wifi.interface", "");
-    property_set("wifi.concurrent.interface", "");
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
-    property_set("wifi.interface.0", "test0");
-    property_set("wifi.interface.1", "test1");
-    property_set("wifi.interface.2", "test2");
-    property_set("wifi.interface", "bad0");
-    property_set("wifi.concurrent.interface", "bad1");
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "bad0");
-    ASSERT_EQ(createIface(IfaceType::STA), "bad1");
-    ASSERT_EQ(createIface(IfaceType::STA), "test2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
-    property_set("wifi.interface.0", "");
-    property_set("wifi.interface.1", "");
-    property_set("wifi.interface.2", "");
-    property_set("wifi.interface", "testA0");
-    property_set("wifi.concurrent.interface", "testA1");
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "testA0");
-    ASSERT_EQ(createIface(IfaceType::STA), "testA1");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    // First AP will be slotted to wlan1.
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-    // First STA will be slotted to wlan0.
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    // All further STA will be slotted to the remaining free indices.
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
-}
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
deleted file mode 100644
index 8b67bb8..0000000
--- a/wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "wifi_iface_util.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Test;
-
-namespace {
-constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
-constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
-constexpr char kIfaceName[] = "test-wlan0";
-
-bool isValidUnicastLocallyAssignedMacAddress(
-    const std::array<uint8_t, 6>& mac_address) {
-    uint8_t first_byte = mac_address[0];
-    return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace iface_util {
-class WifiIfaceUtilTest : public Test {
-   protected:
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-        new NiceMock<wifi_system::MockInterfaceTool>};
-    legacy_hal::wifi_hal_fn fake_func_table_;
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
-                                                    fake_func_table_, true)};
-    WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_, legacy_hal_);
-};
-
-TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
-    auto mac_address = iface_util_->getOrCreateRandomMacAddress();
-    ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
-
-    // All further calls should return the same MAC address.
-    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
-    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
-}
-
-TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
-    std::array<uint8_t, 6> mac_address = {};
-    std::copy(std::begin(kMacAddress), std::end(kMacAddress),
-              std::begin(mac_address));
-    EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
-        .WillRepeatedly(testing::Return(true));
-    EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
-        .WillRepeatedly(testing::Return(true));
-
-    // Register for iface state toggle events.
-    bool callback_invoked = false;
-    iface_util::IfaceEventHandlers event_handlers = {};
-    event_handlers.on_state_toggle_off_on =
-        [&callback_invoked](const std::string& /* iface_name */) {
-            callback_invoked = true;
-        };
-    iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
-    // Invoke setMacAddress and ensure that the cb is invoked.
-    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
-    ASSERT_TRUE(callback_invoked);
-
-    // Unregister for iface state toggle events.
-    callback_invoked = false;
-    iface_util_->unregisterIfaceEventHandlers(kIfaceName);
-    // Invoke setMacAddress and ensure that the cb is not invoked.
-    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
-    ASSERT_FALSE(callback_invoked);
-}
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
deleted file mode 100644
index 32da55e..0000000
--- a/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_nan_iface.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-constexpr char kIfaceName[] = "mockWlan0";
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-using android::hardware::wifi::V1_2::NanDataPathConfirmInd;
-
-bool CaptureIfaceEventHandlers(
-    const std::string& /* iface_name*/,
-    iface_util::IfaceEventHandlers in_iface_event_handlers,
-    iface_util::IfaceEventHandlers* out_iface_event_handlers) {
-    *out_iface_event_handlers = in_iface_event_handlers;
-    return true;
-}
-
-class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback {
-   public:
-    MockNanIfaceEventCallback() = default;
-
-    MOCK_METHOD3(
-        notifyCapabilitiesResponse,
-        Return<void>(uint16_t, const WifiNanStatus&,
-                     const android::hardware::wifi::V1_0::NanCapabilities&));
-    MOCK_METHOD2(notifyEnableResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyConfigResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyDisableResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyStartPublishResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
-    MOCK_METHOD2(notifyStopPublishResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyStartSubscribeResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
-    MOCK_METHOD2(notifyStopSubscribeResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyTransmitFollowupResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyCreateDataInterfaceResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyDeleteDataInterfaceResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyInitiateDataPathResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
-    MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyTerminateDataPathResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
-    MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
-    MOCK_METHOD2(eventPublishTerminated,
-                 Return<void>(uint8_t, const WifiNanStatus&));
-    MOCK_METHOD2(eventSubscribeTerminated,
-                 Return<void>(uint8_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventMatch, Return<void>(const NanMatchInd&));
-    MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
-    MOCK_METHOD1(eventFollowupReceived,
-                 Return<void>(const NanFollowupReceivedInd&));
-    MOCK_METHOD2(eventTransmitFollowup,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventDataPathRequest,
-                 Return<void>(const NanDataPathRequestInd&));
-    MOCK_METHOD1(
-        eventDataPathConfirm,
-        Return<void>(
-            const android::hardware::wifi::V1_0::NanDataPathConfirmInd&));
-    MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
-    MOCK_METHOD1(eventDataPathConfirm_1_2,
-                 Return<void>(const NanDataPathConfirmInd&));
-    MOCK_METHOD1(eventDataPathScheduleUpdate,
-                 Return<void>(const NanDataPathScheduleUpdateInd&));
-    MOCK_METHOD3(notifyCapabilitiesResponse_1_5,
-                 Return<void>(uint16_t, const WifiNanStatus&,
-                              const NanCapabilities&));
-};
-
-class WifiNanIfaceTest : public Test {
-   protected:
-    legacy_hal::wifi_hal_fn fake_func_table_;
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-        new NiceMock<wifi_system::MockInterfaceTool>};
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
-                                                    fake_func_table_, true)};
-    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
-        new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
-};
-
-TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
-    iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
-    EXPECT_CALL(*legacy_hal_,
-                nanRegisterCallbackHandlers(testing::_, testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    EXPECT_CALL(*iface_util_,
-                registerIfaceEventHandlers(testing::_, testing::_))
-        .WillOnce(testing::Invoke(
-            bind(CaptureIfaceEventHandlers, std::placeholders::_1,
-                 std::placeholders::_2, &captured_iface_event_handlers)));
-    sp<WifiNanIface> nan_iface =
-        new WifiNanIface(kIfaceName, false, legacy_hal_, iface_util_);
-
-    // Register a mock nan event callback.
-    sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
-        new NiceMock<MockNanIfaceEventCallback>};
-    nan_iface->registerEventCallback(
-        mock_event_callback, [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-    // Ensure that the eventDisabled() function in mock callback will be
-    // invoked.
-    WifiNanStatus expected_nan_status = {
-        NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
-    EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status))
-        .Times(1);
-
-    // Trigger the iface state toggle callback.
-    captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
-}
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi.cpp b/wifi/1.5/default/wifi.cpp
deleted file mode 100644
index a85b242..0000000
--- a/wifi/1.5/default/wifi.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi.h"
-#include "wifi_status_util.h"
-
-namespace {
-// Starting Chip ID, will be assigned to primary chip
-static constexpr android::hardware::wifi::V1_0::ChipId kPrimaryChipId = 0;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-Wifi::Wifi(
-    const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-    const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
-    const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
-    const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
-    : iface_tool_(iface_tool),
-      legacy_hal_factory_(legacy_hal_factory),
-      mode_controller_(mode_controller),
-      feature_flags_(feature_flags),
-      run_state_(RunState::STOPPED) {}
-
-bool Wifi::isValid() {
-    // This object is always valid.
-    return true;
-}
-
-Return<void> Wifi::registerEventCallback(
-    const sp<V1_0::IWifiEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::registerEventCallbackInternal, hidl_status_cb,
-                           event_callback);
-}
-
-Return<void> Wifi::registerEventCallback_1_5(
-    const sp<V1_5::IWifiEventCallback>& event_callback,
-    registerEventCallback_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::registerEventCallbackInternal_1_5,
-                           hidl_status_cb, event_callback);
-}
-
-Return<bool> Wifi::isStarted() { return run_state_ != RunState::STOPPED; }
-
-Return<void> Wifi::start(start_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::startInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::stop(stop_cb hidl_status_cb) {
-    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
-                                   &Wifi::stopInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::getChipIdsInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::getChipInternal, hidl_status_cb, chip_id);
-}
-
-Return<void> Wifi::debug(const hidl_handle& handle,
-                         const hidl_vec<hidl_string>&) {
-    LOG(INFO) << "-----------Debug is called----------------";
-    if (chips_.size() == 0) {
-        return Void();
-    }
-
-    for (sp<WifiChip> chip : chips_) {
-        if (!chip.get()) continue;
-
-        chip->debug(handle, {});
-    }
-    return Void();
-}
-
-WifiStatus Wifi::registerEventCallbackInternal(
-    const sp<V1_0::IWifiEventCallback>& event_callback __unused) {
-    // Deprecated support for this callback.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus Wifi::registerEventCallbackInternal_1_5(
-    const sp<V1_5::IWifiEventCallback>& event_callback) {
-    if (!event_cb_handler_.addCallback(event_callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::startInternal() {
-    if (run_state_ == RunState::STARTED) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    } else if (run_state_ == RunState::STOPPING) {
-        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
-                                "HAL is stopping");
-    }
-    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
-    if (wifi_status.code == WifiStatusCode::SUCCESS) {
-        // Register the callback for subsystem restart
-        const auto& on_subsystem_restart_callback =
-            [this](const std::string& error) {
-                WifiStatus wifi_status =
-                    createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
-                for (const auto& callback : event_cb_handler_.getCallbacks()) {
-                    LOG(INFO) << "Attempting to invoke onSubsystemRestart "
-                                 "callback";
-                    if (!callback->onSubsystemRestart(wifi_status).isOk()) {
-                        LOG(ERROR)
-                            << "Failed to invoke onSubsystemRestart callback";
-                    } else {
-                        LOG(INFO) << "Succeeded to invoke onSubsystemRestart "
-                                     "callback";
-                    }
-                }
-            };
-
-        // Create the chip instance once the HAL is started.
-        android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
-        for (auto& hal : legacy_hals_) {
-            chips_.push_back(new WifiChip(
-                chipId, chipId == kPrimaryChipId, hal, mode_controller_,
-                std::make_shared<iface_util::WifiIfaceUtil>(iface_tool_, hal),
-                feature_flags_, on_subsystem_restart_callback));
-            chipId++;
-        }
-        run_state_ = RunState::STARTED;
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onStart().isOk()) {
-                LOG(ERROR) << "Failed to invoke onStart callback";
-            };
-        }
-        LOG(INFO) << "Wifi HAL started";
-    } else {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onFailure(wifi_status).isOk()) {
-                LOG(ERROR) << "Failed to invoke onFailure callback";
-            }
-        }
-        LOG(ERROR) << "Wifi HAL start failed";
-        // Clear the event callback objects since the HAL start failed.
-        event_cb_handler_.invalidate();
-    }
-    return wifi_status;
-}
-
-WifiStatus Wifi::stopInternal(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-    if (run_state_ == RunState::STOPPED) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    } else if (run_state_ == RunState::STOPPING) {
-        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
-                                "HAL is stopping");
-    }
-    // Clear the chip object and its child objects since the HAL is now
-    // stopped.
-    for (auto& chip : chips_) {
-        if (chip.get()) {
-            chip->invalidate();
-            chip.clear();
-        }
-    }
-    chips_.clear();
-    WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
-    if (wifi_status.code == WifiStatusCode::SUCCESS) {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onStop().isOk()) {
-                LOG(ERROR) << "Failed to invoke onStop callback";
-            };
-        }
-        LOG(INFO) << "Wifi HAL stopped";
-    } else {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onFailure(wifi_status).isOk()) {
-                LOG(ERROR) << "Failed to invoke onFailure callback";
-            }
-        }
-        LOG(ERROR) << "Wifi HAL stop failed";
-    }
-    // Clear the event callback objects since the HAL is now stopped.
-    event_cb_handler_.invalidate();
-    return wifi_status;
-}
-
-std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
-    std::vector<ChipId> chip_ids;
-
-    for (auto& chip : chips_) {
-        ChipId chip_id = getChipIdFromWifiChip(chip);
-        if (chip_id != UINT32_MAX) chip_ids.emplace_back(chip_id);
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiChip>> Wifi::getChipInternal(
-    ChipId chip_id) {
-    for (auto& chip : chips_) {
-        ChipId cand_id = getChipIdFromWifiChip(chip);
-        if ((cand_id != UINT32_MAX) && (cand_id == chip_id))
-            return {createWifiStatus(WifiStatusCode::SUCCESS), chip};
-    }
-
-    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-}
-
-WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
-    if (!mode_controller_->initialize()) {
-        LOG(ERROR) << "Failed to initialize firmware mode controller";
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-
-    legacy_hals_ = legacy_hal_factory_->getHals();
-    if (legacy_hals_.empty())
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    int index = 0;  // for failure log
-    for (auto& hal : legacy_hals_) {
-        legacy_hal::wifi_error legacy_status = hal->initialize();
-        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-            // Currently WifiLegacyHal::initialize does not allocate extra mem,
-            // only initializes the function table. If this changes, need to
-            // implement WifiLegacyHal::deinitialize and deinitalize the
-            // HALs already initialized
-            LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
-                       << " error: " << legacyErrorToString(legacy_status);
-            return createWifiStatusFromLegacyError(legacy_status);
-        }
-        index++;
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-    legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
-    int index = 0;
-
-    run_state_ = RunState::STOPPING;
-    for (auto& hal : legacy_hals_) {
-        legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
-        if (tmp != legacy_hal::WIFI_SUCCESS) {
-            LOG(ERROR) << "Failed to stop legacy HAL index: " << index
-                       << " error: " << legacyErrorToString(legacy_status);
-            legacy_status = tmp;
-        }
-        index++;
-    }
-    run_state_ = RunState::STOPPED;
-
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "One or more legacy HALs failed to stop";
-        return createWifiStatusFromLegacyError(legacy_status);
-    }
-    if (!mode_controller_->deinitialize()) {
-        LOG(ERROR) << "Failed to deinitialize firmware mode controller";
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-ChipId Wifi::getChipIdFromWifiChip(sp<WifiChip>& chip) {
-    ChipId chip_id = UINT32_MAX;
-    if (chip.get()) {
-        chip->getId([&](WifiStatus status, uint32_t id) {
-            if (status.code == WifiStatusCode::SUCCESS) {
-                chip_id = id;
-            }
-        });
-    }
-
-    return chip_id;
-}
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi.h b/wifi/1.5/default/wifi.h
deleted file mode 100644
index c94ef3f..0000000
--- a/wifi/1.5/default/wifi.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_H_
-#define WIFI_H_
-
-// HACK: NAN is a macro defined in math.h, which can be included in various
-// headers. This wifi HAL uses an enum called NAN, which does not compile when
-// the macro is defined. Undefine NAN to work around it.
-#undef NAN
-#include <android/hardware/wifi/1.5/IWifi.h>
-
-#include <android-base/macros.h>
-#include <utils/Looper.h>
-#include <functional>
-
-#include "hidl_callback_util.h"
-#include "wifi_chip.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_legacy_hal_factory.h"
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-/**
- * Root HIDL interface object used to control the Wifi HAL.
- */
-class Wifi : public V1_5::IWifi {
-   public:
-    Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-         const std::shared_ptr<legacy_hal::WifiLegacyHalFactory>
-             legacy_hal_factory,
-         const std::shared_ptr<mode_controller::WifiModeController>
-             mode_controller,
-         const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
-
-    bool isValid();
-
-    // HIDL methods exposed.
-    Return<void> registerEventCallback(
-        const sp<V1_0::IWifiEventCallback>& event_callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_5(
-        const sp<V1_5::IWifiEventCallback>& event_callback,
-        registerEventCallback_1_5_cb hidl_status_cb) override;
-    Return<bool> isStarted() override;
-    Return<void> start(start_cb hidl_status_cb) override;
-    Return<void> stop(stop_cb hidl_status_cb) override;
-    Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
-    Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
-    Return<void> debug(const hidl_handle& handle,
-                       const hidl_vec<hidl_string>& options) override;
-
-   private:
-    enum class RunState { STOPPED, STARTED, STOPPING };
-
-    // Corresponding worker functions for the HIDL methods.
-    WifiStatus registerEventCallbackInternal(
-        const sp<V1_0::IWifiEventCallback>& event_callback __unused);
-    WifiStatus registerEventCallbackInternal_1_5(
-        const sp<V1_5::IWifiEventCallback>& event_callback);
-    WifiStatus startInternal();
-    WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
-    std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
-    std::pair<WifiStatus, sp<V1_4::IWifiChip>> getChipInternal(ChipId chip_id);
-
-    WifiStatus initializeModeControllerAndLegacyHal();
-    WifiStatus stopLegacyHalAndDeinitializeModeController(
-        std::unique_lock<std::recursive_mutex>* lock);
-    ChipId getChipIdFromWifiChip(sp<WifiChip>& chip);
-
-    // Instance is created in this root level |IWifi| HIDL interface object
-    // and shared with all the child HIDL interface objects.
-    std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
-    std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
-    std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
-    std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
-    RunState run_state_;
-    std::vector<sp<WifiChip>> chips_;
-    hidl_callback_util::HidlCallbackHandler<V1_5::IWifiEventCallback>
-        event_cb_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(Wifi);
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_H_
diff --git a/wifi/1.5/default/wifi_ap_iface.cpp b/wifi/1.5/default/wifi_ap_iface.cpp
deleted file mode 100644
index 1ae7905..0000000
--- a/wifi/1.5/default/wifi_ap_iface.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_ap_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiApIface::WifiApIface(
-    const std::string& ifname, const std::vector<std::string>& instances,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
-    : ifname_(ifname),
-      instances_(instances),
-      legacy_hal_(legacy_hal),
-      iface_util_(iface_util),
-      is_valid_(true) {}
-
-void WifiApIface::invalidate() {
-    legacy_hal_.reset();
-    is_valid_ = false;
-}
-
-bool WifiApIface::isValid() { return is_valid_; }
-
-std::string WifiApIface::getName() { return ifname_; }
-
-void WifiApIface::removeInstance(std::string instance) {
-    instances_.erase(
-        std::remove(instances_.begin(), instances_.end(), instance),
-        instances_.end());
-}
-
-Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
-                                         setCountryCode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::setCountryCodeInternal, hidl_status_cb,
-                           code);
-}
-
-Return<void> WifiApIface::getValidFrequenciesForBand(
-    V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getValidFrequenciesForBandInternal,
-                           hidl_status_cb, band);
-}
-
-Return<void> WifiApIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                                        setMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::setMacAddressInternal, hidl_status_cb,
-                           mac);
-}
-
-Return<void> WifiApIface::getFactoryMacAddress(
-    getFactoryMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getFactoryMacAddressInternal,
-                           hidl_status_cb,
-                           instances_.size() > 0 ? instances_[0] : ifname_);
-}
-
-Return<void> WifiApIface::resetToFactoryMacAddress(
-    resetToFactoryMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::resetToFactoryMacAddressInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiApIface::getBridgedInstances(
-    getBridgedInstances_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getBridgedInstancesInternal,
-                           hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
-}
-
-WifiStatus WifiApIface::setCountryCodeInternal(
-    const std::array<int8_t, 2>& code) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
-        instances_.size() > 0 ? instances_[0] : ifname_, code);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
-    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
-                  "Size mismatch");
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint32_t> valid_frequencies;
-    std::tie(legacy_status, valid_frequencies) =
-        legacy_hal_.lock()->getValidFrequenciesForBand(
-            instances_.size() > 0 ? instances_[0] : ifname_,
-            hidl_struct_util::convertHidlWifiBandToLegacy(band));
-    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-
-WifiStatus WifiApIface::setMacAddressInternal(
-    const std::array<uint8_t, 6>& mac) {
-    // Support random MAC up to 2 interfaces
-    if (instances_.size() == 2) {
-        int rbyte = 1;
-        for (auto const& intf : instances_) {
-            std::array<uint8_t, 6> rmac = mac;
-            // reverse the bits to avoid collision
-            rmac[rbyte] = 0xff - rmac[rbyte];
-            if (!iface_util_.lock()->setMacAddress(intf, rmac)) {
-                LOG(INFO) << "Failed to set random mac address on " << intf;
-                return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-            }
-            rbyte++;
-        }
-    }
-    // It also needs to set mac address for bridged interface, otherwise the mac
-    // address of bridged interface will be changed after one of instance
-    // down.
-    if (!iface_util_.lock()->setMacAddress(ifname_, mac)) {
-        LOG(ERROR) << "Fail to config MAC for interface " << ifname_;
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::array<uint8_t, 6>>
-WifiApIface::getFactoryMacAddressInternal(const std::string& ifaceName) {
-    std::array<uint8_t, 6> mac =
-        iface_util_.lock()->getFactoryMacAddress(ifaceName);
-    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 &&
-        mac[4] == 0 && mac[5] == 0) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
-}
-
-WifiStatus WifiApIface::resetToFactoryMacAddressInternal() {
-    std::pair<WifiStatus, std::array<uint8_t, 6>> getMacResult;
-    if (instances_.size() == 2) {
-        for (auto const& intf : instances_) {
-            getMacResult = getFactoryMacAddressInternal(intf);
-            LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
-            if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
-                !iface_util_.lock()->setMacAddress(intf, getMacResult.second)) {
-                return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-            }
-        }
-        // It needs to set mac address for bridged interface, otherwise the mac
-        // address of the bridged interface will be changed after one of the
-        // instance down. Thus we are generating a random MAC address for the
-        // bridged interface even if we got the request to reset the Factory
-        // MAC. Since the bridged interface is an internal interface for the
-        // operation of bpf and others networking operation.
-        if (!iface_util_.lock()->setMacAddress(
-                ifname_, iface_util_.lock()->createRandomMacAddress())) {
-            LOG(ERROR) << "Fail to config MAC for bridged interface "
-                       << ifname_;
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-        }
-    } else {
-        getMacResult = getFactoryMacAddressInternal(ifname_);
-        LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_;
-        if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
-            !iface_util_.lock()->setMacAddress(ifname_, getMacResult.second)) {
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-        }
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiApIface::getBridgedInstancesInternal() {
-    std::vector<hidl_string> instances;
-    for (const auto& instance_name : instances_) {
-        instances.push_back(instance_name);
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), instances};
-}
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_ap_iface.h b/wifi/1.5/default/wifi_ap_iface.h
deleted file mode 100644
index 8f8387d..0000000
--- a/wifi/1.5/default/wifi_ap_iface.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_AP_IFACE_H_
-#define WIFI_AP_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.5/IWifiApIface.h>
-
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a AP Iface instance.
- */
-class WifiApIface : public V1_5::IWifiApIface {
-   public:
-    WifiApIface(const std::string& ifname,
-                const std::vector<std::string>& instances,
-                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-                const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::string getName();
-    void removeInstance(std::string instance);
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
-                                setCountryCode_cb hidl_status_cb) override;
-    Return<void> getValidFrequenciesForBand(
-        V1_0::WifiBand band,
-        getValidFrequenciesForBand_cb hidl_status_cb) override;
-    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                               setMacAddress_cb hidl_status_cb) override;
-    Return<void> getFactoryMacAddress(
-        getFactoryMacAddress_cb hidl_status_cb) override;
-    Return<void> resetToFactoryMacAddress(
-        resetToFactoryMacAddress_cb hidl_status_cb) override;
-
-    Return<void> getBridgedInstances(
-        getBridgedInstances_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
-    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-    getValidFrequenciesForBandInternal(V1_0::WifiBand band);
-    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
-    std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal(
-        const std::string& ifaceName);
-    WifiStatus resetToFactoryMacAddressInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>>
-    getBridgedInstancesInternal();
-
-    std::string ifname_;
-    std::vector<std::string> instances_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiApIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
deleted file mode 100644
index 6bdff42..0000000
--- a/wifi/1.5/default/wifi_chip.cpp
+++ /dev/null
@@ -1,2065 +0,0 @@
-/*
- * Copyright (C) 2016 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 <fcntl.h>
-
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <cutils/properties.h>
-#include <net/if.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_chip.h"
-#include "wifi_status_util.h"
-
-#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
-
-namespace {
-using android::sp;
-using android::base::unique_fd;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::wifi::V1_0::ChipModeId;
-using android::hardware::wifi::V1_0::IfaceType;
-using android::hardware::wifi::V1_0::IWifiChip;
-
-constexpr char kCpioMagic[] = "070701";
-constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
-constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
-constexpr uint32_t kMaxRingBufferFileNum = 20;
-constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
-constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
-constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
-constexpr unsigned kMaxWlanIfaces = 5;
-constexpr char kApBridgeIfacePrefix[] = "ap_br_";
-
-template <typename Iface>
-void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
-    iface->invalidate();
-    ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface),
-                 ifaces.end());
-}
-
-template <typename Iface>
-void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
-    for (const auto& iface : ifaces) {
-        iface->invalidate();
-    }
-    ifaces.clear();
-}
-
-template <typename Iface>
-std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
-    std::vector<hidl_string> names;
-    for (const auto& iface : ifaces) {
-        names.emplace_back(iface->getName());
-    }
-    return names;
-}
-
-template <typename Iface>
-sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces,
-                        const std::string& name) {
-    std::vector<hidl_string> names;
-    for (const auto& iface : ifaces) {
-        if (name == iface->getName()) {
-            return iface;
-        }
-    }
-    return nullptr;
-}
-
-std::string getWlanIfaceName(unsigned idx) {
-    if (idx >= kMaxWlanIfaces) {
-        CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
-        return {};
-    }
-
-    std::array<char, PROPERTY_VALUE_MAX> buffer;
-    if (idx == 0 || idx == 1) {
-        const char* altPropName =
-            (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
-        auto res = property_get(altPropName, buffer.data(), nullptr);
-        if (res > 0) return buffer.data();
-    }
-    std::string propName = "wifi.interface." + std::to_string(idx);
-    auto res = property_get(propName.c_str(), buffer.data(), nullptr);
-    if (res > 0) return buffer.data();
-
-    return "wlan" + std::to_string(idx);
-}
-
-// Returns the dedicated iface name if defined.
-// Returns two ifaces in bridged mode.
-std::vector<std::string> getPredefinedApIfaceNames(bool is_bridged) {
-    std::vector<std::string> ifnames;
-    std::array<char, PROPERTY_VALUE_MAX> buffer;
-    buffer.fill(0);
-    if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) ==
-        0) {
-        return ifnames;
-    }
-    ifnames.push_back(buffer.data());
-    if (is_bridged) {
-        buffer.fill(0);
-        if (property_get("ro.vendor.wifi.sap.concurrent.iface", buffer.data(),
-                         nullptr) == 0) {
-            return ifnames;
-        }
-        ifnames.push_back(buffer.data());
-    }
-    return ifnames;
-}
-
-std::string getPredefinedP2pIfaceName() {
-    std::array<char, PROPERTY_VALUE_MAX> primaryIfaceName;
-    char p2pParentIfname[100];
-    std::string p2pDevIfName = "";
-    std::array<char, PROPERTY_VALUE_MAX> buffer;
-    property_get("wifi.direct.interface", buffer.data(), "p2p0");
-    if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX,
-                strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
-        /* Get the p2p parent interface name from p2p device interface name set
-         * in property */
-        strncpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX),
-                strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX));
-        if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(),
-                         nullptr) == 0) {
-            return buffer.data();
-        }
-        /* Check if the parent interface derived from p2p device interface name
-         * is active */
-        if (strncmp(p2pParentIfname, primaryIfaceName.data(),
-                    strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) !=
-            0) {
-            /*
-             * Update the predefined p2p device interface parent interface name
-             * with current active wlan interface
-             */
-            p2pDevIfName += P2P_MGMT_DEVICE_PREFIX;
-            p2pDevIfName += primaryIfaceName.data();
-            LOG(INFO) << "update the p2p device interface name to "
-                      << p2pDevIfName.c_str();
-            return p2pDevIfName;
-        }
-    }
-    return buffer.data();
-}
-
-// Returns the dedicated iface name if one is defined.
-std::string getPredefinedNanIfaceName() {
-    std::array<char, PROPERTY_VALUE_MAX> buffer;
-    if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) {
-        return {};
-    }
-    return buffer.data();
-}
-
-void setActiveWlanIfaceNameProperty(const std::string& ifname) {
-    auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
-    if (res != 0) {
-        PLOG(ERROR) << "Failed to set active wlan iface name property";
-    }
-}
-
-// delete files that meet either conditions:
-// 1. older than a predefined time in the wifi tombstone dir.
-// 2. Files in excess to a predefined amount, starting from the oldest ones
-bool removeOldFilesInternal() {
-    time_t now = time(0);
-    const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
-    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(
-        opendir(kTombstoneFolderPath), closedir);
-    if (!dir_dump) {
-        PLOG(ERROR) << "Failed to open directory";
-        return false;
-    }
-    struct dirent* dp;
-    bool success = true;
-    std::list<std::pair<const time_t, std::string>> valid_files;
-    while ((dp = readdir(dir_dump.get()))) {
-        if (dp->d_type != DT_REG) {
-            continue;
-        }
-        std::string cur_file_name(dp->d_name);
-        struct stat cur_file_stat;
-        std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
-        if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
-            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
-            success = false;
-            continue;
-        }
-        const time_t cur_file_time = cur_file_stat.st_mtime;
-        valid_files.push_back(
-            std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
-    }
-    valid_files.sort();  // sort the list of files by last modified time from
-                         // small to big.
-    uint32_t cur_file_count = valid_files.size();
-    for (auto cur_file : valid_files) {
-        if (cur_file_count > kMaxRingBufferFileNum ||
-            cur_file.first < delete_files_before) {
-            if (unlink(cur_file.second.c_str()) != 0) {
-                PLOG(ERROR) << "Error deleting file";
-                success = false;
-            }
-            cur_file_count--;
-        } else {
-            break;
-        }
-    }
-    return success;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name,
-                     size_t file_name_len) {
-    std::array<char, 32 * 1024> read_buf;
-    ssize_t llen =
-        sprintf(read_buf.data(),
-                "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
-                kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid,
-                st.st_gid, static_cast<int>(st.st_nlink),
-                static_cast<int>(st.st_mtime), static_cast<int>(st.st_size),
-                major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
-                minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
-    if (write(out_fd, read_buf.data(), llen) == -1) {
-        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
-        return false;
-    }
-    if (write(out_fd, file_name, file_name_len) == -1) {
-        PLOG(ERROR) << "Error writing filename to file " << file_name;
-        return false;
-    }
-
-    // NUL Pad header up to 4 multiple bytes.
-    llen = (llen + file_name_len) % 4;
-    if (llen != 0) {
-        const uint32_t zero = 0;
-        if (write(out_fd, &zero, 4 - llen) == -1) {
-            PLOG(ERROR) << "Error padding 0s to file " << file_name;
-            return false;
-        }
-    }
-    return true;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
-    // writing content of file
-    std::array<char, 32 * 1024> read_buf;
-    ssize_t llen = st.st_size;
-    size_t n_error = 0;
-    while (llen > 0) {
-        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
-        if (bytes_read == -1) {
-            PLOG(ERROR) << "Error reading file";
-            return ++n_error;
-        }
-        llen -= bytes_read;
-        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
-            PLOG(ERROR) << "Error writing data to file";
-            return ++n_error;
-        }
-        if (bytes_read == 0) {  // this should never happen, but just in case
-                                // to unstuck from while loop
-            PLOG(ERROR) << "Unexpected read result";
-            n_error++;
-            break;
-        }
-    }
-    llen = st.st_size % 4;
-    if (llen != 0) {
-        const uint32_t zero = 0;
-        if (write(out_fd, &zero, 4 - llen) == -1) {
-            PLOG(ERROR) << "Error padding 0s to file";
-            return ++n_error;
-        }
-    }
-    return n_error;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteFileTrailer(int out_fd) {
-    std::array<char, 4096> read_buf;
-    read_buf.fill(0);
-    if (write(out_fd, read_buf.data(),
-              sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1,
-                      0x0b, 0) +
-                  4) == -1) {
-        PLOG(ERROR) << "Error writing trailing bytes";
-        return false;
-    }
-    return true;
-}
-
-// Archives all files in |input_dir| and writes result into |out_fd|
-// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
-// portion
-size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
-    struct dirent* dp;
-    size_t n_error = 0;
-    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir),
-                                                       closedir);
-    if (!dir_dump) {
-        PLOG(ERROR) << "Failed to open directory";
-        return ++n_error;
-    }
-    while ((dp = readdir(dir_dump.get()))) {
-        if (dp->d_type != DT_REG) {
-            continue;
-        }
-        std::string cur_file_name(dp->d_name);
-        struct stat st;
-        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
-        if (stat(cur_file_path.c_str(), &st) == -1) {
-            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
-            n_error++;
-            continue;
-        }
-        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
-        if (fd_read == -1) {
-            PLOG(ERROR) << "Failed to open file " << cur_file_path;
-            n_error++;
-            continue;
-        }
-        std::string file_name_with_last_modified_time =
-            cur_file_name + "-" + std::to_string(st.st_mtime);
-        // string.size() does not include the null terminator. The cpio FreeBSD
-        // file header expects the null character to be included in the length.
-        const size_t file_name_len =
-            file_name_with_last_modified_time.size() + 1;
-        unique_fd file_auto_closer(fd_read);
-        if (!cpioWriteHeader(out_fd, st,
-                             file_name_with_last_modified_time.c_str(),
-                             file_name_len)) {
-            return ++n_error;
-        }
-        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
-        if (write_error) {
-            return n_error + write_error;
-        }
-    }
-    if (!cpioWriteFileTrailer(out_fd)) {
-        return ++n_error;
-    }
-    return n_error;
-}
-
-// Helper function to create a non-const char*.
-std::vector<char> makeCharVec(const std::string& str) {
-    std::vector<char> vec(str.size() + 1);
-    vec.assign(str.begin(), str.end());
-    vec.push_back('\0');
-    return vec;
-}
-
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-WifiChip::WifiChip(
-    ChipId chip_id, bool is_primary,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
-    const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
-    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
-    const std::function<void(const std::string&)>& handler)
-    : chip_id_(chip_id),
-      legacy_hal_(legacy_hal),
-      mode_controller_(mode_controller),
-      iface_util_(iface_util),
-      is_valid_(true),
-      current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
-      modes_(feature_flags.lock()->getChipModes(is_primary)),
-      debug_ring_buffer_cb_registered_(false),
-      subsystemCallbackHandler_(handler) {
-    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
-}
-
-void WifiChip::invalidate() {
-    if (!writeRingbufferFilesInternal()) {
-        LOG(ERROR) << "Error writing files to flash";
-    }
-    invalidateAndRemoveAllIfaces();
-    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
-    legacy_hal_.reset();
-    event_cb_handler_.invalidate();
-    is_valid_ = false;
-}
-
-bool WifiChip::isValid() { return is_valid_; }
-
-std::set<sp<V1_4::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getIdInternal, hidl_status_cb);
-}
-
-// Deprecated support for this callback
-Return<void> WifiChip::registerEventCallback(
-    const sp<V1_0::IWifiChipEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal,
-                           hidl_status_cb, event_callback);
-}
-
-Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getAvailableModesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::configureChip(ChipModeId mode_id,
-                                     configureChip_cb hidl_status_cb) {
-    return validateAndCallWithLock(
-        this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-        &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
-}
-
-Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getModeInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::requestChipDebugInfo(
-    requestChipDebugInfo_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestChipDebugInfoInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::requestDriverDebugDump(
-    requestDriverDebugDump_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestDriverDebugDumpInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::requestFirmwareDebugDump(
-    requestFirmwareDebugDump_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestFirmwareDebugDumpInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createApIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::createBridgedApIface(
-    createBridgedApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createBridgedApIfaceInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIface(const hidl_string& ifname,
-                                  getApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getApIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeApIface(const hidl_string& ifname,
-                                     removeApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeApIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeIfaceInstanceFromBridgedApIface(
-    const hidl_string& ifname, const hidl_string& ifInstanceName,
-    removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-        &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal,
-        hidl_status_cb, ifname, ifInstanceName);
-}
-
-Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createNanIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIface(const hidl_string& ifname,
-                                   getNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getNanIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeNanIface(const hidl_string& ifname,
-                                      removeNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeNanIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createP2pIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIface(const hidl_string& ifname,
-                                   getP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getP2pIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeP2pIface(const hidl_string& ifname,
-                                      removeP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeP2pIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createStaIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIface(const hidl_string& ifname,
-                                   getStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getStaIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
-                                      removeStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeStaIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::createRttController(
-    const sp<IWifiIface>& bound_iface, createRttController_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createRttControllerInternal,
-                           hidl_status_cb, bound_iface);
-}
-
-Return<void> WifiChip::getDebugRingBuffersStatus(
-    getDebugRingBuffersStatus_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getDebugRingBuffersStatusInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::startLoggingToDebugRingBuffer(
-    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
-    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
-    startLoggingToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::startLoggingToDebugRingBufferInternal,
-                           hidl_status_cb, ring_name, verbose_level,
-                           max_interval_in_sec, min_data_size_in_bytes);
-}
-
-Return<void> WifiChip::forceDumpToDebugRingBuffer(
-    const hidl_string& ring_name,
-    forceDumpToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::forceDumpToDebugRingBufferInternal,
-                           hidl_status_cb, ring_name);
-}
-
-Return<void> WifiChip::flushRingBufferToFile(
-    flushRingBufferToFile_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::flushRingBufferToFileInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::stopLoggingToDebugRingBuffer(
-    stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::stopLoggingToDebugRingBufferInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::getDebugHostWakeReasonStats(
-    getDebugHostWakeReasonStats_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getDebugHostWakeReasonStatsInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::enableDebugErrorAlerts(
-    bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::enableDebugErrorAlertsInternal,
-                           hidl_status_cb, enable);
-}
-
-Return<void> WifiChip::selectTxPowerScenario(
-    V1_1::IWifiChip::TxPowerScenario scenario,
-    selectTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::selectTxPowerScenarioInternal,
-                           hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::resetTxPowerScenario(
-    resetTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::resetTxPowerScenarioInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::setLatencyMode(LatencyMode mode,
-                                      setLatencyMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setLatencyModeInternal, hidl_status_cb,
-                           mode);
-}
-
-Return<void> WifiChip::registerEventCallback_1_2(
-    const sp<V1_2::IWifiChipEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal_1_2,
-                           hidl_status_cb, event_callback);
-}
-
-Return<void> WifiChip::selectTxPowerScenario_1_2(
-    TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::selectTxPowerScenarioInternal_1_2,
-                           hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal_1_3,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::getCapabilities_1_5(
-    getCapabilities_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal_1_5,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::debug(const hidl_handle& handle,
-                             const hidl_vec<hidl_string>&) {
-    if (handle != nullptr && handle->numFds >= 1) {
-        {
-            std::unique_lock<std::mutex> lk(lock_t);
-            for (const auto& item : ringbuffer_map_) {
-                forceDumpToDebugRingBufferInternal(item.first);
-            }
-            // unique_lock unlocked here
-        }
-        usleep(100 * 1000);  // sleep for 100 milliseconds to wait for
-                             // ringbuffer updates.
-        int fd = handle->data[0];
-        if (!writeRingbufferFilesInternal()) {
-            LOG(ERROR) << "Error writing files to flash";
-        }
-        uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
-        if (n_error != 0) {
-            LOG(ERROR) << n_error << " errors occured in cpio function";
-        }
-        fsync(fd);
-    } else {
-        LOG(ERROR) << "File handle error";
-    }
-    return Void();
-}
-
-Return<void> WifiChip::createRttController_1_4(
-    const sp<IWifiIface>& bound_iface,
-    createRttController_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createRttControllerInternal_1_4,
-                           hidl_status_cb, bound_iface);
-}
-
-Return<void> WifiChip::registerEventCallback_1_4(
-    const sp<V1_4::IWifiChipEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal_1_4,
-                           hidl_status_cb, event_callback);
-}
-
-Return<void> WifiChip::setMultiStaPrimaryConnection(
-    const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setMultiStaPrimaryConnectionInternal,
-                           hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::setMultiStaUseCase(
-    MultiStaUseCase use_case, setMultiStaUseCase_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setMultiStaUseCaseInternal,
-                           hidl_status_cb, use_case);
-}
-
-Return<void> WifiChip::setCoexUnsafeChannels(
-    const hidl_vec<CoexUnsafeChannel>& unsafeChannels,
-    hidl_bitfield<CoexRestriction> restrictions,
-    setCoexUnsafeChannels_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setCoexUnsafeChannelsInternal,
-                           hidl_status_cb, unsafeChannels, restrictions);
-}
-
-Return<void> WifiChip::setCountryCode(const hidl_array<int8_t, 2>& code,
-                                      setCountryCode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiChip::setCountryCodeInternal, hidl_status_cb,
-                           code);
-}
-
-Return<void> WifiChip::getUsableChannels(
-    WifiBand band, hidl_bitfield<WifiIfaceMode> ifaceModeMask,
-    hidl_bitfield<UsableChannelFilter> filterMask,
-    getUsableChannels_cb _hidl_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getUsableChannelsInternal, _hidl_cb, band,
-                           ifaceModeMask, filterMask);
-}
-
-Return<void> WifiChip::triggerSubsystemRestart(
-    triggerSubsystemRestart_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::triggerSubsystemRestartInternal,
-                           hidl_status_cb);
-}
-
-void WifiChip::invalidateAndRemoveAllIfaces() {
-    invalidateAndClearBridgedApAll();
-    invalidateAndClearAll(ap_ifaces_);
-    invalidateAndClearAll(nan_ifaces_);
-    invalidateAndClearAll(p2p_ifaces_);
-    invalidateAndClearAll(sta_ifaces_);
-    // Since all the ifaces are invalid now, all RTT controller objects
-    // using those ifaces also need to be invalidated.
-    for (const auto& rtt : rtt_controllers_) {
-        rtt->invalidate();
-    }
-    rtt_controllers_.clear();
-}
-
-void WifiChip::invalidateAndRemoveDependencies(
-    const std::string& removed_iface_name) {
-    for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
-        auto nan_iface = *it;
-        if (nan_iface->getName() == removed_iface_name) {
-            nan_iface->invalidate();
-            for (const auto& callback : event_cb_handler_.getCallbacks()) {
-                if (!callback
-                         ->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-                }
-            }
-            it = nan_ifaces_.erase(it);
-        } else {
-            ++it;
-        }
-    }
-
-    for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
-        auto rtt = *it;
-        if (rtt->getIfaceName() == removed_iface_name) {
-            rtt->invalidate();
-            it = rtt_controllers_.erase(it);
-        } else {
-            ++it;
-        }
-    }
-}
-
-std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal(
-    const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
-    // Deprecated support for this callback.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
-    // Deprecated support for this callback.
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
-}
-
-std::pair<WifiStatus, std::vector<V1_4::IWifiChip::ChipMode>>
-WifiChip::getAvailableModesInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
-}
-
-WifiStatus WifiChip::configureChipInternal(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
-    ChipModeId mode_id) {
-    if (!isValidModeId(mode_id)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    if (mode_id == current_mode_id_) {
-        LOG(DEBUG) << "Already in the specified mode " << mode_id;
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    }
-    WifiStatus status = handleChipConfiguration(lock, mode_id);
-    if (status.code != WifiStatusCode::SUCCESS) {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onChipReconfigureFailure(status).isOk()) {
-                LOG(ERROR)
-                    << "Failed to invoke onChipReconfigureFailure callback";
-            }
-        }
-        return status;
-    }
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onChipReconfigured(mode_id).isOk()) {
-            LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
-        }
-    }
-    current_mode_id_ = mode_id;
-    LOG(INFO) << "Configured chip in mode " << mode_id;
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-
-    legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(
-        subsystemCallbackHandler_);
-
-    return status;
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
-    if (!isValidModeId(current_mode_id_)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
-                current_mode_id_};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
-}
-
-std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo>
-WifiChip::requestChipDebugInfoInternal() {
-    V1_4::IWifiChip::ChipDebugInfo result;
-    legacy_hal::wifi_error legacy_status;
-    std::string driver_desc;
-    const auto ifname = getFirstActiveWlanIfaceName();
-    std::tie(legacy_status, driver_desc) =
-        legacy_hal_.lock()->getDriverVersion(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get driver version: "
-                   << legacyErrorToString(legacy_status);
-        WifiStatus status = createWifiStatusFromLegacyError(
-            legacy_status, "failed to get driver version");
-        return {status, result};
-    }
-    result.driverDescription = driver_desc.c_str();
-
-    std::string firmware_desc;
-    std::tie(legacy_status, firmware_desc) =
-        legacy_hal_.lock()->getFirmwareVersion(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get firmware version: "
-                   << legacyErrorToString(legacy_status);
-        WifiStatus status = createWifiStatusFromLegacyError(
-            legacy_status, "failed to get firmware version");
-        return {status, result};
-    }
-    result.firmwareDescription = firmware_desc.c_str();
-
-    return {createWifiStatus(WifiStatusCode::SUCCESS), result};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestDriverDebugDumpInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint8_t> driver_dump;
-    std::tie(legacy_status, driver_dump) =
-        legacy_hal_.lock()->requestDriverMemoryDump(
-            getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get driver debug dump: "
-                   << legacyErrorToString(legacy_status);
-        return {createWifiStatusFromLegacyError(legacy_status),
-                std::vector<uint8_t>()};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestFirmwareDebugDumpInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint8_t> firmware_dump;
-    std::tie(legacy_status, firmware_dump) =
-        legacy_hal_.lock()->requestFirmwareMemoryDump(
-            getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get firmware debug dump: "
-                   << legacyErrorToString(legacy_status);
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
-}
-
-WifiStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
-    legacy_hal::wifi_error legacy_status;
-    legacy_status = legacy_hal_.lock()->createVirtualInterface(
-        apVirtIf,
-        hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-sp<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
-    std::vector<std::string> ap_instances;
-    for (auto const& it : br_ifaces_ap_instances_) {
-        if (it.first == ifname) {
-            ap_instances = it.second;
-        }
-    }
-    sp<WifiApIface> iface =
-        new WifiApIface(ifname, ap_instances, legacy_hal_, iface_util_);
-    ap_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return iface;
-}
-
-std::pair<WifiStatus, sp<V1_5::IWifiApIface>>
-WifiChip::createApIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = allocateApIfaceName();
-    WifiStatus status = createVirtualApInterface(ifname);
-    if (status.code != WifiStatusCode::SUCCESS) {
-        return {status, {}};
-    }
-    sp<WifiApIface> iface = newWifiApIface(ifname);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, sp<V1_5::IWifiApIface>>
-WifiChip::createBridgedApIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
-    if (ap_instances.size() < 2) {
-        LOG(ERROR) << "Fail to allocate two instances";
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
-    for (int i = 0; i < 2; i++) {
-        WifiStatus status = createVirtualApInterface(ap_instances[i]);
-        if (status.code != WifiStatusCode::SUCCESS) {
-            if (i != 0) {  // The failure happened when creating second virtual
-                           // iface.
-                legacy_hal_.lock()->deleteVirtualInterface(
-                    ap_instances.front());  // Remove the first virtual iface.
-            }
-            return {status, {}};
-        }
-    }
-    br_ifaces_ap_instances_[br_ifname] = ap_instances;
-    if (!iface_util_->createBridge(br_ifname)) {
-        LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
-        invalidateAndClearBridgedAp(br_ifname);
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    for (auto const& instance : ap_instances) {
-        // Bind ap instance interface to AP bridge
-        if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
-            LOG(ERROR) << "Failed add if to Bridge - if_name="
-                       << instance.c_str();
-            invalidateAndClearBridgedAp(br_ifname);
-            return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-        }
-    }
-    sp<WifiApIface> iface = newWifiApIface(br_ifname);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getApIfaceNamesInternal() {
-    if (ap_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::getApIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(ap_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(ap_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    // Invalidate & remove any dependent objects first.
-    // Note: This is probably not required because we never create
-    // nan/rtt objects over AP iface. But, there is no harm to do it
-    // here and not make that assumption all over the place.
-    invalidateAndRemoveDependencies(ifname);
-    // Clear the bridge interface and the iface instance.
-    invalidateAndClearBridgedAp(ifname);
-    invalidateAndClear(ap_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal(
-    const std::string& ifname, const std::string& ifInstanceName) {
-    const auto iface = findUsingName(ap_ifaces_, ifname);
-    if (!iface.get() || ifInstanceName.empty()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    // Requires to remove one of the instance in bridge mode
-    for (auto const& it : br_ifaces_ap_instances_) {
-        if (it.first == ifname) {
-            std::vector<std::string> ap_instances = it.second;
-            for (auto const& iface : ap_instances) {
-                if (iface == ifInstanceName) {
-                    if (!iface_util_->removeIfaceFromBridge(it.first, iface)) {
-                        LOG(ERROR)
-                            << "Failed to remove interface: " << ifInstanceName
-                            << " from " << ifname;
-                        return createWifiStatus(
-                            WifiStatusCode::ERROR_NOT_AVAILABLE);
-                    }
-                    legacy_hal::wifi_error legacy_status =
-                        legacy_hal_.lock()->deleteVirtualInterface(iface);
-                    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-                        LOG(ERROR) << "Failed to del interface: " << iface
-                                   << " " << legacyErrorToString(legacy_status);
-                        return createWifiStatusFromLegacyError(legacy_status);
-                    }
-                    ap_instances.erase(
-                        std::remove(ap_instances.begin(), ap_instances.end(),
-                                    ifInstanceName),
-                        ap_instances.end());
-                    br_ifaces_ap_instances_[ifname] = ap_instances;
-                    break;
-                }
-            }
-            break;
-        }
-    }
-    iface->removeInstance(ifInstanceName);
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiNanIface>>
-WifiChip::createNanIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    bool is_dedicated_iface = true;
-    std::string ifname = getPredefinedNanIfaceName();
-    if (ifname.empty() || !iface_util_->ifNameToIndex(ifname)) {
-        // Use the first shared STA iface (wlan0) if a dedicated aware iface is
-        // not defined.
-        ifname = getFirstActiveWlanIfaceName();
-        is_dedicated_iface = false;
-    }
-    sp<WifiNanIface> iface =
-        new WifiNanIface(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
-    nan_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getNanIfaceNamesInternal() {
-    if (nan_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::getNanIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(nan_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(nan_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    invalidateAndClear(nan_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = getPredefinedP2pIfaceName();
-    sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
-    p2p_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getP2pIfaceNamesInternal() {
-    if (p2p_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(p2p_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(p2p_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    invalidateAndClear(p2p_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-        }
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<V1_5::IWifiStaIface>>
-WifiChip::createStaIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = allocateStaIfaceName();
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->createVirtualInterface(
-            ifname,
-            hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to add interface: " << ifname << " "
-                   << legacyErrorToString(legacy_status);
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
-    sta_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getStaIfaceNamesInternal() {
-    if (sta_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> WifiChip::getStaIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(sta_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(sta_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    // Invalidate & remove any dependent objects first.
-    invalidateAndRemoveDependencies(ifname);
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->deleteVirtualInterface(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
-                   << legacyErrorToString(legacy_status);
-    }
-    invalidateAndClear(sta_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
-WifiChip::createRttControllerInternal(const sp<IWifiIface>& /*bound_iface*/) {
-    LOG(ERROR) << "createRttController is not supported on this HAL";
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-WifiChip::getDebugRingBuffersStatusInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<legacy_hal::wifi_ring_buffer_status>
-        legacy_ring_buffer_status_vec;
-    std::tie(legacy_status, legacy_ring_buffer_status_vec) =
-        legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
-            legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS),
-            hidl_ring_buffer_status_vec};
-}
-
-WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
-    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
-    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
-    WifiStatus status = registerDebugRingBufferCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        return status;
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startRingBufferLogging(
-            getFirstActiveWlanIfaceName(), ring_name,
-            static_cast<
-                std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
-                verbose_level),
-            max_interval_in_sec, min_data_size_in_bytes);
-    ringbuffer_map_.insert(std::pair<std::string, Ringbuffer>(
-        ring_name, Ringbuffer(kMaxBufferSizeBytes)));
-    // if verbose logging enabled, turn up HAL daemon logging as well.
-    if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) {
-        android::base::SetMinimumLogSeverity(android::base::DEBUG);
-    } else {
-        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-    }
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
-    const hidl_string& ring_name) {
-    WifiStatus status = registerDebugRingBufferCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        return status;
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(),
-                                              ring_name);
-
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::flushRingBufferToFileInternal() {
-    if (!writeRingbufferFilesInternal()) {
-        LOG(ERROR) << "Error writing files to flash";
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
-            getFirstActiveWlanIfaceName());
-    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
-        debug_ring_buffer_cb_registered_ = false;
-    }
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
-WifiChip::getDebugHostWakeReasonStatsInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::WakeReasonStats legacy_stats;
-    std::tie(legacy_status, legacy_stats) =
-        legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    WifiDebugHostWakeReasonStats hidl_stats;
-    if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
-                                                              &hidl_stats)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
-    legacy_hal::wifi_error legacy_status;
-    if (enable) {
-        android::wp<WifiChip> weak_ptr_this(this);
-        const auto& on_alert_callback = [weak_ptr_this](
-                                            int32_t error_code,
-                                            std::vector<uint8_t> debug_data) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onDebugErrorAlert(error_code, debug_data)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
-                }
-            }
-        };
-        legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
-            getFirstActiveWlanIfaceName(), on_alert_callback);
-    } else {
-        legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
-            getFirstActiveWlanIfaceName());
-    }
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal(
-    V1_1::IWifiChip::TxPowerScenario scenario) {
-    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-        getFirstActiveWlanIfaceName(),
-        hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::resetTxPowerScenarioInternal() {
-    auto legacy_status =
-        legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
-    auto legacy_status = legacy_hal_.lock()->setLatencyMode(
-        getFirstActiveWlanIfaceName(),
-        hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal_1_2(
-    const sp<V1_2::IWifiChipEventCallback>& /* event_callback */) {
-    // Deprecated support for this callback.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
-    TxPowerScenario scenario) {
-    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-        getFirstActiveWlanIfaceName(),
-        hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
-    // Deprecated support for this callback.
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_5() {
-    legacy_hal::wifi_error legacy_status;
-    uint64_t legacy_feature_set;
-    uint32_t legacy_logger_feature_set;
-    const auto ifname = getFirstActiveWlanIfaceName();
-    std::tie(legacy_status, legacy_feature_set) =
-        legacy_hal_.lock()->getSupportedFeatureSet(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), 0};
-    }
-    std::tie(legacy_status, legacy_logger_feature_set) =
-        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        // some devices don't support querying logger feature set
-        legacy_logger_feature_set = 0;
-    }
-    uint32_t hidl_caps;
-    if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
-            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiRttController>>
-WifiChip::createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface) {
-    if (sta_ifaces_.size() == 0 &&
-        !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
-        LOG(ERROR)
-            << "createRttControllerInternal_1_4: Chip cannot support STAs "
-               "(and RTT by extension)";
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    sp<WifiRttController> rtt = new WifiRttController(
-        getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
-    rtt_controllers_.emplace_back(rtt);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal_1_4(
-    const sp<V1_4::IWifiChipEventCallback>& event_callback) {
-    if (!event_cb_handler_.addCallback(event_callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::setMultiStaPrimaryConnectionInternal(
-    const std::string& ifname) {
-    auto legacy_status =
-        legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setMultiStaUseCaseInternal(MultiStaUseCase use_case) {
-    auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase(
-        hidl_struct_util::convertHidlMultiStaUseCaseToLegacy(use_case));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setCoexUnsafeChannelsInternal(
-    std::vector<CoexUnsafeChannel> unsafe_channels, uint32_t restrictions) {
-    std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
-    if (!hidl_struct_util::convertHidlVectorOfCoexUnsafeChannelToLegacy(
-            unsafe_channels, &legacy_unsafe_channels)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    uint32_t legacy_restrictions = 0;
-    if (restrictions & CoexRestriction::WIFI_DIRECT) {
-        legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_DIRECT;
-    }
-    if (restrictions & CoexRestriction::SOFTAP) {
-        legacy_restrictions |= legacy_hal::wifi_coex_restriction::SOFTAP;
-    }
-    if (restrictions & CoexRestriction::WIFI_AWARE) {
-        legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_AWARE;
-    }
-    auto legacy_status = legacy_hal_.lock()->setCoexUnsafeChannels(
-        legacy_unsafe_channels, legacy_restrictions);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setCountryCodeInternal(const std::array<int8_t, 2>& code) {
-    auto legacy_status =
-        legacy_hal_.lock()->setCountryCode(getFirstActiveWlanIfaceName(), code);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiUsableChannel>>
-WifiChip::getUsableChannelsInternal(WifiBand band, uint32_t ifaceModeMask,
-                                    uint32_t filterMask) {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<legacy_hal::wifi_usable_channel> legacy_usable_channels;
-    std::tie(legacy_status, legacy_usable_channels) =
-        legacy_hal_.lock()->getUsableChannels(
-            hidl_struct_util::convertHidlWifiBandToLegacyMacBand(band),
-            hidl_struct_util::convertHidlWifiIfaceModeToLegacy(ifaceModeMask),
-            hidl_struct_util::convertHidlUsableChannelFilterToLegacy(
-                filterMask));
-
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiUsableChannel> hidl_usable_channels;
-    if (!hidl_struct_util::convertLegacyWifiUsableChannelsToHidl(
-            legacy_usable_channels, &hidl_usable_channels)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_usable_channels};
-}
-
-WifiStatus WifiChip::triggerSubsystemRestartInternal() {
-    auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::handleChipConfiguration(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
-    ChipModeId mode_id) {
-    // If the chip is already configured in a different mode, stop
-    // the legacy HAL and then start it after firmware mode change.
-    if (isValidModeId(current_mode_id_)) {
-        LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
-                  << " to mode " << mode_id;
-        invalidateAndRemoveAllIfaces();
-        legacy_hal::wifi_error legacy_status =
-            legacy_hal_.lock()->stop(lock, []() {});
-        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-            LOG(ERROR) << "Failed to stop legacy HAL: "
-                       << legacyErrorToString(legacy_status);
-            return createWifiStatusFromLegacyError(legacy_status);
-        }
-    }
-    // Firmware mode change not needed for V2 devices.
-    bool success = true;
-    if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
-        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
-    } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
-        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
-    }
-    if (!success) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to start legacy HAL: "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
-    }
-    // Every time the HAL is restarted, we need to register the
-    // radio mode change callback.
-    WifiStatus status = registerRadioModeChangeCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        // This probably is not a critical failure?
-        LOG(ERROR) << "Failed to register radio mode change callback";
-    }
-    // Extract and save the version information into property.
-    std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> version_info;
-    version_info = WifiChip::requestChipDebugInfoInternal();
-    if (WifiStatusCode::SUCCESS == version_info.first.code) {
-        property_set("vendor.wlan.firmware.version",
-                     version_info.second.firmwareDescription.c_str());
-        property_set("vendor.wlan.driver.version",
-                     version_info.second.driverDescription.c_str());
-    }
-
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::registerDebugRingBufferCallback() {
-    if (debug_ring_buffer_cb_registered_) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    }
-
-    android::wp<WifiChip> weak_ptr_this(this);
-    const auto& on_ring_buffer_data_callback =
-        [weak_ptr_this](const std::string& name,
-                        const std::vector<uint8_t>& data,
-                        const legacy_hal::wifi_ring_buffer_status& status) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiDebugRingBufferStatus hidl_status;
-            if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(
-                    status, &hidl_status)) {
-                LOG(ERROR) << "Error converting ring buffer status";
-                return;
-            }
-            {
-                std::unique_lock<std::mutex> lk(shared_ptr_this->lock_t);
-                const auto& target =
-                    shared_ptr_this->ringbuffer_map_.find(name);
-                if (target != shared_ptr_this->ringbuffer_map_.end()) {
-                    Ringbuffer& cur_buffer = target->second;
-                    cur_buffer.append(data);
-                } else {
-                    LOG(ERROR) << "Ringname " << name << " not found";
-                    return;
-                }
-                // unique_lock unlocked here
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->registerRingBufferCallbackHandler(
-            getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
-
-    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
-        debug_ring_buffer_cb_registered_ = true;
-    }
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::registerRadioModeChangeCallback() {
-    android::wp<WifiChip> weak_ptr_this(this);
-    const auto& on_radio_mode_change_callback =
-        [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>
-                hidl_radio_mode_infos;
-            if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-                    mac_infos, &hidl_radio_mode_infos)) {
-                LOG(ERROR) << "Error converting wifi mac info";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4"
-                               << " callback on: " << toString(callback);
-                }
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
-            getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::vector<V1_4::IWifiChip::ChipIfaceCombination>
-WifiChip::getCurrentModeIfaceCombinations() {
-    if (!isValidModeId(current_mode_id_)) {
-        LOG(ERROR) << "Chip not configured in a mode yet";
-        return {};
-    }
-    for (const auto& mode : modes_) {
-        if (mode.id == current_mode_id_) {
-            return mode.availableCombinations;
-        }
-    }
-    CHECK(0) << "Expected to find iface combinations for current mode!";
-    return {};
-}
-
-// Returns a map indexed by IfaceType with the number of ifaces currently
-// created of the corresponding type.
-std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
-    std::map<IfaceType, size_t> iface_counts;
-    iface_counts[IfaceType::AP] = ap_ifaces_.size();
-    iface_counts[IfaceType::NAN] = nan_ifaces_.size();
-    iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
-    iface_counts[IfaceType::STA] = sta_ifaces_.size();
-    return iface_counts;
-}
-
-// This expands the provided iface combinations to a more parseable
-// form. Returns a vector of available combinations possible with the number
-// of ifaces of each type in the combination.
-// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
-std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
-    const V1_4::IWifiChip::ChipIfaceCombination& combination) {
-    uint32_t num_expanded_combos = 1;
-    for (const auto& limit : combination.limits) {
-        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
-            num_expanded_combos *= limit.types.size();
-        }
-    }
-
-    // Allocate the vector of expanded combos and reset all iface counts to 0
-    // in each combo.
-    std::vector<std::map<IfaceType, size_t>> expanded_combos;
-    expanded_combos.resize(num_expanded_combos);
-    for (auto& expanded_combo : expanded_combos) {
-        for (const auto type :
-             {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
-            expanded_combo[type] = 0;
-        }
-    }
-    uint32_t span = num_expanded_combos;
-    for (const auto& limit : combination.limits) {
-        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
-            span /= limit.types.size();
-            for (uint32_t k = 0; k < num_expanded_combos; ++k) {
-                const auto iface_type =
-                    limit.types[(k / span) % limit.types.size()];
-                expanded_combos[k][iface_type]++;
-            }
-        }
-    }
-    return expanded_combos;
-}
-
-bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
-    const std::map<IfaceType, size_t>& expanded_combo,
-    IfaceType requested_type) {
-    const auto current_combo = getCurrentIfaceCombination();
-
-    // Check if we have space for 1 more iface of |type| in this combo
-    for (const auto type :
-         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
-        size_t num_ifaces_needed = current_combo.at(type);
-        if (type == requested_type) {
-            num_ifaces_needed++;
-        }
-        size_t num_ifaces_allowed = expanded_combo.at(type);
-        if (num_ifaces_needed > num_ifaces_allowed) {
-            return false;
-        }
-    }
-    return true;
-}
-
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-//    ChipIfaceCombination.
-// b) Check if the requested iface type can be added to the current mode
-//    with the iface combination that is already active.
-bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
-    IfaceType requested_type) {
-    if (!isValidModeId(current_mode_id_)) {
-        LOG(ERROR) << "Chip not configured in a mode yet";
-        return false;
-    }
-    const auto combinations = getCurrentModeIfaceCombinations();
-    for (const auto& combination : combinations) {
-        const auto expanded_combos = expandIfaceCombinations(combination);
-        for (const auto& expanded_combo : expanded_combos) {
-            if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
-                    expanded_combo, requested_type)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-// Note: This does not consider ifaces already active. It only checks if the
-// provided expanded iface combination can support the requested combo.
-bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
-    const std::map<IfaceType, size_t>& expanded_combo,
-    const std::map<IfaceType, size_t>& req_combo) {
-    // Check if we have space for 1 more iface of |type| in this combo
-    for (const auto type :
-         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
-        if (req_combo.count(type) == 0) {
-            // Iface of "type" not in the req_combo.
-            continue;
-        }
-        size_t num_ifaces_needed = req_combo.at(type);
-        size_t num_ifaces_allowed = expanded_combo.at(type);
-        if (num_ifaces_needed > num_ifaces_allowed) {
-            return false;
-        }
-    }
-    return true;
-}
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-//    ChipIfaceCombination.
-// b) Check if the requested iface combo can be added to the current mode.
-// Note: This does not consider ifaces already active. It only checks if the
-// current mode can support the requested combo.
-bool WifiChip::canCurrentModeSupportIfaceCombo(
-    const std::map<IfaceType, size_t>& req_combo) {
-    if (!isValidModeId(current_mode_id_)) {
-        LOG(ERROR) << "Chip not configured in a mode yet";
-        return false;
-    }
-    const auto combinations = getCurrentModeIfaceCombinations();
-    for (const auto& combination : combinations) {
-        const auto expanded_combos = expandIfaceCombinations(combination);
-        for (const auto& expanded_combo : expanded_combos) {
-            if (canExpandedIfaceComboSupportIfaceCombo(expanded_combo,
-                                                       req_combo)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-//    ChipIfaceCombination.
-// b) Check if the requested iface type can be added to the current mode.
-bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
-    // Check if we can support at least 1 iface of type.
-    std::map<IfaceType, size_t> req_iface_combo;
-    req_iface_combo[requested_type] = 1;
-    return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-bool WifiChip::isValidModeId(ChipModeId mode_id) {
-    for (const auto& mode : modes_) {
-        if (mode.id == mode_id) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
-    // Check if we can support at least 1 STA & 1 AP concurrently.
-    std::map<IfaceType, size_t> req_iface_combo;
-    req_iface_combo[IfaceType::AP] = 1;
-    req_iface_combo[IfaceType::STA] = 1;
-    return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-bool WifiChip::isDualStaConcurrencyAllowedInCurrentMode() {
-    // Check if we can support at least 2 STA concurrently.
-    std::map<IfaceType, size_t> req_iface_combo;
-    req_iface_combo[IfaceType::STA] = 2;
-    return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-std::string WifiChip::getFirstActiveWlanIfaceName() {
-    if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
-    if (ap_ifaces_.size() > 0) {
-        // If the first active wlan iface is bridged iface.
-        // Return first instance name.
-        for (auto const& it : br_ifaces_ap_instances_) {
-            if (it.first == ap_ifaces_[0]->getName()) {
-                return it.second[0];
-            }
-        }
-        return ap_ifaces_[0]->getName();
-    }
-    // This could happen if the chip call is made before any STA/AP
-    // iface is created. Default to wlan0 for such cases.
-    LOG(WARNING) << "No active wlan interfaces in use! Using default";
-    return getWlanIfaceNameWithType(IfaceType::STA, 0);
-}
-
-// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
-// not already in use.
-// Note: This doesn't check the actual presence of these interfaces.
-std::string WifiChip::allocateApOrStaIfaceName(IfaceType type,
-                                               uint32_t start_idx) {
-    for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
-        const auto ifname = getWlanIfaceNameWithType(type, idx);
-        if (findUsingNameFromBridgedApInstances(ifname)) continue;
-        if (findUsingName(ap_ifaces_, ifname)) continue;
-        if (findUsingName(sta_ifaces_, ifname)) continue;
-        return ifname;
-    }
-    // This should never happen. We screwed up somewhere if it did.
-    CHECK(false) << "All wlan interfaces in use already!";
-    return {};
-}
-
-uint32_t WifiChip::startIdxOfApIface() {
-    if (isDualStaConcurrencyAllowedInCurrentMode()) {
-        // When the HAL support dual STAs, AP should start with idx 2.
-        return 2;
-    } else if (isStaApConcurrencyAllowedInCurrentMode()) {
-        //  When the HAL support STA + AP but it doesn't support dual STAs.
-        //  AP should start with idx 1.
-        return 1;
-    }
-    // No concurrency support.
-    return 0;
-}
-
-// AP iface names start with idx 1 for modes supporting
-// concurrent STA and not dual AP, else start with idx 0.
-std::string WifiChip::allocateApIfaceName() {
-    // Check if we have a dedicated iface for AP.
-    std::vector<std::string> ifnames = getPredefinedApIfaceNames(false);
-    if (!ifnames.empty()) {
-        return ifnames[0];
-    }
-    return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
-}
-
-std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
-    // Check if we have a dedicated iface for AP.
-    std::vector<std::string> instances = getPredefinedApIfaceNames(true);
-    if (instances.size() == 2) {
-        return instances;
-    } else {
-        int num_ifaces_need_to_allocate = 2 - instances.size();
-        for (int i = 0; i < num_ifaces_need_to_allocate; i++) {
-            std::string instance_name = allocateApOrStaIfaceName(
-                IfaceType::AP, startIdxOfApIface() + i);
-            if (!instance_name.empty()) {
-                instances.push_back(instance_name);
-            }
-        }
-    }
-    return instances;
-}
-
-// STA iface names start with idx 0.
-// Primary STA iface will always be 0.
-std::string WifiChip::allocateStaIfaceName() {
-    return allocateApOrStaIfaceName(IfaceType::STA, 0);
-}
-
-bool WifiChip::writeRingbufferFilesInternal() {
-    if (!removeOldFilesInternal()) {
-        LOG(ERROR) << "Error occurred while deleting old tombstone files";
-        return false;
-    }
-    // write ringbuffers to file
-    {
-        std::unique_lock<std::mutex> lk(lock_t);
-        for (auto& item : ringbuffer_map_) {
-            Ringbuffer& cur_buffer = item.second;
-            if (cur_buffer.getData().empty()) {
-                continue;
-            }
-            const std::string file_path_raw =
-                kTombstoneFolderPath + item.first + "XXXXXXXXXX";
-            const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
-            if (dump_fd == -1) {
-                PLOG(ERROR) << "create file failed";
-                return false;
-            }
-            unique_fd file_auto_closer(dump_fd);
-            for (const auto& cur_block : cur_buffer.getData()) {
-                if (write(dump_fd, cur_block.data(),
-                          sizeof(cur_block[0]) * cur_block.size()) == -1) {
-                    PLOG(ERROR) << "Error writing to file";
-                }
-            }
-            cur_buffer.clear();
-        }
-        // unique_lock unlocked here
-    }
-    return true;
-}
-
-std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
-    std::string ifname;
-
-    // let the legacy hal override the interface name
-    legacy_hal::wifi_error err =
-        legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
-    if (err == legacy_hal::WIFI_SUCCESS) return ifname;
-
-    return getWlanIfaceName(idx);
-}
-
-void WifiChip::invalidateAndClearBridgedApAll() {
-    for (auto const& it : br_ifaces_ap_instances_) {
-        for (auto const& iface : it.second) {
-            iface_util_->removeIfaceFromBridge(it.first, iface);
-            legacy_hal_.lock()->deleteVirtualInterface(iface);
-        }
-        iface_util_->deleteBridge(it.first);
-    }
-    br_ifaces_ap_instances_.clear();
-}
-
-void WifiChip::invalidateAndClearBridgedAp(const std::string& br_name) {
-    if (br_name.empty()) return;
-    // delete managed interfaces
-    for (auto const& it : br_ifaces_ap_instances_) {
-        if (it.first == br_name) {
-            for (auto const& iface : it.second) {
-                iface_util_->removeIfaceFromBridge(br_name, iface);
-                legacy_hal_.lock()->deleteVirtualInterface(iface);
-            }
-            iface_util_->deleteBridge(br_name);
-            br_ifaces_ap_instances_.erase(br_name);
-            break;
-        }
-    }
-    return;
-}
-
-bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
-    for (auto const& it : br_ifaces_ap_instances_) {
-        if (it.first == name) {
-            return true;
-        }
-        for (auto const& iface : it.second) {
-            if (iface == name) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
deleted file mode 100644
index bd40ead..0000000
--- a/wifi/1.5/default/wifi_chip.h
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_CHIP_H_
-#define WIFI_CHIP_H_
-
-#include <list>
-#include <map>
-#include <mutex>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.4/IWifiRttController.h>
-#include <android/hardware/wifi/1.5/IWifiChip.h>
-
-#include "hidl_callback_util.h"
-#include "ringbuffer.h"
-#include "wifi_ap_iface.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-#include "wifi_nan_iface.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_sta_iface.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a Wifi HAL chip instance.
- * Since there is only a single chip instance used today, there is no
- * identifying handle information stored here.
- */
-class WifiChip : public V1_5::IWifiChip {
-   public:
-    WifiChip(ChipId chip_id, bool is_primary,
-             const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-             const std::weak_ptr<mode_controller::WifiModeController>
-                 mode_controller,
-             const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
-             const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
-             const std::function<void(const std::string&)>&
-                 subsystemCallbackHandler);
-    // HIDL does not provide a built-in mechanism to let the server invalidate
-    // a HIDL interface object after creation. If any client process holds onto
-    // a reference to the object in their context, any method calls on that
-    // reference will continue to be directed to the server.
-    //
-    // However Wifi HAL needs to control the lifetime of these objects. So, add
-    // a public |invalidate| method to |WifiChip| and it's child objects. This
-    // will be used to mark an object invalid when either:
-    // a) Wifi HAL is stopped, or
-    // b) Wifi Chip is reconfigured.
-    //
-    // All HIDL method implementations should check if the object is still
-    // marked valid before processing them.
-    void invalidate();
-    bool isValid();
-    std::set<sp<V1_4::IWifiChipEventCallback>> getEventCallbacks();
-
-    // HIDL methods exposed.
-    Return<void> getId(getId_cb hidl_status_cb) override;
-    // Deprecated support for this callback
-    Return<void> registerEventCallback(
-        const sp<V1_0::IWifiChipEventCallback>& event_callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> getAvailableModes(
-        getAvailableModes_cb hidl_status_cb) override;
-    Return<void> configureChip(ChipModeId mode_id,
-                               configureChip_cb hidl_status_cb) override;
-    Return<void> getMode(getMode_cb hidl_status_cb) override;
-    Return<void> requestChipDebugInfo(
-        requestChipDebugInfo_cb hidl_status_cb) override;
-    Return<void> requestDriverDebugDump(
-        requestDriverDebugDump_cb hidl_status_cb) override;
-    Return<void> requestFirmwareDebugDump(
-        requestFirmwareDebugDump_cb hidl_status_cb) override;
-    Return<void> createApIface(createApIface_cb hidl_status_cb) override;
-    Return<void> createBridgedApIface(
-        createBridgedApIface_cb hidl_status_cb) override;
-    Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
-    Return<void> getApIface(const hidl_string& ifname,
-                            getApIface_cb hidl_status_cb) override;
-    Return<void> removeApIface(const hidl_string& ifname,
-                               removeApIface_cb hidl_status_cb) override;
-    Return<void> removeIfaceInstanceFromBridgedApIface(
-        const hidl_string& brIfaceName, const hidl_string& ifaceInstanceName,
-        removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) override;
-    Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
-    Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
-    Return<void> getNanIface(const hidl_string& ifname,
-                             getNanIface_cb hidl_status_cb) override;
-    Return<void> removeNanIface(const hidl_string& ifname,
-                                removeNanIface_cb hidl_status_cb) override;
-    Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
-    Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
-    Return<void> getP2pIface(const hidl_string& ifname,
-                             getP2pIface_cb hidl_status_cb) override;
-    Return<void> removeP2pIface(const hidl_string& ifname,
-                                removeP2pIface_cb hidl_status_cb) override;
-    Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
-    Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
-    Return<void> getStaIface(const hidl_string& ifname,
-                             getStaIface_cb hidl_status_cb) override;
-    Return<void> removeStaIface(const hidl_string& ifname,
-                                removeStaIface_cb hidl_status_cb) override;
-    Return<void> createRttController(
-        const sp<IWifiIface>& bound_iface,
-        createRttController_cb hidl_status_cb) override;
-    Return<void> getDebugRingBuffersStatus(
-        getDebugRingBuffersStatus_cb hidl_status_cb) override;
-    Return<void> startLoggingToDebugRingBuffer(
-        const hidl_string& ring_name,
-        WifiDebugRingBufferVerboseLevel verbose_level,
-        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
-        startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> forceDumpToDebugRingBuffer(
-        const hidl_string& ring_name,
-        forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> flushRingBufferToFile(
-        flushRingBufferToFile_cb hidl_status_cb) override;
-    Return<void> stopLoggingToDebugRingBuffer(
-        stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> getDebugHostWakeReasonStats(
-        getDebugHostWakeReasonStats_cb hidl_status_cb) override;
-    Return<void> enableDebugErrorAlerts(
-        bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
-    Return<void> selectTxPowerScenario(
-        V1_1::IWifiChip::TxPowerScenario scenario,
-        selectTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> resetTxPowerScenario(
-        resetTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> setLatencyMode(LatencyMode mode,
-                                setLatencyMode_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_2(
-        const sp<V1_2::IWifiChipEventCallback>& event_callback,
-        registerEventCallback_1_2_cb hidl_status_cb) override;
-    Return<void> selectTxPowerScenario_1_2(
-        TxPowerScenario scenario,
-        selectTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_3(
-        getCapabilities_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_5(
-        getCapabilities_1_5_cb hidl_status_cb) override;
-    Return<void> debug(const hidl_handle& handle,
-                       const hidl_vec<hidl_string>& options) override;
-    Return<void> createRttController_1_4(
-        const sp<IWifiIface>& bound_iface,
-        createRttController_1_4_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_4(
-        const sp<V1_4::IWifiChipEventCallback>& event_callback,
-        registerEventCallback_1_4_cb hidl_status_cb) override;
-    Return<void> setMultiStaPrimaryConnection(
-        const hidl_string& ifname,
-        setMultiStaPrimaryConnection_cb hidl_status_cb) override;
-    Return<void> setMultiStaUseCase(
-        MultiStaUseCase use_case,
-        setMultiStaUseCase_cb hidl_status_cb) override;
-    Return<void> setCoexUnsafeChannels(
-        const hidl_vec<CoexUnsafeChannel>& unsafe_channels,
-        hidl_bitfield<IfaceType> restrictions,
-        setCoexUnsafeChannels_cb hidl_status_cb) override;
-    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
-                                setCountryCode_cb _hidl_cb) override;
-    Return<void> getUsableChannels(
-        WifiBand band, hidl_bitfield<WifiIfaceMode> ifaceModeMask,
-        hidl_bitfield<UsableChannelFilter> filterMask,
-        getUsableChannels_cb _hidl_cb) override;
-    Return<void> triggerSubsystemRestart(
-        triggerSubsystemRestart_cb hidl_status_cb) override;
-
-   private:
-    void invalidateAndRemoveAllIfaces();
-    // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
-    // invalidated & removed.
-    void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
-
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, ChipId> getIdInternal();
-    // Deprecated support for this callback
-    WifiStatus registerEventCallbackInternal(
-        const sp<V1_0::IWifiChipEventCallback>& event_callback);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-    std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
-    WifiStatus configureChipInternal(
-        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
-    std::pair<WifiStatus, uint32_t> getModeInternal();
-    std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
-    requestChipDebugInfoInternal();
-    std::pair<WifiStatus, std::vector<uint8_t>>
-    requestDriverDebugDumpInternal();
-    std::pair<WifiStatus, std::vector<uint8_t>>
-    requestFirmwareDebugDumpInternal();
-    sp<WifiApIface> newWifiApIface(std::string& ifname);
-    WifiStatus createVirtualApInterface(const std::string& apVirtIf);
-    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createApIfaceInternal();
-    std::pair<WifiStatus, sp<V1_5::IWifiApIface>>
-    createBridgedApIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
-    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> getApIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeApIfaceInternal(const std::string& ifname);
-    WifiStatus removeIfaceInstanceFromBridgedApIfaceInternal(
-        const std::string& brIfaceName, const std::string& ifInstanceName);
-    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
-    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeNanIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeP2pIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> createStaIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
-    std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> getStaIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeStaIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
-    createRttControllerInternal(const sp<IWifiIface>& bound_iface);
-    std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-    getDebugRingBuffersStatusInternal();
-    WifiStatus startLoggingToDebugRingBufferInternal(
-        const hidl_string& ring_name,
-        WifiDebugRingBufferVerboseLevel verbose_level,
-        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
-    WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
-    WifiStatus flushRingBufferToFileInternal();
-    WifiStatus stopLoggingToDebugRingBufferInternal();
-    std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
-    getDebugHostWakeReasonStatsInternal();
-    WifiStatus enableDebugErrorAlertsInternal(bool enable);
-    WifiStatus selectTxPowerScenarioInternal(
-        V1_1::IWifiChip::TxPowerScenario scenario);
-    WifiStatus resetTxPowerScenarioInternal();
-    WifiStatus setLatencyModeInternal(LatencyMode mode);
-    WifiStatus registerEventCallbackInternal_1_2(
-        const sp<V1_2::IWifiChipEventCallback>& event_callback);
-    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_5();
-    std::pair<WifiStatus, sp<V1_4::IWifiRttController>>
-    createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface);
-    WifiStatus registerEventCallbackInternal_1_4(
-        const sp<V1_4::IWifiChipEventCallback>& event_callback);
-    WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
-    WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case);
-    WifiStatus setCoexUnsafeChannelsInternal(
-        std::vector<CoexUnsafeChannel> unsafe_channels, uint32_t restrictions);
-    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
-    std::pair<WifiStatus, std::vector<WifiUsableChannel>>
-    getUsableChannelsInternal(WifiBand band, uint32_t ifaceModeMask,
-                              uint32_t filterMask);
-    WifiStatus handleChipConfiguration(
-        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
-    WifiStatus registerDebugRingBufferCallback();
-    WifiStatus registerRadioModeChangeCallback();
-
-    std::vector<V1_4::IWifiChip::ChipIfaceCombination>
-    getCurrentModeIfaceCombinations();
-    std::map<IfaceType, size_t> getCurrentIfaceCombination();
-    std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
-        const V1_4::IWifiChip::ChipIfaceCombination& combination);
-    bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
-        const std::map<IfaceType, size_t>& expanded_combo,
-        IfaceType requested_type);
-    bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
-        IfaceType requested_type);
-    bool canExpandedIfaceComboSupportIfaceCombo(
-        const std::map<IfaceType, size_t>& expanded_combo,
-        const std::map<IfaceType, size_t>& req_combo);
-    bool canCurrentModeSupportIfaceCombo(
-        const std::map<IfaceType, size_t>& req_combo);
-    bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
-    bool isValidModeId(ChipModeId mode_id);
-    bool isStaApConcurrencyAllowedInCurrentMode();
-    bool isDualStaConcurrencyAllowedInCurrentMode();
-    uint32_t startIdxOfApIface();
-    std::string getFirstActiveWlanIfaceName();
-    std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
-    std::string allocateApIfaceName();
-    std::vector<std::string> allocateBridgedApInstanceNames();
-    std::string allocateStaIfaceName();
-    bool writeRingbufferFilesInternal();
-    std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
-    void invalidateAndClearBridgedApAll();
-    void invalidateAndClearBridgedAp(const std::string& br_name);
-    bool findUsingNameFromBridgedApInstances(const std::string& name);
-    WifiStatus triggerSubsystemRestartInternal();
-
-    ChipId chip_id_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
-    std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    std::vector<sp<WifiApIface>> ap_ifaces_;
-    std::vector<sp<WifiNanIface>> nan_ifaces_;
-    std::vector<sp<WifiP2pIface>> p2p_ifaces_;
-    std::vector<sp<WifiStaIface>> sta_ifaces_;
-    std::vector<sp<WifiRttController>> rtt_controllers_;
-    std::map<std::string, Ringbuffer> ringbuffer_map_;
-    bool is_valid_;
-    // Members pertaining to chip configuration.
-    uint32_t current_mode_id_;
-    std::mutex lock_t;
-    std::vector<V1_4::IWifiChip::ChipMode> modes_;
-    // The legacy ring buffer callback API has only a global callback
-    // registration mechanism. Use this to check if we have already
-    // registered a callback.
-    bool debug_ring_buffer_cb_registered_;
-    hidl_callback_util::HidlCallbackHandler<V1_4::IWifiChipEventCallback>
-        event_cb_handler_;
-
-    const std::function<void(const std::string&)> subsystemCallbackHandler_;
-    std::map<std::string, std::vector<std::string>> br_ifaces_ap_instances_;
-    DISALLOW_COPY_AND_ASSIGN(WifiChip);
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_CHIP_H_
diff --git a/wifi/1.5/default/wifi_feature_flags.cpp b/wifi/1.5/default/wifi_feature_flags.cpp
deleted file mode 100644
index 124ba32..0000000
--- a/wifi/1.5/default/wifi_feature_flags.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2016 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 <string>
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-
-#include "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace feature_flags {
-
-using V1_0::ChipModeId;
-using V1_0::IfaceType;
-using V1_0::IWifiChip;
-
-/* The chip may either have a single mode supporting any number of combinations,
- * or a fixed dual-mode (so it involves firmware loading to switch between
- * modes) setting. If there is a need to support more modes, it needs to be
- * implemented manually in WiFi HAL (see changeFirmwareMode in
- * WifiChip::handleChipConfiguration).
- *
- * Supported combinations are defined in device's makefile, for example:
- *    WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
- *    WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
- * What means:
- *    Interface combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
- *                             operations.
- *    Interface combination 2: 1 STA and 2 AP concurrent iface operations.
- *
- * For backward compatibility, the following makefile flags can be used to
- * generate combinations list:
- *  - WIFI_HIDL_FEATURE_DUAL_INTERFACE
- *  - WIFI_HIDL_FEATURE_DISABLE_AP
- *  - WIFI_HIDL_FEATURE_AWARE
- * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
- * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
- * two interface combinations:
- *    Interface Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
- *                             concurrent iface operations.
- *    Interface Combination 2: Will support 1 STA and 1 AP concurrent
- *                             iface operations.
- *
- * The only dual-mode configuration supported is for alternating STA and AP
- * mode, that may involve firmware reloading. In such case, there are 2 separate
- * modes of operation with 1 interface combination each:
- *    Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
- *                       concurrent iface operations.
- *    Mode 2 (AP mode): Will support 1 AP iface operation.
- *
- * If Aware is enabled, the iface combination will be modified to support either
- * P2P or NAN in place of just P2P.
- */
-// clang-format off
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
-#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
-// former V2 (fixed dual interface) setup expressed as V3
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
-#  ifdef WIFI_HIDL_FEATURE_DISABLE_AP
-#    ifdef WIFI_HIDL_FEATURE_AWARE
-//     1 STA + 1 of (P2P or NAN)
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
-#    else
-//     1 STA + 1 P2P
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
-#    endif
-#  else
-#    ifdef WIFI_HIDL_FEATURE_AWARE
-//     (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
-                                              {{{STA}, 1}, {{P2P, NAN}, 1}}
-#    else
-//     (1 STA + 1 AP) or (1 STA + 1 P2P)
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
-                                              {{{STA}, 1}, {{P2P}, 1}}
-#    endif
-#  endif
-#else
-// V1 (fixed single interface, dual-mode chip)
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV1Sta;
-#  ifdef WIFI_HIDL_FEATURE_AWARE
-//   1 STA + 1 of (P2P or NAN)
-#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
-#  else
-//   1 STA + 1 P2P
-#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
-#  endif
-
-#  ifndef WIFI_HIDL_FEATURE_DISABLE_AP
-#    define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
-#  endif
-#endif
-// clang-format on
-
-/**
- * Helper class to convert a collection of combination limits to a combination.
- *
- * The main point here is to simplify the syntax required by
- * WIFI_HAL_INTERFACE_COMBINATIONS.
- */
-struct ChipIfaceCombination
-    : public hidl_vec<IWifiChip::ChipIfaceCombinationLimit> {
-    ChipIfaceCombination(
-        const std::initializer_list<IWifiChip::ChipIfaceCombinationLimit> list)
-        : hidl_vec(list) {}
-
-    operator IWifiChip::ChipIfaceCombination() const { return {*this}; }
-
-    static hidl_vec<IWifiChip::ChipIfaceCombination> make_vec(
-        const std::initializer_list<ChipIfaceCombination> list) {
-        return hidl_vec<IWifiChip::ChipIfaceCombination>(  //
-            std::begin(list), std::end(list));
-    }
-};
-
-#define STA IfaceType::STA
-#define AP IfaceType::AP
-#define P2P IfaceType::P2P
-#define NAN IfaceType::NAN
-static const std::vector<IWifiChip::ChipMode> kChipModesPrimary{
-    {kMainModeId,
-     ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
-    {chip_mode_ids::kV1Ap,
-     ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
-#endif
-};
-
-static const std::vector<IWifiChip::ChipMode> kChipModesSecondary{
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
-    {chip_mode_ids::kV3, ChipIfaceCombination::make_vec(
-                             {WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
-#endif
-};
-
-constexpr char kDebugPresetInterfaceCombinationIdxProperty[] =
-    "persist.vendor.debug.wifi.hal.preset_interface_combination_idx";
-// List of pre-defined interface combinations that can be enabled at runtime via
-// setting the property: "kDebugPresetInterfaceCombinationIdxProperty" to the
-// corresponding index value.
-static const std::vector<
-    std::pair<std::string, std::vector<IWifiChip::ChipMode>>>
-    kDebugChipModes{
-        // Legacy combination - No STA/AP concurrencies.
-        // 0 - (1 AP) or (1 STA + 1 of (P2P or NAN))
-        {"No STA/AP Concurrency",
-         {{kMainModeId,
-           ChipIfaceCombination::make_vec(
-               {{{{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
-
-        // STA + AP concurrency
-        // 1 - (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
-        {"STA + AP Concurrency",
-         {{kMainModeId,
-           ChipIfaceCombination::make_vec(
-               {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
-
-        // STA + STA concurrency
-        // 2 - (1 STA + 1 AP) or (2 STA + 1 of (P2P or NAN))
-        {"Dual STA Concurrency",
-         {{kMainModeId,
-           ChipIfaceCombination::make_vec(
-               {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
-
-        // AP + AP + STA concurrency
-        // 3 - (1 STA + 2 AP) or (1 STA + 1 of (P2P or NAN))
-        {"Dual AP Concurrency",
-         {{kMainModeId,
-           ChipIfaceCombination::make_vec(
-               {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
-
-        // STA + STA concurrency and AP + AP + STA concurrency
-        // 4 - (1 STA + 2 AP) or (2 STA + 1 of (P2P or NAN))
-        {"Dual STA & Dual AP Concurrency",
-         {{kMainModeId,
-           ChipIfaceCombination::make_vec(
-               {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}}};
-
-#undef STA
-#undef AP
-#undef P2P
-#undef NAN
-
-#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-#pragma message                                                               \
-    "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
-    "'config_wifi_ap_randomization_supported' in "                            \
-    "frameworks/base/core/res/res/values/config.xml in the device overlay "   \
-    "instead"
-#endif  // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-
-WifiFeatureFlags::WifiFeatureFlags() {}
-
-std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModesForPrimary() {
-    std::array<char, PROPERTY_VALUE_MAX> buffer;
-    auto res = property_get(kDebugPresetInterfaceCombinationIdxProperty,
-                            buffer.data(), nullptr);
-    // Debug propety not set, use the device preset interface combination.
-    if (res <= 0) return kChipModesPrimary;
-
-    // Debug propety set, use one of the debug preset interface combination.
-    unsigned long idx = std::stoul(buffer.data());
-    if (idx >= kDebugChipModes.size()) {
-        LOG(ERROR) << "Invalid index set in property: "
-                   << kDebugPresetInterfaceCombinationIdxProperty;
-        return kChipModesPrimary;
-    }
-    std::string name;
-    std::vector<IWifiChip::ChipMode> chip_modes;
-    std::tie(name, chip_modes) = kDebugChipModes[idx];
-    LOG(INFO) << "Using debug chip mode: <" << name << "> set via property: "
-              << kDebugPresetInterfaceCombinationIdxProperty;
-    return chip_modes;
-}
-
-std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(
-    bool is_primary) {
-    return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary;
-}
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_feature_flags.h b/wifi/1.5/default/wifi_feature_flags.h
deleted file mode 100644
index 7d561fc..0000000
--- a/wifi/1.5/default/wifi_feature_flags.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_FEATURE_FLAGS_H_
-#define WIFI_FEATURE_FLAGS_H_
-
-#include <android/hardware/wifi/1.2/IWifiChip.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace feature_flags {
-
-namespace chip_mode_ids {
-// These mode ID's should be unique (even across combo versions). Refer to
-// handleChipConfiguration() for it's usage.
-constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
-// Mode ID's for V1
-constexpr V1_0::ChipModeId kV1Sta = 0;
-constexpr V1_0::ChipModeId kV1Ap = 1;
-// Mode ID for V3
-constexpr V1_0::ChipModeId kV3 = 3;
-}  // namespace chip_mode_ids
-
-class WifiFeatureFlags {
-   public:
-    WifiFeatureFlags();
-    virtual ~WifiFeatureFlags() = default;
-
-    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes(
-        bool is_primary);
-
-   private:
-    std::vector<V1_0::IWifiChip::ChipMode> getChipModesForPrimary();
-};
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.5/default/wifi_iface_util.cpp b/wifi/1.5/default/wifi_iface_util.cpp
deleted file mode 100644
index 0977026..0000000
--- a/wifi/1.5/default/wifi_iface_util.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <net/if.h>
-#include <cstddef>
-#include <iostream>
-#include <limits>
-#include <random>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#undef NAN
-#include "wifi_iface_util.h"
-
-namespace {
-// Constants to set the local bit & clear the multicast bit.
-constexpr uint8_t kMacAddressMulticastMask = 0x01;
-constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace iface_util {
-
-WifiIfaceUtil::WifiIfaceUtil(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : iface_tool_(iface_tool),
-      legacy_hal_(legacy_hal),
-      random_mac_address_(nullptr),
-      event_handlers_map_() {}
-
-std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(
-    const std::string& iface_name) {
-    return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
-}
-
-bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
-                                  const std::array<uint8_t, 6>& mac) {
-#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
-    legacy_hal::wifi_error legacy_status;
-    uint64_t legacy_feature_set;
-    std::tie(legacy_status, legacy_feature_set) =
-        legacy_hal_.lock()->getSupportedFeatureSet(iface_name);
-
-    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
-        !iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
-        LOG(ERROR) << "SetUpState(false) failed.";
-        return false;
-    }
-#endif
-    bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac);
-#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
-    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
-        !iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
-        LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready.";
-        // Wait for driver ready and try to set iface UP again
-        if (legacy_hal_.lock()->waitForDriverReady() !=
-            legacy_hal::WIFI_SUCCESS) {
-            LOG(ERROR) << "SetUpState(true) wait for driver ready failed.";
-            return false;
-        }
-        if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
-            LOG(ERROR) << "SetUpState(true) failed after retry.";
-            return false;
-        }
-    }
-#endif
-    IfaceEventHandlers event_handlers = {};
-    const auto it = event_handlers_map_.find(iface_name);
-    if (it != event_handlers_map_.end()) {
-        event_handlers = it->second;
-    }
-    if (event_handlers.on_state_toggle_off_on != nullptr) {
-        event_handlers.on_state_toggle_off_on(iface_name);
-    }
-    if (!success) {
-        LOG(ERROR) << "SetMacAddress failed on " << iface_name;
-    } else {
-        LOG(DEBUG) << "SetMacAddress succeeded on " << iface_name;
-    }
-    return success;
-}
-
-std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
-    if (random_mac_address_) {
-        return *random_mac_address_.get();
-    }
-    random_mac_address_ =
-        std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
-    return *random_mac_address_.get();
-}
-
-void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
-                                               IfaceEventHandlers handlers) {
-    event_handlers_map_[iface_name] = handlers;
-}
-
-void WifiIfaceUtil::unregisterIfaceEventHandlers(
-    const std::string& iface_name) {
-    event_handlers_map_.erase(iface_name);
-}
-
-std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
-    std::array<uint8_t, 6> address = {};
-    std::random_device rd;
-    std::default_random_engine engine(rd());
-    std::uniform_int_distribution<uint8_t> dist(
-        std::numeric_limits<uint8_t>::min(),
-        std::numeric_limits<uint8_t>::max());
-    for (size_t i = 0; i < address.size(); i++) {
-        address[i] = dist(engine);
-    }
-    // Set the local bit and clear the multicast bit.
-    address[0] |= kMacAddressLocallyAssignedMask;
-    address[0] &= ~kMacAddressMulticastMask;
-    return address;
-}
-
-bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) {
-    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) {
-        LOG(ERROR) << "SetUpState to " << request_up << " failed";
-        return false;
-    }
-    return true;
-}
-
-unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) {
-    return if_nametoindex(iface_name.c_str());
-}
-
-bool WifiIfaceUtil::createBridge(const std::string& br_name) {
-    if (!iface_tool_.lock()->createBridge(br_name)) {
-        return false;
-    }
-
-    if (!iface_tool_.lock()->SetUpState(br_name.c_str(), true)) {
-        LOG(ERROR) << "bridge SetUpState(true) failed.";
-    }
-    return true;
-}
-
-bool WifiIfaceUtil::deleteBridge(const std::string& br_name) {
-    if (!iface_tool_.lock()->SetUpState(br_name.c_str(), false)) {
-        LOG(INFO) << "SetUpState(false) failed for bridge=" << br_name.c_str();
-    }
-
-    return iface_tool_.lock()->deleteBridge(br_name);
-}
-
-bool WifiIfaceUtil::addIfaceToBridge(const std::string& br_name,
-                                     const std::string& if_name) {
-    return iface_tool_.lock()->addIfaceToBridge(br_name, if_name);
-}
-
-bool WifiIfaceUtil::removeIfaceFromBridge(const std::string& br_name,
-                                          const std::string& if_name) {
-    return iface_tool_.lock()->removeIfaceFromBridge(br_name, if_name);
-}
-
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_iface_util.h b/wifi/1.5/default/wifi_iface_util.h
deleted file mode 100644
index 544f575..0000000
--- a/wifi/1.5/default/wifi_iface_util.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_IFACE_UTIL_H_
-#define WIFI_IFACE_UTIL_H_
-
-#include <wifi_system/interface_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace iface_util {
-
-// Iface event handlers.
-struct IfaceEventHandlers {
-    // Callback to be invoked when the iface is set down & up for MAC address
-    // change.
-    std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
-};
-
-/**
- * Util class for common iface operations.
- */
-class WifiIfaceUtil {
-   public:
-    WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-    virtual ~WifiIfaceUtil() = default;
-
-    virtual std::array<uint8_t, 6> getFactoryMacAddress(
-        const std::string& iface_name);
-    virtual bool setMacAddress(const std::string& iface_name,
-                               const std::array<uint8_t, 6>& mac);
-    // Get or create a random MAC address. The MAC address returned from
-    // this method will remain the same throughout the lifetime of the HAL
-    // daemon. (So, changes on every reboot)
-    virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
-
-    // Register for any iface event callbacks for the provided interface.
-    virtual void registerIfaceEventHandlers(const std::string& iface_name,
-                                            IfaceEventHandlers handlers);
-    virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
-    virtual bool setUpState(const std::string& iface_name, bool request_up);
-    virtual unsigned ifNameToIndex(const std::string& iface_name);
-
-    virtual bool createBridge(const std::string& br_name);
-
-    virtual bool deleteBridge(const std::string& br_name);
-
-    virtual bool addIfaceToBridge(const std::string& br_name,
-                                  const std::string& if_name);
-
-    virtual bool removeIfaceFromBridge(const std::string& br_name,
-                                       const std::string& if_name);
-    // Get a random MAC address.
-    virtual std::array<uint8_t, 6> createRandomMacAddress();
-
-   private:
-    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
-    std::map<std::string, IfaceEventHandlers> event_handlers_map_;
-};
-
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
deleted file mode 100644
index 5074252..0000000
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,1725 +0,0 @@
-/*
- * Copyright (C) 2016 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 <array>
-#include <chrono>
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-#include <net/if.h>
-
-#include "hidl_sync_util.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_legacy_hal_stubs.h"
-
-namespace {
-// Constants ported over from the legacy HAL calling code
-// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
-// away when this shim layer is replaced by the real vendor
-// implementation.
-static constexpr uint32_t kMaxVersionStringLength = 256;
-static constexpr uint32_t kMaxCachedGscanResults = 64;
-static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
-static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
-static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
-static constexpr uint32_t kMaxRingBuffers = 10;
-static constexpr uint32_t kMaxWifiUsableChannels = 256;
-// need a long timeout (1000ms) for chips that unload their driver.
-static constexpr uint32_t kMaxStopCompleteWaitMs = 1000;
-static constexpr char kDriverPropName[] = "wlan.driver.status";
-
-// Helper function to create a non-const char* for legacy Hal API's.
-std::vector<char> makeCharVec(const std::string& str) {
-    std::vector<char> vec(str.size() + 1);
-    vec.assign(str.begin(), str.end());
-    vec.push_back('\0');
-    return vec;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace legacy_hal {
-
-// Legacy HAL functions accept "C" style function pointers, so use global
-// functions to pass to the legacy HAL function and store the corresponding
-// std::function methods to be invoked.
-//
-// Callback to be invoked once |stop| is complete
-std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
-void onAsyncStopComplete(wifi_handle handle) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_stop_complete_internal_callback) {
-        on_stop_complete_internal_callback(handle);
-        // Invalidate this callback since we don't want this firing again.
-        on_stop_complete_internal_callback = nullptr;
-    }
-}
-
-// Callback to be invoked for driver dump.
-std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
-void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
-    if (on_driver_memory_dump_internal_callback) {
-        on_driver_memory_dump_internal_callback(buffer, buffer_size);
-    }
-}
-
-// Callback to be invoked for firmware dump.
-std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
-void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
-    if (on_firmware_memory_dump_internal_callback) {
-        on_firmware_memory_dump_internal_callback(buffer, buffer_size);
-    }
-}
-
-// Callback to be invoked for Gscan events.
-std::function<void(wifi_request_id, wifi_scan_event)>
-    on_gscan_event_internal_callback;
-void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_gscan_event_internal_callback) {
-        on_gscan_event_internal_callback(id, event);
-    }
-}
-
-// Callback to be invoked for Gscan full results.
-std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
-    on_gscan_full_result_internal_callback;
-void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
-                            uint32_t buckets_scanned) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_gscan_full_result_internal_callback) {
-        on_gscan_full_result_internal_callback(id, result, buckets_scanned);
-    }
-}
-
-// Callback to be invoked for link layer stats results.
-std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
-    on_link_layer_stats_result_internal_callback;
-void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat,
-                                int num_radios, wifi_radio_stat* radio_stat) {
-    if (on_link_layer_stats_result_internal_callback) {
-        on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios,
-                                                     radio_stat);
-    }
-}
-
-// Callback to be invoked for rssi threshold breach.
-std::function<void((wifi_request_id, uint8_t*, int8_t))>
-    on_rssi_threshold_breached_internal_callback;
-void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid,
-                                  int8_t rssi) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_rssi_threshold_breached_internal_callback) {
-        on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
-    }
-}
-
-// Callback to be invoked for ring buffer data indication.
-std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
-    on_ring_buffer_data_internal_callback;
-void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
-                           wifi_ring_buffer_status* status) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_ring_buffer_data_internal_callback) {
-        on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size,
-                                              status);
-    }
-}
-
-// Callback to be invoked for error alert indication.
-std::function<void(wifi_request_id, char*, int, int)>
-    on_error_alert_internal_callback;
-void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size,
-                       int err_code) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_error_alert_internal_callback) {
-        on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
-    }
-}
-
-// Callback to be invoked for radio mode change indication.
-std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
-    on_radio_mode_change_internal_callback;
-void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs,
-                            wifi_mac_info* mac_infos) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_radio_mode_change_internal_callback) {
-        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
-    }
-}
-
-// Callback to be invoked to report subsystem restart
-std::function<void(const char*)> on_subsystem_restart_internal_callback;
-void onAsyncSubsystemRestart(const char* error) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_subsystem_restart_internal_callback) {
-        on_subsystem_restart_internal_callback(error);
-    }
-}
-
-// Callback to be invoked for rtt results results.
-std::function<void(wifi_request_id, unsigned num_results,
-                   wifi_rtt_result* rtt_results[])>
-    on_rtt_results_internal_callback;
-void onAsyncRttResults(wifi_request_id id, unsigned num_results,
-                       wifi_rtt_result* rtt_results[]) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_rtt_results_internal_callback) {
-        on_rtt_results_internal_callback(id, num_results, rtt_results);
-        on_rtt_results_internal_callback = nullptr;
-    }
-}
-
-// Callbacks for the various NAN operations.
-// NOTE: These have very little conversions to perform before invoking the user
-// callbacks.
-// So, handle all of them here directly to avoid adding an unnecessary layer.
-std::function<void(transaction_id, const NanResponseMsg&)>
-    on_nan_notify_response_user_callback;
-void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_notify_response_user_callback && msg) {
-        on_nan_notify_response_user_callback(id, *msg);
-    }
-}
-
-std::function<void(const NanPublishRepliedInd&)>
-    on_nan_event_publish_replied_user_callback;
-void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
-    LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
-}
-
-std::function<void(const NanPublishTerminatedInd&)>
-    on_nan_event_publish_terminated_user_callback;
-void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_publish_terminated_user_callback && event) {
-        on_nan_event_publish_terminated_user_callback(*event);
-    }
-}
-
-std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
-void onAysncNanEventMatch(NanMatchInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_match_user_callback && event) {
-        on_nan_event_match_user_callback(*event);
-    }
-}
-
-std::function<void(const NanMatchExpiredInd&)>
-    on_nan_event_match_expired_user_callback;
-void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_match_expired_user_callback && event) {
-        on_nan_event_match_expired_user_callback(*event);
-    }
-}
-
-std::function<void(const NanSubscribeTerminatedInd&)>
-    on_nan_event_subscribe_terminated_user_callback;
-void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_subscribe_terminated_user_callback && event) {
-        on_nan_event_subscribe_terminated_user_callback(*event);
-    }
-}
-
-std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
-void onAysncNanEventFollowup(NanFollowupInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_followup_user_callback && event) {
-        on_nan_event_followup_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDiscEngEventInd&)>
-    on_nan_event_disc_eng_event_user_callback;
-void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_disc_eng_event_user_callback && event) {
-        on_nan_event_disc_eng_event_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
-void onAysncNanEventDisabled(NanDisabledInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_disabled_user_callback && event) {
-        on_nan_event_disabled_user_callback(*event);
-    }
-}
-
-std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
-void onAysncNanEventTca(NanTCAInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_tca_user_callback && event) {
-        on_nan_event_tca_user_callback(*event);
-    }
-}
-
-std::function<void(const NanBeaconSdfPayloadInd&)>
-    on_nan_event_beacon_sdf_payload_user_callback;
-void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_beacon_sdf_payload_user_callback && event) {
-        on_nan_event_beacon_sdf_payload_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDataPathRequestInd&)>
-    on_nan_event_data_path_request_user_callback;
-void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_data_path_request_user_callback && event) {
-        on_nan_event_data_path_request_user_callback(*event);
-    }
-}
-std::function<void(const NanDataPathConfirmInd&)>
-    on_nan_event_data_path_confirm_user_callback;
-void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_data_path_confirm_user_callback && event) {
-        on_nan_event_data_path_confirm_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDataPathEndInd&)>
-    on_nan_event_data_path_end_user_callback;
-void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_data_path_end_user_callback && event) {
-        on_nan_event_data_path_end_user_callback(*event);
-    }
-}
-
-std::function<void(const NanTransmitFollowupInd&)>
-    on_nan_event_transmit_follow_up_user_callback;
-void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_transmit_follow_up_user_callback && event) {
-        on_nan_event_transmit_follow_up_user_callback(*event);
-    }
-}
-
-std::function<void(const NanRangeRequestInd&)>
-    on_nan_event_range_request_user_callback;
-void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_range_request_user_callback && event) {
-        on_nan_event_range_request_user_callback(*event);
-    }
-}
-
-std::function<void(const NanRangeReportInd&)>
-    on_nan_event_range_report_user_callback;
-void onAysncNanEventRangeReport(NanRangeReportInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_range_report_user_callback && event) {
-        on_nan_event_range_report_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDataPathScheduleUpdateInd&)>
-    on_nan_event_schedule_update_user_callback;
-void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_schedule_update_user_callback && event) {
-        on_nan_event_schedule_update_user_callback(*event);
-    }
-}
-
-// Callbacks for the various TWT operations.
-std::function<void(const TwtSetupResponse&)>
-    on_twt_event_setup_response_callback;
-void onAsyncTwtEventSetupResponse(TwtSetupResponse* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_twt_event_setup_response_callback && event) {
-        on_twt_event_setup_response_callback(*event);
-    }
-}
-
-std::function<void(const TwtTeardownCompletion&)>
-    on_twt_event_teardown_completion_callback;
-void onAsyncTwtEventTeardownCompletion(TwtTeardownCompletion* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_twt_event_teardown_completion_callback && event) {
-        on_twt_event_teardown_completion_callback(*event);
-    }
-}
-
-std::function<void(const TwtInfoFrameReceived&)>
-    on_twt_event_info_frame_received_callback;
-void onAsyncTwtEventInfoFrameReceived(TwtInfoFrameReceived* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_twt_event_info_frame_received_callback && event) {
-        on_twt_event_info_frame_received_callback(*event);
-    }
-}
-
-std::function<void(const TwtDeviceNotify&)> on_twt_event_device_notify_callback;
-void onAsyncTwtEventDeviceNotify(TwtDeviceNotify* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_twt_event_device_notify_callback && event) {
-        on_twt_event_device_notify_callback(*event);
-    }
-}
-
-// End of the free-standing "C" style callbacks.
-
-WifiLegacyHal::WifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-    const wifi_hal_fn& fn, bool is_primary)
-    : global_func_table_(fn),
-      global_handle_(nullptr),
-      awaiting_event_loop_termination_(false),
-      is_started_(false),
-      iface_tool_(iface_tool),
-      is_primary_(is_primary) {}
-
-wifi_error WifiLegacyHal::initialize() {
-    LOG(DEBUG) << "Initialize legacy HAL";
-    // this now does nothing, since HAL function table is provided
-    // to the constructor
-    return WIFI_SUCCESS;
-}
-
-wifi_error WifiLegacyHal::start() {
-    // Ensure that we're starting in a good state.
-    CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
-          iface_name_to_handle_.empty() && !awaiting_event_loop_termination_);
-    if (is_started_) {
-        LOG(DEBUG) << "Legacy HAL already started";
-        return WIFI_SUCCESS;
-    }
-    LOG(DEBUG) << "Waiting for the driver ready";
-    wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
-    if (status == WIFI_ERROR_TIMED_OUT || status == WIFI_ERROR_UNKNOWN) {
-        LOG(ERROR) << "Failed or timed out awaiting driver ready";
-        return status;
-    }
-
-    if (is_primary_) {
-        property_set(kDriverPropName, "ok");
-
-        if (!iface_tool_.lock()->SetWifiUpState(true)) {
-            LOG(ERROR) << "Failed to set WiFi interface up";
-            return WIFI_ERROR_UNKNOWN;
-        }
-    }
-
-    LOG(DEBUG) << "Starting legacy HAL";
-    status = global_func_table_.wifi_initialize(&global_handle_);
-    if (status != WIFI_SUCCESS || !global_handle_) {
-        LOG(ERROR) << "Failed to retrieve global handle";
-        return status;
-    }
-    std::thread(&WifiLegacyHal::runEventLoop, this).detach();
-    status = retrieveIfaceHandles();
-    if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
-        LOG(ERROR) << "Failed to retrieve wlan interface handle";
-        return status;
-    }
-    LOG(DEBUG) << "Legacy HAL start complete";
-    is_started_ = true;
-    return WIFI_SUCCESS;
-}
-
-wifi_error WifiLegacyHal::stop(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
-    const std::function<void()>& on_stop_complete_user_callback) {
-    if (!is_started_) {
-        LOG(DEBUG) << "Legacy HAL already stopped";
-        on_stop_complete_user_callback();
-        return WIFI_SUCCESS;
-    }
-    LOG(DEBUG) << "Stopping legacy HAL";
-    on_stop_complete_internal_callback = [on_stop_complete_user_callback,
-                                          this](wifi_handle handle) {
-        CHECK_EQ(global_handle_, handle) << "Handle mismatch";
-        LOG(INFO) << "Legacy HAL stop complete callback received";
-        // Invalidate all the internal pointers now that the HAL is
-        // stopped.
-        invalidate();
-        if (is_primary_) iface_tool_.lock()->SetWifiUpState(false);
-        on_stop_complete_user_callback();
-        is_started_ = false;
-    };
-    awaiting_event_loop_termination_ = true;
-    global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
-    const auto status = stop_wait_cv_.wait_for(
-        *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
-        [this] { return !awaiting_event_loop_termination_; });
-    if (!status) {
-        LOG(ERROR) << "Legacy HAL stop failed or timed out";
-        return WIFI_ERROR_UNKNOWN;
-    }
-    LOG(DEBUG) << "Legacy HAL stop complete";
-    return WIFI_SUCCESS;
-}
-
-bool WifiLegacyHal::isStarted() { return is_started_; }
-
-wifi_error WifiLegacyHal::waitForDriverReady() {
-    return global_func_table_.wifi_wait_for_driver_ready();
-}
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(
-    const std::string& iface_name) {
-    std::array<char, kMaxVersionStringLength> buffer;
-    buffer.fill(0);
-    wifi_error status = global_func_table_.wifi_get_driver_version(
-        getIfaceHandle(iface_name), buffer.data(), buffer.size());
-    return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
-    const std::string& iface_name) {
-    std::array<char, kMaxVersionStringLength> buffer;
-    buffer.fill(0);
-    wifi_error status = global_func_table_.wifi_get_firmware_version(
-        getIfaceHandle(iface_name), buffer.data(), buffer.size());
-    return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestDriverMemoryDump(const std::string& iface_name) {
-    std::vector<uint8_t> driver_dump;
-    on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
-                                                             int buffer_size) {
-        driver_dump.insert(driver_dump.end(),
-                           reinterpret_cast<uint8_t*>(buffer),
-                           reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-    };
-    wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
-        getIfaceHandle(iface_name), {onSyncDriverMemoryDump});
-    on_driver_memory_dump_internal_callback = nullptr;
-    return {status, std::move(driver_dump)};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) {
-    std::vector<uint8_t> firmware_dump;
-    on_firmware_memory_dump_internal_callback =
-        [&firmware_dump](char* buffer, int buffer_size) {
-            firmware_dump.insert(
-                firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
-                reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-        };
-    wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
-        getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
-    on_firmware_memory_dump_internal_callback = nullptr;
-    return {status, std::move(firmware_dump)};
-}
-
-std::pair<wifi_error, uint64_t> WifiLegacyHal::getSupportedFeatureSet(
-    const std::string& iface_name) {
-    feature_set set = 0, chip_set = 0;
-    wifi_error status = WIFI_SUCCESS;
-
-    static_assert(sizeof(set) == sizeof(uint64_t),
-                  "Some feature_flags can not be represented in output");
-    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
-
-    global_func_table_.wifi_get_chip_feature_set(
-        global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */
-
-    if (iface_handle) {
-        status = global_func_table_.wifi_get_supported_feature_set(iface_handle,
-                                                                   &set);
-    }
-    return {status, static_cast<uint64_t>(set | chip_set)};
-}
-
-std::pair<wifi_error, PacketFilterCapabilities>
-WifiLegacyHal::getPacketFilterCapabilities(const std::string& iface_name) {
-    PacketFilterCapabilities caps;
-    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
-        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
-    return {status, caps};
-}
-
-wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
-                                          const std::vector<uint8_t>& program) {
-    return global_func_table_.wifi_set_packet_filter(
-        getIfaceHandle(iface_name), program.data(), program.size());
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::readApfPacketFilterData(const std::string& iface_name) {
-    PacketFilterCapabilities caps;
-    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
-        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
-    if (status != WIFI_SUCCESS) {
-        return {status, {}};
-    }
-
-    // Size the buffer to read the entire program & work memory.
-    std::vector<uint8_t> buffer(caps.max_len);
-
-    status = global_func_table_.wifi_read_packet_filter(
-        getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(),
-        buffer.size());
-    return {status, move(buffer)};
-}
-
-std::pair<wifi_error, wifi_gscan_capabilities>
-WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
-    wifi_gscan_capabilities caps;
-    wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
-        getIfaceHandle(iface_name), &caps);
-    return {status, caps};
-}
-
-wifi_error WifiLegacyHal::startGscan(
-    const std::string& iface_name, wifi_request_id id,
-    const wifi_scan_cmd_params& params,
-    const std::function<void(wifi_request_id)>& on_failure_user_callback,
-    const on_gscan_results_callback& on_results_user_callback,
-    const on_gscan_full_result_callback& on_full_result_user_callback) {
-    // If there is already an ongoing background scan, reject new scan requests.
-    if (on_gscan_event_internal_callback ||
-        on_gscan_full_result_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-
-    // This callback will be used to either trigger |on_results_user_callback|
-    // or |on_failure_user_callback|.
-    on_gscan_event_internal_callback =
-        [iface_name, on_failure_user_callback, on_results_user_callback, this](
-            wifi_request_id id, wifi_scan_event event) {
-            switch (event) {
-                case WIFI_SCAN_RESULTS_AVAILABLE:
-                case WIFI_SCAN_THRESHOLD_NUM_SCANS:
-                case WIFI_SCAN_THRESHOLD_PERCENT: {
-                    wifi_error status;
-                    std::vector<wifi_cached_scan_results> cached_scan_results;
-                    std::tie(status, cached_scan_results) =
-                        getGscanCachedResults(iface_name);
-                    if (status == WIFI_SUCCESS) {
-                        on_results_user_callback(id, cached_scan_results);
-                        return;
-                    }
-                    FALLTHROUGH_INTENDED;
-                }
-                // Fall through if failed. Failure to retrieve cached scan
-                // results should trigger a background scan failure.
-                case WIFI_SCAN_FAILED:
-                    on_failure_user_callback(id);
-                    on_gscan_event_internal_callback = nullptr;
-                    on_gscan_full_result_internal_callback = nullptr;
-                    return;
-            }
-            LOG(FATAL) << "Unexpected gscan event received: " << event;
-        };
-
-    on_gscan_full_result_internal_callback = [on_full_result_user_callback](
-                                                 wifi_request_id id,
-                                                 wifi_scan_result* result,
-                                                 uint32_t buckets_scanned) {
-        if (result) {
-            on_full_result_user_callback(id, result, buckets_scanned);
-        }
-    };
-
-    wifi_scan_result_handler handler = {onAsyncGscanFullResult,
-                                        onAsyncGscanEvent};
-    wifi_error status = global_func_table_.wifi_start_gscan(
-        id, getIfaceHandle(iface_name), params, handler);
-    if (status != WIFI_SUCCESS) {
-        on_gscan_event_internal_callback = nullptr;
-        on_gscan_full_result_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name,
-                                    wifi_request_id id) {
-    // If there is no an ongoing background scan, reject stop requests.
-    // TODO(b/32337212): This needs to be handled by the HIDL object because we
-    // need to return the NOT_STARTED error code.
-    if (!on_gscan_event_internal_callback &&
-        !on_gscan_full_result_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    wifi_error status =
-        global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
-    // If the request Id is wrong, don't stop the ongoing background scan. Any
-    // other error should be treated as the end of background scan.
-    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-        on_gscan_event_internal_callback = nullptr;
-        on_gscan_full_result_internal_callback = nullptr;
-    }
-    return status;
-}
-
-std::pair<wifi_error, std::vector<uint32_t>>
-WifiLegacyHal::getValidFrequenciesForBand(const std::string& iface_name,
-                                          wifi_band band) {
-    static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
-                  "Wifi Channel cannot be represented in output");
-    std::vector<uint32_t> freqs;
-    freqs.resize(kMaxGscanFrequenciesForBand);
-    int32_t num_freqs = 0;
-    wifi_error status = global_func_table_.wifi_get_valid_channels(
-        getIfaceHandle(iface_name), band, freqs.size(),
-        reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
-    CHECK(num_freqs >= 0 &&
-          static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
-    freqs.resize(num_freqs);
-    return {status, std::move(freqs)};
-}
-
-wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name,
-                                     bool dfs_on) {
-    return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name),
-                                                  dfs_on ? 0 : 1);
-}
-
-wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name,
-                                               bool debug) {
-    wifi_link_layer_params params;
-    params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
-    params.aggressive_statistics_gathering = debug;
-    return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name),
-                                                  params);
-}
-
-wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
-    // TODO: Do we care about these responses?
-    uint32_t clear_mask_rsp;
-    uint8_t stop_rsp;
-    return global_func_table_.wifi_clear_link_stats(
-        getIfaceHandle(iface_name), 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
-}
-
-std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
-    const std::string& iface_name) {
-    LinkLayerStats link_stats{};
-    LinkLayerStats* link_stats_ptr = &link_stats;
-
-    on_link_layer_stats_result_internal_callback =
-        [&link_stats_ptr](wifi_request_id /* id */,
-                          wifi_iface_stat* iface_stats_ptr, int num_radios,
-                          wifi_radio_stat* radio_stats_ptr) {
-            wifi_radio_stat* l_radio_stats_ptr;
-            wifi_peer_info* l_peer_info_stats_ptr;
-
-            if (iface_stats_ptr != nullptr) {
-                link_stats_ptr->iface = *iface_stats_ptr;
-                l_peer_info_stats_ptr = iface_stats_ptr->peer_info;
-                for (uint32_t i = 0; i < iface_stats_ptr->num_peers; i++) {
-                    WifiPeerInfo peer;
-                    peer.peer_info = *l_peer_info_stats_ptr;
-                    if (l_peer_info_stats_ptr->num_rate > 0) {
-                        /* Copy the rate stats */
-                        peer.rate_stats.assign(
-                            l_peer_info_stats_ptr->rate_stats,
-                            l_peer_info_stats_ptr->rate_stats +
-                                l_peer_info_stats_ptr->num_rate);
-                    }
-                    peer.peer_info.num_rate = 0;
-                    link_stats_ptr->peers.push_back(peer);
-                    l_peer_info_stats_ptr =
-                        (wifi_peer_info*)((u8*)l_peer_info_stats_ptr +
-                                          sizeof(wifi_peer_info) +
-                                          (sizeof(wifi_rate_stat) *
-                                           l_peer_info_stats_ptr->num_rate));
-                }
-                link_stats_ptr->iface.num_peers = 0;
-            } else {
-                LOG(ERROR) << "Invalid iface stats in link layer stats";
-            }
-            if (num_radios <= 0 || radio_stats_ptr == nullptr) {
-                LOG(ERROR) << "Invalid radio stats in link layer stats";
-                return;
-            }
-            l_radio_stats_ptr = radio_stats_ptr;
-            for (int i = 0; i < num_radios; i++) {
-                LinkLayerRadioStats radio;
-
-                radio.stats = *l_radio_stats_ptr;
-                // Copy over the tx level array to the separate vector.
-                if (l_radio_stats_ptr->num_tx_levels > 0 &&
-                    l_radio_stats_ptr->tx_time_per_levels != nullptr) {
-                    radio.tx_time_per_levels.assign(
-                        l_radio_stats_ptr->tx_time_per_levels,
-                        l_radio_stats_ptr->tx_time_per_levels +
-                            l_radio_stats_ptr->num_tx_levels);
-                }
-                radio.stats.num_tx_levels = 0;
-                radio.stats.tx_time_per_levels = nullptr;
-                /* Copy over the channel stat to separate vector */
-                if (l_radio_stats_ptr->num_channels > 0) {
-                    /* Copy the channel stats */
-                    radio.channel_stats.assign(
-                        l_radio_stats_ptr->channels,
-                        l_radio_stats_ptr->channels +
-                            l_radio_stats_ptr->num_channels);
-                }
-                link_stats_ptr->radios.push_back(radio);
-                l_radio_stats_ptr =
-                    (wifi_radio_stat*)((u8*)l_radio_stats_ptr +
-                                       sizeof(wifi_radio_stat) +
-                                       (sizeof(wifi_channel_stat) *
-                                        l_radio_stats_ptr->num_channels));
-            }
-        };
-
-    wifi_error status = global_func_table_.wifi_get_link_stats(
-        0, getIfaceHandle(iface_name), {onSyncLinkLayerStatsResult});
-    on_link_layer_stats_result_internal_callback = nullptr;
-    return {status, link_stats};
-}
-
-wifi_error WifiLegacyHal::startRssiMonitoring(
-    const std::string& iface_name, wifi_request_id id, int8_t max_rssi,
-    int8_t min_rssi,
-    const on_rssi_threshold_breached_callback&
-        on_threshold_breached_user_callback) {
-    if (on_rssi_threshold_breached_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_rssi_threshold_breached_internal_callback =
-        [on_threshold_breached_user_callback](wifi_request_id id,
-                                              uint8_t* bssid_ptr, int8_t rssi) {
-            if (!bssid_ptr) {
-                return;
-            }
-            std::array<uint8_t, 6> bssid_arr;
-            // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
-            // address.
-            std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
-            on_threshold_breached_user_callback(id, bssid_arr, rssi);
-        };
-    wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
-        id, getIfaceHandle(iface_name), max_rssi, min_rssi,
-        {onAsyncRssiThresholdBreached});
-    if (status != WIFI_SUCCESS) {
-        on_rssi_threshold_breached_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name,
-                                             wifi_request_id id) {
-    if (!on_rssi_threshold_breached_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    wifi_error status = global_func_table_.wifi_stop_rssi_monitoring(
-        id, getIfaceHandle(iface_name));
-    // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
-    // other error should be treated as the end of background scan.
-    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-        on_rssi_threshold_breached_internal_callback = nullptr;
-    }
-    return status;
-}
-
-std::pair<wifi_error, wifi_roaming_capabilities>
-WifiLegacyHal::getRoamingCapabilities(const std::string& iface_name) {
-    wifi_roaming_capabilities caps;
-    wifi_error status = global_func_table_.wifi_get_roaming_capabilities(
-        getIfaceHandle(iface_name), &caps);
-    return {status, caps};
-}
-
-wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
-                                           const wifi_roaming_config& config) {
-    wifi_roaming_config config_internal = config;
-    return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name),
-                                                     &config_internal);
-}
-
-wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
-                                                fw_roaming_state_t state) {
-    return global_func_table_.wifi_enable_firmware_roaming(
-        getIfaceHandle(iface_name), state);
-}
-
-wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name,
-                                             bool enable) {
-    return global_func_table_.wifi_configure_nd_offload(
-        getIfaceHandle(iface_name), enable);
-}
-
-wifi_error WifiLegacyHal::startSendingOffloadedPacket(
-    const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
-    const std::vector<uint8_t>& ip_packet_data,
-    const std::array<uint8_t, 6>& src_address,
-    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
-    std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
-    std::vector<uint8_t> src_address_internal(
-        src_address.data(), src_address.data() + src_address.size());
-    std::vector<uint8_t> dst_address_internal(
-        dst_address.data(), dst_address.data() + dst_address.size());
-    return global_func_table_.wifi_start_sending_offloaded_packet(
-        cmd_id, getIfaceHandle(iface_name), ether_type,
-        ip_packet_data_internal.data(), ip_packet_data_internal.size(),
-        src_address_internal.data(), dst_address_internal.data(), period_in_ms);
-}
-
-wifi_error WifiLegacyHal::stopSendingOffloadedPacket(
-    const std::string& iface_name, uint32_t cmd_id) {
-    return global_func_table_.wifi_stop_sending_offloaded_packet(
-        cmd_id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
-                                                wifi_power_scenario scenario) {
-    return global_func_table_.wifi_select_tx_power_scenario(
-        getIfaceHandle(iface_name), scenario);
-}
-
-wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
-    return global_func_table_.wifi_reset_tx_power_scenario(
-        getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name,
-                                         wifi_latency_mode mode) {
-    return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name),
-                                                    mode);
-}
-
-wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode,
-                                                   uint32_t completion_window) {
-    return global_func_table_.wifi_set_thermal_mitigation_mode(
-        global_handle_, mode, completion_window);
-}
-
-wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping(
-    uint32_t start, uint32_t end, uint32_t access_category) {
-    return global_func_table_.wifi_map_dscp_access_category(
-        global_handle_, start, end, access_category);
-}
-
-wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() {
-    return global_func_table_.wifi_reset_dscp_mapping(global_handle_);
-}
-
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
-    const std::string& iface_name) {
-    uint32_t supported_feature_flags = 0;
-    wifi_error status = WIFI_SUCCESS;
-
-    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
-
-    if (iface_handle) {
-        status = global_func_table_.wifi_get_logger_supported_feature_set(
-            iface_handle, &supported_feature_flags);
-    }
-    return {status, supported_feature_flags};
-}
-
-wifi_error WifiLegacyHal::startPktFateMonitoring(
-    const std::string& iface_name) {
-    return global_func_table_.wifi_start_pkt_fate_monitoring(
-        getIfaceHandle(iface_name));
-}
-
-std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
-    const std::string& iface_name) {
-    std::vector<wifi_tx_report> tx_pkt_fates;
-    tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
-    size_t num_fates = 0;
-    wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
-        getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(),
-        &num_fates);
-    CHECK(num_fates <= MAX_FATE_LOG_LEN);
-    tx_pkt_fates.resize(num_fates);
-    return {status, std::move(tx_pkt_fates)};
-}
-
-std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
-    const std::string& iface_name) {
-    std::vector<wifi_rx_report> rx_pkt_fates;
-    rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
-    size_t num_fates = 0;
-    wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
-        getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(),
-        &num_fates);
-    CHECK(num_fates <= MAX_FATE_LOG_LEN);
-    rx_pkt_fates.resize(num_fates);
-    return {status, std::move(rx_pkt_fates)};
-}
-
-std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
-    const std::string& iface_name) {
-    WakeReasonStats stats;
-    stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
-    stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
-
-    // This legacy struct needs separate memory to store the variable sized wake
-    // reason types.
-    stats.wake_reason_cnt.cmd_event_wake_cnt =
-        reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
-    stats.wake_reason_cnt.cmd_event_wake_cnt_sz =
-        stats.cmd_event_wake_cnt.size();
-    stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt =
-        reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz =
-        stats.driver_fw_local_wake_cnt.size();
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
-
-    wifi_error status = global_func_table_.wifi_get_wake_reason_stats(
-        getIfaceHandle(iface_name), &stats.wake_reason_cnt);
-
-    CHECK(
-        stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
-        static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
-            kMaxWakeReasonStatsArraySize);
-    stats.cmd_event_wake_cnt.resize(
-        stats.wake_reason_cnt.cmd_event_wake_cnt_used);
-    stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
-
-    CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
-          static_cast<uint32_t>(
-              stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
-              kMaxWakeReasonStatsArraySize);
-    stats.driver_fw_local_wake_cnt.resize(
-        stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
-
-    return {status, stats};
-}
-
-wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
-    const std::string& iface_name,
-    const on_ring_buffer_data_callback& on_user_data_callback) {
-    if (on_ring_buffer_data_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_ring_buffer_data_internal_callback =
-        [on_user_data_callback](char* ring_name, char* buffer, int buffer_size,
-                                wifi_ring_buffer_status* status) {
-            if (status && buffer) {
-                std::vector<uint8_t> buffer_vector(
-                    reinterpret_cast<uint8_t*>(buffer),
-                    reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-                on_user_data_callback(ring_name, buffer_vector, *status);
-            }
-        };
-    wifi_error status = global_func_table_.wifi_set_log_handler(
-        0, getIfaceHandle(iface_name), {onAsyncRingBufferData});
-    if (status != WIFI_SUCCESS) {
-        on_ring_buffer_data_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(
-    const std::string& iface_name) {
-    if (!on_ring_buffer_data_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_ring_buffer_data_internal_callback = nullptr;
-    return global_func_table_.wifi_reset_log_handler(
-        0, getIfaceHandle(iface_name));
-}
-
-std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
-WifiLegacyHal::getRingBuffersStatus(const std::string& iface_name) {
-    std::vector<wifi_ring_buffer_status> ring_buffers_status;
-    ring_buffers_status.resize(kMaxRingBuffers);
-    uint32_t num_rings = kMaxRingBuffers;
-    wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
-        getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
-    CHECK(num_rings <= kMaxRingBuffers);
-    ring_buffers_status.resize(num_rings);
-    return {status, std::move(ring_buffers_status)};
-}
-
-wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
-                                                 const std::string& ring_name,
-                                                 uint32_t verbose_level,
-                                                 uint32_t max_interval_sec,
-                                                 uint32_t min_data_size) {
-    return global_func_table_.wifi_start_logging(
-        getIfaceHandle(iface_name), verbose_level, 0, max_interval_sec,
-        min_data_size, makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
-                                            const std::string& ring_name) {
-    return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
-                                                 makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
-    const std::string& iface_name,
-    const on_error_alert_callback& on_user_alert_callback) {
-    if (on_error_alert_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_error_alert_internal_callback = [on_user_alert_callback](
-                                           wifi_request_id id, char* buffer,
-                                           int buffer_size, int err_code) {
-        if (buffer) {
-            CHECK(id == 0);
-            on_user_alert_callback(
-                err_code,
-                std::vector<uint8_t>(
-                    reinterpret_cast<uint8_t*>(buffer),
-                    reinterpret_cast<uint8_t*>(buffer) + buffer_size));
-        }
-    };
-    wifi_error status = global_func_table_.wifi_set_alert_handler(
-        0, getIfaceHandle(iface_name), {onAsyncErrorAlert});
-    if (status != WIFI_SUCCESS) {
-        on_error_alert_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(
-    const std::string& iface_name) {
-    if (!on_error_alert_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_error_alert_internal_callback = nullptr;
-    return global_func_table_.wifi_reset_alert_handler(
-        0, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
-    const std::string& iface_name,
-    const on_radio_mode_change_callback& on_user_change_callback) {
-    if (on_radio_mode_change_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_radio_mode_change_internal_callback = [on_user_change_callback](
-                                                 wifi_request_id /* id */,
-                                                 uint32_t num_macs,
-                                                 wifi_mac_info* mac_infos_arr) {
-        if (num_macs > 0 && mac_infos_arr) {
-            std::vector<WifiMacInfo> mac_infos_vec;
-            for (uint32_t i = 0; i < num_macs; i++) {
-                WifiMacInfo mac_info;
-                mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
-                mac_info.mac_band = mac_infos_arr[i].mac_band;
-                for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
-                    WifiIfaceInfo iface_info;
-                    iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
-                    iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
-                    mac_info.iface_infos.push_back(iface_info);
-                }
-                mac_infos_vec.push_back(mac_info);
-            }
-            on_user_change_callback(mac_infos_vec);
-        }
-    };
-    wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
-        0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
-    if (status != WIFI_SUCCESS) {
-        on_radio_mode_change_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::registerSubsystemRestartCallbackHandler(
-    const on_subsystem_restart_callback& on_restart_callback) {
-    if (on_subsystem_restart_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_subsystem_restart_internal_callback =
-        [on_restart_callback](const char* error) {
-            on_restart_callback(error);
-        };
-    wifi_error status = global_func_table_.wifi_set_subsystem_restart_handler(
-        global_handle_, {onAsyncSubsystemRestart});
-    if (status != WIFI_SUCCESS) {
-        on_subsystem_restart_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::startRttRangeRequest(
-    const std::string& iface_name, wifi_request_id id,
-    const std::vector<wifi_rtt_config>& rtt_configs,
-    const on_rtt_results_callback& on_results_user_callback) {
-    if (on_rtt_results_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-
-    on_rtt_results_internal_callback =
-        [on_results_user_callback](wifi_request_id id, unsigned num_results,
-                                   wifi_rtt_result* rtt_results[]) {
-            if (num_results > 0 && !rtt_results) {
-                LOG(ERROR) << "Unexpected nullptr in RTT results";
-                return;
-            }
-            std::vector<const wifi_rtt_result*> rtt_results_vec;
-            std::copy_if(rtt_results, rtt_results + num_results,
-                         back_inserter(rtt_results_vec),
-                         [](wifi_rtt_result* rtt_result) {
-                             return rtt_result != nullptr;
-                         });
-            on_results_user_callback(id, rtt_results_vec);
-        };
-
-    std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
-    wifi_error status = global_func_table_.wifi_rtt_range_request(
-        id, getIfaceHandle(iface_name), rtt_configs.size(),
-        rtt_configs_internal.data(), {onAsyncRttResults});
-    if (status != WIFI_SUCCESS) {
-        on_rtt_results_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::cancelRttRangeRequest(
-    const std::string& iface_name, wifi_request_id id,
-    const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
-    if (!on_rtt_results_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>),
-                  "MAC address size mismatch");
-    // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
-    // addressed are cancelled).
-    std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
-    wifi_error status = global_func_table_.wifi_rtt_range_cancel(
-        id, getIfaceHandle(iface_name), mac_addrs.size(),
-        reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
-    // If the request Id is wrong, don't stop the ongoing range request. Any
-    // other error should be treated as the end of rtt ranging.
-    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-        on_rtt_results_internal_callback = nullptr;
-    }
-    return status;
-}
-
-std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
-    const std::string& iface_name) {
-    wifi_rtt_capabilities rtt_caps;
-    wifi_error status = global_func_table_.wifi_get_rtt_capabilities(
-        getIfaceHandle(iface_name), &rtt_caps);
-    return {status, rtt_caps};
-}
-
-std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
-    const std::string& iface_name) {
-    wifi_rtt_responder rtt_responder;
-    wifi_error status = global_func_table_.wifi_rtt_get_responder_info(
-        getIfaceHandle(iface_name), &rtt_responder);
-    return {status, rtt_responder};
-}
-
-wifi_error WifiLegacyHal::enableRttResponder(
-    const std::string& iface_name, wifi_request_id id,
-    const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
-    const wifi_rtt_responder& info) {
-    wifi_rtt_responder info_internal(info);
-    return global_func_table_.wifi_enable_responder(
-        id, getIfaceHandle(iface_name), channel_hint, max_duration_secs,
-        &info_internal);
-}
-
-wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name,
-                                              wifi_request_id id) {
-    return global_func_table_.wifi_disable_responder(
-        id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name,
-                                    wifi_request_id id,
-                                    const wifi_lci_information& info) {
-    wifi_lci_information info_internal(info);
-    return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name),
-                                           &info_internal);
-}
-
-wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name,
-                                    wifi_request_id id,
-                                    const wifi_lcr_information& info) {
-    wifi_lcr_information info_internal(info);
-    return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name),
-                                           &info_internal);
-}
-
-wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(
-    const std::string& iface_name, const NanCallbackHandlers& user_callbacks) {
-    on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
-    on_nan_event_publish_terminated_user_callback =
-        user_callbacks.on_event_publish_terminated;
-    on_nan_event_match_user_callback = user_callbacks.on_event_match;
-    on_nan_event_match_expired_user_callback =
-        user_callbacks.on_event_match_expired;
-    on_nan_event_subscribe_terminated_user_callback =
-        user_callbacks.on_event_subscribe_terminated;
-    on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
-    on_nan_event_disc_eng_event_user_callback =
-        user_callbacks.on_event_disc_eng_event;
-    on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
-    on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
-    on_nan_event_beacon_sdf_payload_user_callback =
-        user_callbacks.on_event_beacon_sdf_payload;
-    on_nan_event_data_path_request_user_callback =
-        user_callbacks.on_event_data_path_request;
-    on_nan_event_data_path_confirm_user_callback =
-        user_callbacks.on_event_data_path_confirm;
-    on_nan_event_data_path_end_user_callback =
-        user_callbacks.on_event_data_path_end;
-    on_nan_event_transmit_follow_up_user_callback =
-        user_callbacks.on_event_transmit_follow_up;
-    on_nan_event_range_request_user_callback =
-        user_callbacks.on_event_range_request;
-    on_nan_event_range_report_user_callback =
-        user_callbacks.on_event_range_report;
-    on_nan_event_schedule_update_user_callback =
-        user_callbacks.on_event_schedule_update;
-
-    return global_func_table_.wifi_nan_register_handler(
-        getIfaceHandle(iface_name),
-        {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
-         onAysncNanEventPublishTerminated, onAysncNanEventMatch,
-         onAysncNanEventMatchExpired, onAysncNanEventSubscribeTerminated,
-         onAysncNanEventFollowup, onAysncNanEventDiscEngEvent,
-         onAysncNanEventDisabled, onAysncNanEventTca,
-         onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
-         onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
-         onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
-         onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
-}
-
-wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
-                                           transaction_id id,
-                                           const NanEnableRequest& msg) {
-    NanEnableRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_enable_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name,
-                                            transaction_id id) {
-    return global_func_table_.wifi_nan_disable_request(
-        id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name,
-                                            transaction_id id,
-                                            const NanPublishRequest& msg) {
-    NanPublishRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_publish_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanPublishCancelRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanPublishCancelRequest& msg) {
-    NanPublishCancelRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_publish_cancel_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name,
-                                              transaction_id id,
-                                              const NanSubscribeRequest& msg) {
-    NanSubscribeRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_subscribe_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeCancelRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanSubscribeCancelRequest& msg) {
-    NanSubscribeCancelRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_subscribe_cancel_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTransmitFollowupRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanTransmitFollowupRequest& msg) {
-    NanTransmitFollowupRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_transmit_followup_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name,
-                                          transaction_id id,
-                                          const NanStatsRequest& msg) {
-    NanStatsRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_stats_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name,
-                                           transaction_id id,
-                                           const NanConfigRequest& msg) {
-    NanConfigRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_config_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name,
-                                        transaction_id id,
-                                        const NanTCARequest& msg) {
-    NanTCARequest msg_internal(msg);
-    return global_func_table_.wifi_nan_tca_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanBeaconSdfPayloadRequest& msg) {
-    NanBeaconSdfPayloadRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_beacon_sdf_payload_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
-    NanVersion version;
-    wifi_error status =
-        global_func_table_.wifi_nan_get_version(global_handle_, &version);
-    return {status, version};
-}
-
-wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name,
-                                             transaction_id id) {
-    return global_func_table_.wifi_nan_get_capabilities(
-        id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceCreate(
-    const std::string& iface_name, transaction_id id,
-    const std::string& data_iface_name) {
-    return global_func_table_.wifi_nan_data_interface_create(
-        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceDelete(
-    const std::string& iface_name, transaction_id id,
-    const std::string& data_iface_name) {
-    return global_func_table_.wifi_nan_data_interface_delete(
-        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataRequestInitiator(
-    const std::string& iface_name, transaction_id id,
-    const NanDataPathInitiatorRequest& msg) {
-    NanDataPathInitiatorRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_data_request_initiator(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDataIndicationResponse(
-    const std::string& iface_name, transaction_id id,
-    const NanDataPathIndicationResponse& msg) {
-    NanDataPathIndicationResponse msg_internal(msg);
-    return global_func_table_.wifi_nan_data_indication_response(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-typedef struct {
-    u8 num_ndp_instances;
-    NanDataPathId ndp_instance_id;
-} NanDataPathEndSingleNdpIdRequest;
-
-wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name,
-                                     transaction_id id,
-                                     uint32_t ndpInstanceId) {
-    NanDataPathEndSingleNdpIdRequest msg;
-    msg.num_ndp_instances = 1;
-    msg.ndp_instance_id = ndpInstanceId;
-    wifi_error status = global_func_table_.wifi_nan_data_end(
-        id, getIfaceHandle(iface_name), (NanDataPathEndRequest*)&msg);
-    return status;
-}
-
-wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
-                                         std::array<int8_t, 2> code) {
-    std::string code_str(code.data(), code.data() + code.size());
-    return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name),
-                                                    code_str.c_str());
-}
-
-wifi_error WifiLegacyHal::retrieveIfaceHandles() {
-    wifi_interface_handle* iface_handles = nullptr;
-    int num_iface_handles = 0;
-    wifi_error status = global_func_table_.wifi_get_ifaces(
-        global_handle_, &num_iface_handles, &iface_handles);
-    if (status != WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to enumerate interface handles";
-        return status;
-    }
-    iface_name_to_handle_.clear();
-    for (int i = 0; i < num_iface_handles; ++i) {
-        std::array<char, IFNAMSIZ> iface_name_arr = {};
-        status = global_func_table_.wifi_get_iface_name(
-            iface_handles[i], iface_name_arr.data(), iface_name_arr.size());
-        if (status != WIFI_SUCCESS) {
-            LOG(WARNING) << "Failed to get interface handle name";
-            continue;
-        }
-        // Assuming the interface name is null terminated since the legacy HAL
-        // API does not return a size.
-        std::string iface_name(iface_name_arr.data());
-        LOG(INFO) << "Adding interface handle for " << iface_name;
-        iface_name_to_handle_[iface_name] = iface_handles[i];
-    }
-    return WIFI_SUCCESS;
-}
-
-wifi_interface_handle WifiLegacyHal::getIfaceHandle(
-    const std::string& iface_name) {
-    const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
-    if (iface_handle_iter == iface_name_to_handle_.end()) {
-        LOG(ERROR) << "Unknown iface name: " << iface_name;
-        return nullptr;
-    }
-    return iface_handle_iter->second;
-}
-
-void WifiLegacyHal::runEventLoop() {
-    LOG(DEBUG) << "Starting legacy HAL event loop";
-    global_func_table_.wifi_event_loop(global_handle_);
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (!awaiting_event_loop_termination_) {
-        LOG(FATAL)
-            << "Legacy HAL event loop terminated, but HAL was not stopping";
-    }
-    LOG(DEBUG) << "Legacy HAL event loop terminated";
-    awaiting_event_loop_termination_ = false;
-    stop_wait_cv_.notify_one();
-}
-
-std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
-WifiLegacyHal::getGscanCachedResults(const std::string& iface_name) {
-    std::vector<wifi_cached_scan_results> cached_scan_results;
-    cached_scan_results.resize(kMaxCachedGscanResults);
-    int32_t num_results = 0;
-    wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
-        getIfaceHandle(iface_name), true /* always flush */,
-        cached_scan_results.size(), cached_scan_results.data(), &num_results);
-    CHECK(num_results >= 0 &&
-          static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
-    cached_scan_results.resize(num_results);
-    // Check for invalid IE lengths in these cached scan results and correct it.
-    for (auto& cached_scan_result : cached_scan_results) {
-        int num_scan_results = cached_scan_result.num_results;
-        for (int i = 0; i < num_scan_results; i++) {
-            auto& scan_result = cached_scan_result.results[i];
-            if (scan_result.ie_length > 0) {
-                LOG(DEBUG) << "Cached scan result has non-zero IE length "
-                           << scan_result.ie_length;
-                scan_result.ie_length = 0;
-            }
-        }
-    }
-    return {status, std::move(cached_scan_results)};
-}
-
-wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
-                                                 wifi_interface_type iftype) {
-    // Create the interface if it doesn't exist. If interface already exist,
-    // Vendor Hal should return WIFI_SUCCESS.
-    wifi_error status = global_func_table_.wifi_virtual_interface_create(
-        global_handle_, ifname.c_str(), iftype);
-    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
-}
-
-wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
-    // Delete the interface if it was created dynamically.
-    wifi_error status = global_func_table_.wifi_virtual_interface_delete(
-        global_handle_, ifname.c_str());
-    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
-}
-
-wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(
-    const std::string& ifname, wifi_error status) {
-    if (status == WIFI_SUCCESS) {
-        // refresh list of handlers now.
-        status = retrieveIfaceHandles();
-    } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
-        // Vendor hal does not implement this API. Such vendor implementations
-        // are expected to create / delete interface by other means.
-
-        // check if interface exists.
-        if (if_nametoindex(ifname.c_str())) {
-            status = retrieveIfaceHandles();
-        }
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type,
-                                                std::string& ifname) {
-    std::array<char, IFNAMSIZ> buffer;
-
-    wifi_error res = global_func_table_.wifi_get_supported_iface_name(
-        global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size());
-    if (res == WIFI_SUCCESS) ifname = buffer.data();
-
-    return res;
-}
-
-wifi_error WifiLegacyHal::multiStaSetPrimaryConnection(
-    const std::string& ifname) {
-    return global_func_table_.wifi_multi_sta_set_primary_connection(
-        global_handle_, getIfaceHandle(ifname));
-}
-
-wifi_error WifiLegacyHal::multiStaSetUseCase(wifi_multi_sta_use_case use_case) {
-    return global_func_table_.wifi_multi_sta_set_use_case(global_handle_,
-                                                          use_case);
-}
-
-wifi_error WifiLegacyHal::setCoexUnsafeChannels(
-    std::vector<wifi_coex_unsafe_channel> unsafe_channels,
-    uint32_t restrictions) {
-    return global_func_table_.wifi_set_coex_unsafe_channels(
-        global_handle_, unsafe_channels.size(), unsafe_channels.data(),
-        restrictions);
-}
-
-wifi_error WifiLegacyHal::setVoipMode(const std::string& iface_name,
-                                      wifi_voip_mode mode) {
-    return global_func_table_.wifi_set_voip_mode(getIfaceHandle(iface_name),
-                                                 mode);
-}
-
-wifi_error WifiLegacyHal::twtRegisterHandler(
-    const std::string& iface_name, const TwtCallbackHandlers& user_callbacks) {
-    on_twt_event_setup_response_callback = user_callbacks.on_setup_response;
-    on_twt_event_teardown_completion_callback =
-        user_callbacks.on_teardown_completion;
-    on_twt_event_info_frame_received_callback =
-        user_callbacks.on_info_frame_received;
-    on_twt_event_device_notify_callback = user_callbacks.on_device_notify;
-
-    return global_func_table_.wifi_twt_register_handler(
-        getIfaceHandle(iface_name),
-        {onAsyncTwtEventSetupResponse, onAsyncTwtEventTeardownCompletion,
-         onAsyncTwtEventInfoFrameReceived, onAsyncTwtEventDeviceNotify});
-}
-
-std::pair<wifi_error, TwtCapabilitySet> WifiLegacyHal::twtGetCapability(
-    const std::string& iface_name) {
-    TwtCapabilitySet capSet;
-    wifi_error status = global_func_table_.wifi_twt_get_capability(
-        getIfaceHandle(iface_name), &capSet);
-    return {status, capSet};
-}
-
-wifi_error WifiLegacyHal::twtSetupRequest(const std::string& iface_name,
-                                          const TwtSetupRequest& msg) {
-    TwtSetupRequest msgInternal(msg);
-    return global_func_table_.wifi_twt_setup_request(getIfaceHandle(iface_name),
-                                                     &msgInternal);
-}
-
-wifi_error WifiLegacyHal::twtTearDownRequest(const std::string& iface_name,
-                                             const TwtTeardownRequest& msg) {
-    TwtTeardownRequest msgInternal(msg);
-    return global_func_table_.wifi_twt_teardown_request(
-        getIfaceHandle(iface_name), &msgInternal);
-}
-
-wifi_error WifiLegacyHal::twtInfoFrameRequest(const std::string& iface_name,
-                                              const TwtInfoFrameRequest& msg) {
-    TwtInfoFrameRequest msgInternal(msg);
-    return global_func_table_.wifi_twt_info_frame_request(
-        getIfaceHandle(iface_name), &msgInternal);
-}
-
-std::pair<wifi_error, TwtStats> WifiLegacyHal::twtGetStats(
-    const std::string& iface_name, uint8_t configId) {
-    TwtStats stats;
-    wifi_error status = global_func_table_.wifi_twt_get_stats(
-        getIfaceHandle(iface_name), configId, &stats);
-    return {status, stats};
-}
-
-wifi_error WifiLegacyHal::twtClearStats(const std::string& iface_name,
-                                        uint8_t configId) {
-    return global_func_table_.wifi_twt_clear_stats(getIfaceHandle(iface_name),
-                                                   configId);
-}
-
-wifi_error WifiLegacyHal::setDtimConfig(const std::string& iface_name,
-                                        uint32_t multiplier) {
-    return global_func_table_.wifi_set_dtim_config(getIfaceHandle(iface_name),
-                                                   multiplier);
-}
-
-std::pair<wifi_error, std::vector<wifi_usable_channel>>
-WifiLegacyHal::getUsableChannels(uint32_t band_mask, uint32_t iface_mode_mask,
-                                 uint32_t filter_mask) {
-    std::vector<wifi_usable_channel> channels;
-    channels.resize(kMaxWifiUsableChannels);
-    uint32_t size = 0;
-    wifi_error status = global_func_table_.wifi_get_usable_channels(
-        global_handle_, band_mask, iface_mode_mask, filter_mask,
-        channels.size(), &size,
-        reinterpret_cast<wifi_usable_channel*>(channels.data()));
-    CHECK(size >= 0 && size <= kMaxWifiUsableChannels);
-    channels.resize(size);
-    return {status, std::move(channels)};
-}
-
-wifi_error WifiLegacyHal::triggerSubsystemRestart() {
-    return global_func_table_.wifi_trigger_subsystem_restart(global_handle_);
-}
-
-void WifiLegacyHal::invalidate() {
-    global_handle_ = nullptr;
-    iface_name_to_handle_.clear();
-    on_driver_memory_dump_internal_callback = nullptr;
-    on_firmware_memory_dump_internal_callback = nullptr;
-    on_gscan_event_internal_callback = nullptr;
-    on_gscan_full_result_internal_callback = nullptr;
-    on_link_layer_stats_result_internal_callback = nullptr;
-    on_rssi_threshold_breached_internal_callback = nullptr;
-    on_ring_buffer_data_internal_callback = nullptr;
-    on_error_alert_internal_callback = nullptr;
-    on_radio_mode_change_internal_callback = nullptr;
-    on_subsystem_restart_internal_callback = nullptr;
-    on_rtt_results_internal_callback = nullptr;
-    on_nan_notify_response_user_callback = nullptr;
-    on_nan_event_publish_terminated_user_callback = nullptr;
-    on_nan_event_match_user_callback = nullptr;
-    on_nan_event_match_expired_user_callback = nullptr;
-    on_nan_event_subscribe_terminated_user_callback = nullptr;
-    on_nan_event_followup_user_callback = nullptr;
-    on_nan_event_disc_eng_event_user_callback = nullptr;
-    on_nan_event_disabled_user_callback = nullptr;
-    on_nan_event_tca_user_callback = nullptr;
-    on_nan_event_beacon_sdf_payload_user_callback = nullptr;
-    on_nan_event_data_path_request_user_callback = nullptr;
-    on_nan_event_data_path_confirm_user_callback = nullptr;
-    on_nan_event_data_path_end_user_callback = nullptr;
-    on_nan_event_transmit_follow_up_user_callback = nullptr;
-    on_nan_event_range_request_user_callback = nullptr;
-    on_nan_event_range_report_user_callback = nullptr;
-    on_nan_event_schedule_update_user_callback = nullptr;
-    on_twt_event_setup_response_callback = nullptr;
-    on_twt_event_teardown_completion_callback = nullptr;
-    on_twt_event_info_frame_received_callback = nullptr;
-    on_twt_event_device_notify_callback = nullptr;
-}
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
deleted file mode 100644
index 2bb7631..0000000
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_LEGACY_HAL_H_
-#define WIFI_LEGACY_HAL_H_
-
-#include <condition_variable>
-#include <functional>
-#include <map>
-#include <thread>
-#include <vector>
-
-#include <hardware_legacy/wifi_hal.h>
-#include <wifi_system/interface_tool.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-// This is in a separate namespace to prevent typename conflicts between
-// the legacy HAL types and the HIDL interface types.
-namespace legacy_hal {
-// Import all the types defined inside the legacy HAL header files into this
-// namespace.
-using ::frame_info;
-using ::frame_type;
-using ::FRAME_TYPE_80211_MGMT;
-using ::FRAME_TYPE_ETHERNET_II;
-using ::FRAME_TYPE_UNKNOWN;
-using ::fw_roaming_state_t;
-using ::mac_addr;
-using ::NAN_CHANNEL_24G_BAND;
-using ::NAN_CHANNEL_5G_BAND_HIGH;
-using ::NAN_CHANNEL_5G_BAND_LOW;
-using ::NAN_DISABLE_RANGE_REPORT;
-using ::NAN_DO_NOT_USE_SRF;
-using ::NAN_DP_CHANNEL_NOT_REQUESTED;
-using ::NAN_DP_CONFIG_NO_SECURITY;
-using ::NAN_DP_CONFIG_SECURITY;
-using ::NAN_DP_END;
-using ::NAN_DP_FORCE_CHANNEL_SETUP;
-using ::NAN_DP_INITIATOR_RESPONSE;
-using ::NAN_DP_INTERFACE_CREATE;
-using ::NAN_DP_INTERFACE_DELETE;
-using ::NAN_DP_REQUEST_ACCEPT;
-using ::NAN_DP_REQUEST_CHANNEL_SETUP;
-using ::NAN_DP_REQUEST_REJECT;
-using ::NAN_DP_RESPONDER_RESPONSE;
-using ::NAN_GET_CAPABILITIES;
-using ::NAN_MATCH_ALG_MATCH_CONTINUOUS;
-using ::NAN_MATCH_ALG_MATCH_NEVER;
-using ::NAN_MATCH_ALG_MATCH_ONCE;
-using ::NAN_PUBLISH_TYPE_SOLICITED;
-using ::NAN_PUBLISH_TYPE_UNSOLICITED;
-using ::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
-using ::NAN_RANGING_AUTO_RESPONSE_DISABLE;
-using ::NAN_RANGING_AUTO_RESPONSE_ENABLE;
-using ::NAN_RANGING_DISABLE;
-using ::NAN_RANGING_ENABLE;
-using ::NAN_RESPONSE_BEACON_SDF_PAYLOAD;
-using ::NAN_RESPONSE_CONFIG;
-using ::NAN_RESPONSE_DISABLED;
-using ::NAN_RESPONSE_ENABLED;
-using ::NAN_RESPONSE_ERROR;
-using ::NAN_RESPONSE_PUBLISH;
-using ::NAN_RESPONSE_PUBLISH_CANCEL;
-using ::NAN_RESPONSE_STATS;
-using ::NAN_RESPONSE_SUBSCRIBE;
-using ::NAN_RESPONSE_SUBSCRIBE_CANCEL;
-using ::NAN_RESPONSE_TCA;
-using ::NAN_RESPONSE_TRANSMIT_FOLLOWUP;
-using ::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-using ::NAN_SECURITY_KEY_INPUT_PMK;
-using ::NAN_SERVICE_ACCEPT_POLICY_ALL;
-using ::NAN_SERVICE_ACCEPT_POLICY_NONE;
-using ::NAN_SRF_ATTR_BLOOM_FILTER;
-using ::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
-using ::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
-using ::NAN_SRF_INCLUDE_RESPOND;
-using ::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
-using ::NAN_SSI_REQUIRED_IN_MATCH_IND;
-using ::NAN_STATUS_ALREADY_ENABLED;
-using ::NAN_STATUS_FOLLOWUP_QUEUE_FULL;
-using ::NAN_STATUS_INTERNAL_FAILURE;
-using ::NAN_STATUS_INVALID_NDP_ID;
-using ::NAN_STATUS_INVALID_PARAM;
-using ::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
-using ::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID;
-using ::NAN_STATUS_NAN_NOT_ALLOWED;
-using ::NAN_STATUS_NO_OTA_ACK;
-using ::NAN_STATUS_NO_RESOURCE_AVAILABLE;
-using ::NAN_STATUS_PROTOCOL_FAILURE;
-using ::NAN_STATUS_SUCCESS;
-using ::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
-using ::NAN_SUBSCRIBE_TYPE_ACTIVE;
-using ::NAN_SUBSCRIBE_TYPE_PASSIVE;
-using ::NAN_TRANSMIT_IN_DW;
-using ::NAN_TRANSMIT_IN_FAW;
-using ::NAN_TX_PRIORITY_HIGH;
-using ::NAN_TX_PRIORITY_NORMAL;
-using ::NAN_TX_TYPE_BROADCAST;
-using ::NAN_TX_TYPE_UNICAST;
-using ::NAN_USE_SRF;
-using ::NanBeaconSdfPayloadInd;
-using ::NanCapabilities;
-using ::NanChannelInfo;
-using ::NanConfigRequest;
-using ::NanDataPathChannelCfg;
-using ::NanDataPathConfirmInd;
-using ::NanDataPathEndInd;
-using ::NanDataPathIndicationResponse;
-using ::NanDataPathInitiatorRequest;
-using ::NanDataPathRequestInd;
-using ::NanDataPathScheduleUpdateInd;
-using ::NanDisabledInd;
-using ::NanDiscEngEventInd;
-using ::NanEnableRequest;
-using ::NanFollowupInd;
-using ::NanMatchAlg;
-using ::NanMatchExpiredInd;
-using ::NanMatchInd;
-using ::NanPublishCancelRequest;
-using ::NanPublishRequest;
-using ::NanPublishTerminatedInd;
-using ::NanPublishType;
-using ::NanRangeReportInd;
-using ::NanRangeRequestInd;
-using ::NanResponseMsg;
-using ::NanSRFType;
-using ::NanStatusType;
-using ::NanSubscribeCancelRequest;
-using ::NanSubscribeRequest;
-using ::NanSubscribeTerminatedInd;
-using ::NanSubscribeType;
-using ::NanTransmitFollowupInd;
-using ::NanTransmitFollowupRequest;
-using ::NanTxType;
-using ::ROAMING_DISABLE;
-using ::ROAMING_ENABLE;
-using ::RTT_PEER_AP;
-using ::RTT_PEER_NAN;
-using ::RTT_PEER_P2P_CLIENT;
-using ::RTT_PEER_P2P_GO;
-using ::RTT_PEER_STA;
-using ::rtt_peer_type;
-using ::RTT_STATUS_ABORTED;
-using ::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL;
-using ::RTT_STATUS_FAIL_BUSY_TRY_LATER;
-using ::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE;
-using ::RTT_STATUS_FAIL_INVALID_TS;
-using ::RTT_STATUS_FAIL_NO_CAPABILITY;
-using ::RTT_STATUS_FAIL_NO_RSP;
-using ::RTT_STATUS_FAIL_NOT_SCHEDULED_YET;
-using ::RTT_STATUS_FAIL_PROTOCOL;
-using ::RTT_STATUS_FAIL_REJECTED;
-using ::RTT_STATUS_FAIL_SCHEDULE;
-using ::RTT_STATUS_FAIL_TM_TIMEOUT;
-using ::RTT_STATUS_FAILURE;
-using ::RTT_STATUS_INVALID_REQ;
-using ::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
-using ::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE;
-using ::RTT_STATUS_NO_WIFI;
-using ::RTT_STATUS_SUCCESS;
-using ::RTT_TYPE_1_SIDED;
-using ::RTT_TYPE_2_SIDED;
-using ::RX_PKT_FATE_DRV_DROP_FILTER;
-using ::RX_PKT_FATE_DRV_DROP_INVALID;
-using ::RX_PKT_FATE_DRV_DROP_NOBUFS;
-using ::RX_PKT_FATE_DRV_DROP_OTHER;
-using ::RX_PKT_FATE_DRV_QUEUED;
-using ::RX_PKT_FATE_FW_DROP_FILTER;
-using ::RX_PKT_FATE_FW_DROP_INVALID;
-using ::RX_PKT_FATE_FW_DROP_NOBUFS;
-using ::RX_PKT_FATE_FW_DROP_OTHER;
-using ::RX_PKT_FATE_FW_QUEUED;
-using ::RX_PKT_FATE_SUCCESS;
-using ::ssid_t;
-using ::transaction_id;
-using ::TX_PKT_FATE_ACKED;
-using ::TX_PKT_FATE_DRV_DROP_INVALID;
-using ::TX_PKT_FATE_DRV_DROP_NOBUFS;
-using ::TX_PKT_FATE_DRV_DROP_OTHER;
-using ::TX_PKT_FATE_DRV_QUEUED;
-using ::TX_PKT_FATE_FW_DROP_INVALID;
-using ::TX_PKT_FATE_FW_DROP_NOBUFS;
-using ::TX_PKT_FATE_FW_DROP_OTHER;
-using ::TX_PKT_FATE_FW_QUEUED;
-using ::TX_PKT_FATE_SENT;
-using ::WIFI_AC_BE;
-using ::WIFI_AC_BK;
-using ::WIFI_AC_VI;
-using ::WIFI_AC_VO;
-using ::wifi_band;
-using ::WIFI_BAND_A;
-using ::WIFI_BAND_A_DFS;
-using ::WIFI_BAND_A_WITH_DFS;
-using ::WIFI_BAND_ABG;
-using ::WIFI_BAND_ABG_WITH_DFS;
-using ::WIFI_BAND_BG;
-using ::WIFI_BAND_UNSPECIFIED;
-using ::wifi_cached_scan_results;
-using ::WIFI_CHAN_WIDTH_10;
-using ::WIFI_CHAN_WIDTH_160;
-using ::WIFI_CHAN_WIDTH_20;
-using ::WIFI_CHAN_WIDTH_40;
-using ::WIFI_CHAN_WIDTH_5;
-using ::WIFI_CHAN_WIDTH_80;
-using ::WIFI_CHAN_WIDTH_80P80;
-using ::WIFI_CHAN_WIDTH_INVALID;
-using ::wifi_channel_info;
-using ::wifi_channel_stat;
-using ::wifi_channel_width;
-using ::wifi_coex_restriction;
-using ::wifi_coex_unsafe_channel;
-using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
-using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
-using ::wifi_error;
-using ::WIFI_ERROR_BUSY;
-using ::WIFI_ERROR_INVALID_ARGS;
-using ::WIFI_ERROR_INVALID_REQUEST_ID;
-using ::WIFI_ERROR_NONE;
-using ::WIFI_ERROR_NOT_AVAILABLE;
-using ::WIFI_ERROR_NOT_SUPPORTED;
-using ::WIFI_ERROR_OUT_OF_MEMORY;
-using ::WIFI_ERROR_TIMED_OUT;
-using ::WIFI_ERROR_TOO_MANY_REQUESTS;
-using ::WIFI_ERROR_UNINITIALIZED;
-using ::WIFI_ERROR_UNKNOWN;
-using ::wifi_gscan_capabilities;
-using ::wifi_hal_fn;
-using ::wifi_information_element;
-using ::WIFI_INTERFACE_IBSS;
-using ::WIFI_INTERFACE_MESH;
-using ::wifi_interface_mode;
-using ::WIFI_INTERFACE_NAN;
-using ::WIFI_INTERFACE_P2P_CLIENT;
-using ::WIFI_INTERFACE_P2P_GO;
-using ::WIFI_INTERFACE_SOFTAP;
-using ::WIFI_INTERFACE_STA;
-using ::WIFI_INTERFACE_TDLS;
-using ::wifi_interface_type;
-using ::WIFI_INTERFACE_TYPE_AP;
-using ::WIFI_INTERFACE_TYPE_NAN;
-using ::WIFI_INTERFACE_TYPE_P2P;
-using ::WIFI_INTERFACE_TYPE_STA;
-using ::WIFI_INTERFACE_UNKNOWN;
-using ::wifi_latency_mode;
-using ::WIFI_LATENCY_MODE_LOW;
-using ::WIFI_LATENCY_MODE_NORMAL;
-using ::wifi_lci_information;
-using ::wifi_lcr_information;
-using ::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
-using ::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
-using ::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
-using ::WIFI_LOGGER_PACKET_FATE_SUPPORTED;
-using ::WIFI_LOGGER_POWER_EVENT_SUPPORTED;
-using ::WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
-using ::WIFI_MOTION_EXPECTED;
-using ::WIFI_MOTION_NOT_EXPECTED;
-using ::wifi_motion_pattern;
-using ::WIFI_MOTION_UNKNOWN;
-using ::wifi_multi_sta_use_case;
-using ::wifi_power_scenario;
-using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
-using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
-using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
-using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
-using ::WIFI_POWER_SCENARIO_VOICE_CALL;
-using ::wifi_rate;
-using ::wifi_request_id;
-using ::wifi_ring_buffer_status;
-using ::wifi_roaming_capabilities;
-using ::wifi_roaming_config;
-using ::wifi_rtt_bw;
-using ::WIFI_RTT_BW_10;
-using ::WIFI_RTT_BW_160;
-using ::WIFI_RTT_BW_20;
-using ::WIFI_RTT_BW_40;
-using ::WIFI_RTT_BW_5;
-using ::WIFI_RTT_BW_80;
-using ::wifi_rtt_capabilities;
-using ::wifi_rtt_config;
-using ::wifi_rtt_preamble;
-using ::WIFI_RTT_PREAMBLE_HE;
-using ::WIFI_RTT_PREAMBLE_HT;
-using ::WIFI_RTT_PREAMBLE_LEGACY;
-using ::WIFI_RTT_PREAMBLE_VHT;
-using ::wifi_rtt_responder;
-using ::wifi_rtt_result;
-using ::wifi_rtt_status;
-using ::wifi_rtt_type;
-using ::wifi_rx_packet_fate;
-using ::wifi_rx_report;
-using ::wifi_scan_bucket_spec;
-using ::wifi_scan_cmd_params;
-using ::WIFI_SCAN_FLAG_INTERRUPTED;
-using ::wifi_scan_result;
-using ::WIFI_SUCCESS;
-using ::wifi_tx_packet_fate;
-using ::wifi_tx_report;
-using ::wifi_usable_channel;
-using ::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
-using ::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
-using ::WLAN_MAC_2_4_BAND;
-using ::WLAN_MAC_5_0_BAND;
-using ::WLAN_MAC_60_0_BAND;
-using ::WLAN_MAC_6_0_BAND;
-
-// APF capabilities supported by the iface.
-struct PacketFilterCapabilities {
-    uint32_t version;
-    uint32_t max_len;
-};
-
-// WARNING: We don't care about the variable sized members of either
-// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
-// to escape the compiler warnings regarding this.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
-// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
-// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
-// into a separate return element to avoid passing pointers around.
-struct LinkLayerRadioStats {
-    wifi_radio_stat stats;
-    std::vector<uint32_t> tx_time_per_levels;
-    std::vector<wifi_channel_stat> channel_stats;
-};
-
-struct WifiPeerInfo {
-    wifi_peer_info peer_info;
-    std::vector<wifi_rate_stat> rate_stats;
-};
-
-struct LinkLayerStats {
-    wifi_iface_stat iface;
-    std::vector<LinkLayerRadioStats> radios;
-    std::vector<WifiPeerInfo> peers;
-};
-#pragma GCC diagnostic pop
-
-// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
-// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
-// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
-// API. Separate that out into a separate return elements to avoid passing
-// pointers around.
-struct WakeReasonStats {
-    WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
-    std::vector<uint32_t> cmd_event_wake_cnt;
-    std::vector<uint32_t> driver_fw_local_wake_cnt;
-};
-
-// NAN response and event callbacks struct.
-struct NanCallbackHandlers {
-    // NotifyResponse invoked to notify the status of the Request.
-    std::function<void(transaction_id, const NanResponseMsg&)>
-        on_notify_response;
-    // Various event callbacks.
-    std::function<void(const NanPublishTerminatedInd&)>
-        on_event_publish_terminated;
-    std::function<void(const NanMatchInd&)> on_event_match;
-    std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
-    std::function<void(const NanSubscribeTerminatedInd&)>
-        on_event_subscribe_terminated;
-    std::function<void(const NanFollowupInd&)> on_event_followup;
-    std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
-    std::function<void(const NanDisabledInd&)> on_event_disabled;
-    std::function<void(const NanTCAInd&)> on_event_tca;
-    std::function<void(const NanBeaconSdfPayloadInd&)>
-        on_event_beacon_sdf_payload;
-    std::function<void(const NanDataPathRequestInd&)>
-        on_event_data_path_request;
-    std::function<void(const NanDataPathConfirmInd&)>
-        on_event_data_path_confirm;
-    std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
-    std::function<void(const NanTransmitFollowupInd&)>
-        on_event_transmit_follow_up;
-    std::function<void(const NanRangeRequestInd&)> on_event_range_request;
-    std::function<void(const NanRangeReportInd&)> on_event_range_report;
-    std::function<void(const NanDataPathScheduleUpdateInd&)>
-        on_event_schedule_update;
-};
-
-// Full scan results contain IE info and are hence passed by reference, to
-// preserve the variable length array member |ie_data|. Callee must not retain
-// the pointer.
-using on_gscan_full_result_callback =
-    std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
-// These scan results don't contain any IE info, so no need to pass by
-// reference.
-using on_gscan_results_callback = std::function<void(
-    wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
-
-// Invoked when the rssi value breaches the thresholds set.
-using on_rssi_threshold_breached_callback =
-    std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
-
-// Callback for RTT range request results.
-// Rtt results contain IE info and are hence passed by reference, to
-// preserve the |LCI| and |LCR| pointers. Callee must not retain
-// the pointer.
-using on_rtt_results_callback = std::function<void(
-    wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
-
-// Callback for ring buffer data.
-using on_ring_buffer_data_callback =
-    std::function<void(const std::string&, const std::vector<uint8_t>&,
-                       const wifi_ring_buffer_status&)>;
-
-// Callback for alerts.
-using on_error_alert_callback =
-    std::function<void(int32_t, const std::vector<uint8_t>&)>;
-
-// Callback for subsystem restart
-using on_subsystem_restart_callback = std::function<void(const std::string&)>;
-
-// Struct for the mac info from the legacy HAL. This is a cleaner version
-// of the |wifi_mac_info| & |wifi_iface_info|.
-typedef struct {
-    std::string name;
-    wifi_channel channel;
-} WifiIfaceInfo;
-
-typedef struct {
-    uint32_t wlan_mac_id;
-    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
-    uint32_t mac_band;
-    /* Represents the connected Wi-Fi interfaces associated with each MAC */
-    std::vector<WifiIfaceInfo> iface_infos;
-} WifiMacInfo;
-
-// Callback for radio mode change
-using on_radio_mode_change_callback =
-    std::function<void(const std::vector<WifiMacInfo>&)>;
-
-// TWT response and event callbacks struct.
-struct TwtCallbackHandlers {
-    // Callback for TWT setup response
-    std::function<void(const TwtSetupResponse&)> on_setup_response;
-    // Callback for TWT teardown completion
-    std::function<void(const TwtTeardownCompletion&)> on_teardown_completion;
-    // Callback for TWT info frame received event
-    std::function<void(const TwtInfoFrameReceived&)> on_info_frame_received;
-    // Callback for TWT notification from the device
-    std::function<void(const TwtDeviceNotify&)> on_device_notify;
-};
-
-/**
- * Class that encapsulates all legacy HAL interactions.
- * This class manages the lifetime of the event loop thread used by legacy HAL.
- *
- * Note: There will only be a single instance of this class created in the Wifi
- * object and will be valid for the lifetime of the process.
- */
-class WifiLegacyHal {
-   public:
-    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-                  const wifi_hal_fn& fn, bool is_primary);
-    virtual ~WifiLegacyHal() = default;
-
-    // Initialize the legacy HAL function table.
-    virtual wifi_error initialize();
-    // Start the legacy HAL and the event looper thread.
-    virtual wifi_error start();
-    // Deinitialize the legacy HAL and wait for the event loop thread to exit
-    // using a predefined timeout.
-    virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
-                            const std::function<void()>& on_complete_callback);
-    virtual wifi_error waitForDriverReady();
-    // Checks if legacy HAL has successfully started
-    bool isStarted();
-    // Wrappers for all the functions in the legacy HAL function table.
-    virtual std::pair<wifi_error, std::string> getDriverVersion(
-        const std::string& iface_name);
-    virtual std::pair<wifi_error, std::string> getFirmwareVersion(
-        const std::string& iface_name);
-    std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
-        const std::string& iface_name);
-    std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
-        const std::string& iface_name);
-    std::pair<wifi_error, uint64_t> getSupportedFeatureSet(
-        const std::string& iface_name);
-    // APF functions.
-    std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
-        const std::string& iface_name);
-    wifi_error setPacketFilter(const std::string& iface_name,
-                               const std::vector<uint8_t>& program);
-    std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
-        const std::string& iface_name);
-    // Gscan functions.
-    std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
-        const std::string& iface_name);
-    // These API's provides a simplified interface over the legacy Gscan API's:
-    // a) All scan events from the legacy HAL API other than the
-    //    |WIFI_SCAN_FAILED| are treated as notification of results.
-    //    This method then retrieves the cached scan results from the legacy
-    //    HAL API and triggers the externally provided
-    //    |on_results_user_callback| on success.
-    // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
-    // results
-    //    triggers the externally provided |on_failure_user_callback|.
-    // c) Full scan result event triggers the externally provided
-    //    |on_full_result_user_callback|.
-    wifi_error startGscan(
-        const std::string& iface_name, wifi_request_id id,
-        const wifi_scan_cmd_params& params,
-        const std::function<void(wifi_request_id)>& on_failure_callback,
-        const on_gscan_results_callback& on_results_callback,
-        const on_gscan_full_result_callback& on_full_result_callback);
-    wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
-    std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
-        const std::string& iface_name, wifi_band band);
-    virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
-    // Link layer stats functions.
-    wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
-    wifi_error disableLinkLayerStats(const std::string& iface_name);
-    std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(
-        const std::string& iface_name);
-    // RSSI monitor functions.
-    wifi_error startRssiMonitoring(const std::string& iface_name,
-                                   wifi_request_id id, int8_t max_rssi,
-                                   int8_t min_rssi,
-                                   const on_rssi_threshold_breached_callback&
-                                       on_threshold_breached_callback);
-    wifi_error stopRssiMonitoring(const std::string& iface_name,
-                                  wifi_request_id id);
-    std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
-        const std::string& iface_name);
-    wifi_error configureRoaming(const std::string& iface_name,
-                                const wifi_roaming_config& config);
-    wifi_error enableFirmwareRoaming(const std::string& iface_name,
-                                     fw_roaming_state_t state);
-    wifi_error configureNdOffload(const std::string& iface_name, bool enable);
-    wifi_error startSendingOffloadedPacket(
-        const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
-        const std::vector<uint8_t>& ip_packet_data,
-        const std::array<uint8_t, 6>& src_address,
-        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
-    wifi_error stopSendingOffloadedPacket(const std::string& iface_name,
-                                          uint32_t cmd_id);
-    virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
-                                             wifi_power_scenario scenario);
-    virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
-    wifi_error setLatencyMode(const std::string& iface_name,
-                              wifi_latency_mode mode);
-    wifi_error setThermalMitigationMode(wifi_thermal_mode mode,
-                                        uint32_t completion_window);
-    wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
-                                              uint32_t access_category);
-    wifi_error resetDscpToAccessCategoryMapping();
-    // Logger/debug functions.
-    std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
-        const std::string& iface_name);
-    wifi_error startPktFateMonitoring(const std::string& iface_name);
-    std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(
-        const std::string& iface_name);
-    std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(
-        const std::string& iface_name);
-    std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(
-        const std::string& iface_name);
-    wifi_error registerRingBufferCallbackHandler(
-        const std::string& iface_name,
-        const on_ring_buffer_data_callback& on_data_callback);
-    wifi_error deregisterRingBufferCallbackHandler(
-        const std::string& iface_name);
-    wifi_error registerSubsystemRestartCallbackHandler(
-        const on_subsystem_restart_callback& on_restart_callback);
-    std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
-    getRingBuffersStatus(const std::string& iface_name);
-    wifi_error startRingBufferLogging(const std::string& iface_name,
-                                      const std::string& ring_name,
-                                      uint32_t verbose_level,
-                                      uint32_t max_interval_sec,
-                                      uint32_t min_data_size);
-    wifi_error getRingBufferData(const std::string& iface_name,
-                                 const std::string& ring_name);
-    wifi_error registerErrorAlertCallbackHandler(
-        const std::string& iface_name,
-        const on_error_alert_callback& on_alert_callback);
-    wifi_error deregisterErrorAlertCallbackHandler(
-        const std::string& iface_name);
-    // Radio mode functions.
-    virtual wifi_error registerRadioModeChangeCallbackHandler(
-        const std::string& iface_name,
-        const on_radio_mode_change_callback& on_user_change_callback);
-    // RTT functions.
-    wifi_error startRttRangeRequest(
-        const std::string& iface_name, wifi_request_id id,
-        const std::vector<wifi_rtt_config>& rtt_configs,
-        const on_rtt_results_callback& on_results_callback);
-    wifi_error cancelRttRangeRequest(
-        const std::string& iface_name, wifi_request_id id,
-        const std::vector<std::array<uint8_t, 6>>& mac_addrs);
-    std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(
-        const std::string& iface_name);
-    std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(
-        const std::string& iface_name);
-    wifi_error enableRttResponder(const std::string& iface_name,
-                                  wifi_request_id id,
-                                  const wifi_channel_info& channel_hint,
-                                  uint32_t max_duration_secs,
-                                  const wifi_rtt_responder& info);
-    wifi_error disableRttResponder(const std::string& iface_name,
-                                   wifi_request_id id);
-    wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
-                         const wifi_lci_information& info);
-    wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
-                         const wifi_lcr_information& info);
-    // NAN functions.
-    virtual wifi_error nanRegisterCallbackHandlers(
-        const std::string& iface_name, const NanCallbackHandlers& callbacks);
-    wifi_error nanEnableRequest(const std::string& iface_name,
-                                transaction_id id, const NanEnableRequest& msg);
-    virtual wifi_error nanDisableRequest(const std::string& iface_name,
-                                         transaction_id id);
-    wifi_error nanPublishRequest(const std::string& iface_name,
-                                 transaction_id id,
-                                 const NanPublishRequest& msg);
-    wifi_error nanPublishCancelRequest(const std::string& iface_name,
-                                       transaction_id id,
-                                       const NanPublishCancelRequest& msg);
-    wifi_error nanSubscribeRequest(const std::string& iface_name,
-                                   transaction_id id,
-                                   const NanSubscribeRequest& msg);
-    wifi_error nanSubscribeCancelRequest(const std::string& iface_name,
-                                         transaction_id id,
-                                         const NanSubscribeCancelRequest& msg);
-    wifi_error nanTransmitFollowupRequest(
-        const std::string& iface_name, transaction_id id,
-        const NanTransmitFollowupRequest& msg);
-    wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
-                               const NanStatsRequest& msg);
-    wifi_error nanConfigRequest(const std::string& iface_name,
-                                transaction_id id, const NanConfigRequest& msg);
-    wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
-                             const NanTCARequest& msg);
-    wifi_error nanBeaconSdfPayloadRequest(
-        const std::string& iface_name, transaction_id id,
-        const NanBeaconSdfPayloadRequest& msg);
-    std::pair<wifi_error, NanVersion> nanGetVersion();
-    wifi_error nanGetCapabilities(const std::string& iface_name,
-                                  transaction_id id);
-    wifi_error nanDataInterfaceCreate(const std::string& iface_name,
-                                      transaction_id id,
-                                      const std::string& data_iface_name);
-    virtual wifi_error nanDataInterfaceDelete(
-        const std::string& iface_name, transaction_id id,
-        const std::string& data_iface_name);
-    wifi_error nanDataRequestInitiator(const std::string& iface_name,
-                                       transaction_id id,
-                                       const NanDataPathInitiatorRequest& msg);
-    wifi_error nanDataIndicationResponse(
-        const std::string& iface_name, transaction_id id,
-        const NanDataPathIndicationResponse& msg);
-    wifi_error nanDataEnd(const std::string& iface_name, transaction_id id,
-                          uint32_t ndpInstanceId);
-    // AP functions.
-    wifi_error setCountryCode(const std::string& iface_name,
-                              std::array<int8_t, 2> code);
-
-    // interface functions.
-    virtual wifi_error createVirtualInterface(const std::string& ifname,
-                                              wifi_interface_type iftype);
-    virtual wifi_error deleteVirtualInterface(const std::string& ifname);
-    wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
-
-    // STA + STA functions
-    virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
-    virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
-
-    // Coex functions.
-    virtual wifi_error setCoexUnsafeChannels(
-        std::vector<wifi_coex_unsafe_channel> unsafe_channels,
-        uint32_t restrictions);
-
-    wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode);
-
-    wifi_error twtRegisterHandler(const std::string& iface_name,
-                                  const TwtCallbackHandlers& handler);
-
-    std::pair<wifi_error, TwtCapabilitySet> twtGetCapability(
-        const std::string& iface_name);
-
-    wifi_error twtSetupRequest(const std::string& iface_name,
-                               const TwtSetupRequest& msg);
-
-    wifi_error twtTearDownRequest(const std::string& iface_name,
-                                  const TwtTeardownRequest& msg);
-
-    wifi_error twtInfoFrameRequest(const std::string& iface_name,
-                                   const TwtInfoFrameRequest& msg);
-
-    std::pair<wifi_error, TwtStats> twtGetStats(const std::string& iface_name,
-                                                uint8_t configId);
-
-    wifi_error twtClearStats(const std::string& iface_name, uint8_t configId);
-
-    wifi_error setDtimConfig(const std::string& iface_name,
-                             uint32_t multiplier);
-
-    // Retrieve the list of usable channels in the requested bands
-    // for the requested modes
-    std::pair<wifi_error, std::vector<wifi_usable_channel>> getUsableChannels(
-        uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask);
-
-    wifi_error triggerSubsystemRestart();
-
-   private:
-    // Retrieve interface handles for all the available interfaces.
-    wifi_error retrieveIfaceHandles();
-    wifi_interface_handle getIfaceHandle(const std::string& iface_name);
-    // Run the legacy HAL event loop thread.
-    void runEventLoop();
-    // Retrieve the cached gscan results to pass the results back to the
-    // external callbacks.
-    std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
-    getGscanCachedResults(const std::string& iface_name);
-    void invalidate();
-    // Handles wifi (error) status of Virtual interface create/delete
-    wifi_error handleVirtualInterfaceCreateOrDeleteStatus(
-        const std::string& ifname, wifi_error status);
-
-    // Global function table of legacy HAL.
-    wifi_hal_fn global_func_table_;
-    // Opaque handle to be used for all global operations.
-    wifi_handle global_handle_;
-    // Map of interface name to handle that is to be used for all interface
-    // specific operations.
-    std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
-    // Flag to indicate if we have initiated the cleanup of legacy HAL.
-    std::atomic<bool> awaiting_event_loop_termination_;
-    std::condition_variable_any stop_wait_cv_;
-    // Flag to indicate if the legacy HAL has been started.
-    bool is_started_;
-    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
-    // flag to indicate if this HAL is for the primary chip. This is used
-    // in order to avoid some hard-coded behavior used with older HALs,
-    // such as bring wlan0 interface up/down on start/stop HAL.
-    // it may be removed once vendor HALs are updated.
-    bool is_primary_;
-};
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.cpp b/wifi/1.5/default/wifi_legacy_hal_factory.cpp
deleted file mode 100644
index fbaa284..0000000
--- a/wifi/1.5/default/wifi_legacy_hal_factory.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <android-base/logging.h>
-#include <dlfcn.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xmlmemory.h>
-
-#include "wifi_legacy_hal_factory.h"
-#include "wifi_legacy_hal_stubs.h"
-
-namespace {
-static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
-static constexpr char kVendorHalsDescExt[] = ".xml";
-static constexpr uint32_t kVendorHalsDescVersion = 1;
-
-bool isDirectory(struct dirent* entryPtr) {
-    bool isDir = false;
-    if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
-        isDir = (entryPtr->d_type == DT_DIR);
-    } else {
-        struct stat entryStat;
-        stat(entryPtr->d_name, &entryStat);
-        isDir = S_ISDIR(entryStat.st_mode);
-    }
-    return isDir;
-}
-
-bool isFileExtension(const char* name, const char* ext) {
-    if (name == NULL) return false;
-    if (ext == NULL) return false;
-
-    size_t extLen = strlen(ext);
-    size_t nameLen = strlen(name);
-
-    if (extLen > nameLen) return false;
-
-    if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
-
-    return true;
-}
-};  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace legacy_hal {
-
-WifiLegacyHalFactory::WifiLegacyHalFactory(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : iface_tool_(iface_tool) {}
-
-std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
-    if (legacy_hals_.empty()) {
-        if (!initVendorHalDescriptorFromLinked())
-            initVendorHalsDescriptorList();
-        for (auto& desc : descs_) {
-            std::shared_ptr<WifiLegacyHal> hal =
-                std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn,
-                                                desc.primary);
-            legacy_hals_.push_back(hal);
-        }
-    }
-
-    return legacy_hals_;
-}
-
-bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
-    wifi_hal_lib_desc desc;
-
-    if (!initLinkedHalFunctionTable(&desc.fn)) return false;
-
-    desc.primary = true;
-    desc.handle = NULL;
-    descs_.push_back(desc);
-    return true;
-}
-
-bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
-    init_wifi_vendor_hal_func_table_t initfn;
-
-    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
-        RTLD_DEFAULT, "init_wifi_vendor_hal_func_table");
-    if (!initfn) {
-        LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
-        return false;
-    }
-
-    if (!initHalFuncTableWithStubs(hal_fn)) {
-        LOG(ERROR) << "Can not initialize the basic function pointer table";
-        return false;
-    }
-
-    if (initfn(hal_fn) != WIFI_SUCCESS) {
-        LOG(ERROR) << "Can not initialize the vendor function pointer table";
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Overall structure of the HAL descriptor XML schema
- *
- * <?xml version="1.0" encoding="UTF-8"?>
- * <WifiVendorHal version="1">
- * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
- * <primary>1</primary>
- * </WifiVendorHal>
- */
-void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
-    xmlDocPtr xml;
-    xmlNodePtr node, cnode;
-    char* version;
-    std::string path;
-    xmlChar* value;
-    wifi_hal_lib_desc desc;
-
-    LOG(INFO) << "processing vendor HALs descriptions in "
-              << kVendorHalsDescPath;
-    DIR* dirPtr = ::opendir(kVendorHalsDescPath);
-    if (dirPtr == NULL) {
-        LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
-        return;
-    }
-    for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
-         entryPtr = ::readdir(dirPtr)) {
-        if (isDirectory(entryPtr)) continue;
-
-        if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
-            continue;  // only process .xml files
-
-        LOG(INFO) << "processing config file: " << entryPtr->d_name;
-
-        std::string fullPath(kVendorHalsDescPath);
-        fullPath.append("/");
-        fullPath.append(entryPtr->d_name);
-        xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
-        if (!xml) {
-            LOG(ERROR) << "failed to parse: " << entryPtr->d_name
-                       << " skipping...";
-            continue;
-        }
-        node = xmlDocGetRootElement(xml);
-        if (!node) {
-            LOG(ERROR) << "empty config file: " << entryPtr->d_name
-                       << " skipping...";
-            goto skip;
-        }
-        if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
-            LOG(ERROR) << "bad config, root element not WifiVendorHal: "
-                       << entryPtr->d_name << " skipping...";
-            goto skip;
-        }
-        version = (char*)xmlGetProp(node, BAD_CAST "version");
-        if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
-            LOG(ERROR) << "conf file: " << entryPtr->d_name
-                       << "must have version: " << kVendorHalsDescVersion
-                       << ", skipping...";
-            goto skip;
-        }
-        cnode = node->children;
-        path.clear();
-        desc.primary = false;
-        while (cnode) {
-            if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
-                value = xmlNodeListGetString(xml, cnode->children, 1);
-                if (value) path = (char*)value;
-                xmlFree(value);
-            } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
-                value = xmlNodeListGetString(xml, cnode->children, 1);
-                desc.primary = !xmlStrcmp(value, BAD_CAST "1");
-                xmlFree(value);
-            }
-            cnode = cnode->next;
-        }
-        if (path.empty()) {
-            LOG(ERROR) << "hal library path not provided in: "
-                       << entryPtr->d_name << ", skipping...";
-            goto skip;
-        }
-        if (loadVendorHalLib(path, desc)) {
-            if (desc.primary)
-                descs_.insert(descs_.begin(), desc);
-            else
-                descs_.push_back(desc);
-        }
-    skip:
-        xmlFreeDoc(xml);
-    }
-    ::closedir(dirPtr);
-}
-
-bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path,
-                                            wifi_hal_lib_desc& desc) {
-    void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
-    init_wifi_vendor_hal_func_table_t initfn;
-    wifi_error res;
-
-    if (!h) {
-        LOG(ERROR) << "failed to open vendor hal library: " << path;
-        return false;
-    }
-    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
-        h, "init_wifi_vendor_hal_func_table");
-    if (!initfn) {
-        LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
-        goto out_err;
-    }
-
-    if (!initHalFuncTableWithStubs(&desc.fn)) {
-        LOG(ERROR) << "Can not initialize the basic function pointer table";
-        goto out_err;
-    }
-    res = initfn(&desc.fn);
-    if (res != WIFI_SUCCESS) {
-        LOG(ERROR) << "failed to initialize the vendor func table in: " << path
-                   << " error: " << res;
-        goto out_err;
-    }
-
-    res = desc.fn.wifi_early_initialize();
-    // vendor HALs which do not implement early_initialize will return
-    // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
-    if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
-        LOG(ERROR) << "early initialization failed in: " << path
-                   << " error: " << res;
-        goto out_err;
-    }
-
-    desc.handle = h;
-    return true;
-out_err:
-    dlclose(h);
-    return false;
-}
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.h b/wifi/1.5/default/wifi_legacy_hal_factory.h
deleted file mode 100644
index e3440fa..0000000
--- a/wifi/1.5/default/wifi_legacy_hal_factory.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_LEGACY_HAL_FACTORY_H_
-#define WIFI_LEGACY_HAL_FACTORY_H_
-
-#include <wifi_system/interface_tool.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-// This is in a separate namespace to prevent typename conflicts between
-// the legacy HAL types and the HIDL interface types.
-namespace legacy_hal {
-/**
- * Class that creates WifiLegacyHal objects for vendor HALs in the system.
- */
-class WifiLegacyHalFactory {
-   public:
-    WifiLegacyHalFactory(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
-    virtual ~WifiLegacyHalFactory() = default;
-
-    std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
-
-   private:
-    typedef struct {
-        wifi_hal_fn fn;
-        bool primary;
-        void* handle;
-    } wifi_hal_lib_desc;
-
-    bool initVendorHalDescriptorFromLinked();
-    void initVendorHalsDescriptorList();
-    bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
-    bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
-
-    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::vector<wifi_hal_lib_desc> descs_;
-    std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
-};
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
deleted file mode 100644
index dd860d6..0000000
--- a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2016 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 "wifi_legacy_hal_stubs.h"
-
-// TODO: Remove these stubs from HalTool in libwifi-system.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace legacy_hal {
-template <typename>
-struct stubFunction;
-
-template <typename R, typename... Args>
-struct stubFunction<R (*)(Args...)> {
-    static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
-};
-template <typename... Args>
-struct stubFunction<void (*)(Args...)> {
-    static constexpr void invoke(Args...) {}
-};
-
-template <typename T>
-void populateStubFor(T* val) {
-    *val = &stubFunction<T>::invoke;
-}
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
-    if (hal_fn == nullptr) {
-        return false;
-    }
-    populateStubFor(&hal_fn->wifi_initialize);
-    populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
-    populateStubFor(&hal_fn->wifi_cleanup);
-    populateStubFor(&hal_fn->wifi_event_loop);
-    populateStubFor(&hal_fn->wifi_get_error_info);
-    populateStubFor(&hal_fn->wifi_get_supported_feature_set);
-    populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
-    populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
-    populateStubFor(&hal_fn->wifi_get_supported_channels);
-    populateStubFor(&hal_fn->wifi_is_epr_supported);
-    populateStubFor(&hal_fn->wifi_get_ifaces);
-    populateStubFor(&hal_fn->wifi_get_iface_name);
-    populateStubFor(&hal_fn->wifi_set_iface_event_handler);
-    populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
-    populateStubFor(&hal_fn->wifi_start_gscan);
-    populateStubFor(&hal_fn->wifi_stop_gscan);
-    populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
-    populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
-    populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
-    populateStubFor(&hal_fn->wifi_set_significant_change_handler);
-    populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
-    populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
-    populateStubFor(&hal_fn->wifi_set_link_stats);
-    populateStubFor(&hal_fn->wifi_get_link_stats);
-    populateStubFor(&hal_fn->wifi_clear_link_stats);
-    populateStubFor(&hal_fn->wifi_get_valid_channels);
-    populateStubFor(&hal_fn->wifi_rtt_range_request);
-    populateStubFor(&hal_fn->wifi_rtt_range_cancel);
-    populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
-    populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
-    populateStubFor(&hal_fn->wifi_enable_responder);
-    populateStubFor(&hal_fn->wifi_disable_responder);
-    populateStubFor(&hal_fn->wifi_set_nodfs_flag);
-    populateStubFor(&hal_fn->wifi_start_logging);
-    populateStubFor(&hal_fn->wifi_set_epno_list);
-    populateStubFor(&hal_fn->wifi_reset_epno_list);
-    populateStubFor(&hal_fn->wifi_set_country_code);
-    populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
-    populateStubFor(&hal_fn->wifi_set_log_handler);
-    populateStubFor(&hal_fn->wifi_reset_log_handler);
-    populateStubFor(&hal_fn->wifi_set_alert_handler);
-    populateStubFor(&hal_fn->wifi_reset_alert_handler);
-    populateStubFor(&hal_fn->wifi_get_firmware_version);
-    populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
-    populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
-    populateStubFor(&hal_fn->wifi_get_ring_data);
-    populateStubFor(&hal_fn->wifi_enable_tdls);
-    populateStubFor(&hal_fn->wifi_disable_tdls);
-    populateStubFor(&hal_fn->wifi_get_tdls_status);
-    populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
-    populateStubFor(&hal_fn->wifi_get_driver_version);
-    populateStubFor(&hal_fn->wifi_set_passpoint_list);
-    populateStubFor(&hal_fn->wifi_reset_passpoint_list);
-    populateStubFor(&hal_fn->wifi_set_lci);
-    populateStubFor(&hal_fn->wifi_set_lcr);
-    populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
-    populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
-    populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
-    populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
-    populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
-    populateStubFor(&hal_fn->wifi_configure_nd_offload);
-    populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
-    populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
-    populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
-    populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
-    populateStubFor(&hal_fn->wifi_nan_enable_request);
-    populateStubFor(&hal_fn->wifi_nan_disable_request);
-    populateStubFor(&hal_fn->wifi_nan_publish_request);
-    populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
-    populateStubFor(&hal_fn->wifi_nan_subscribe_request);
-    populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
-    populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
-    populateStubFor(&hal_fn->wifi_nan_stats_request);
-    populateStubFor(&hal_fn->wifi_nan_config_request);
-    populateStubFor(&hal_fn->wifi_nan_tca_request);
-    populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
-    populateStubFor(&hal_fn->wifi_nan_register_handler);
-    populateStubFor(&hal_fn->wifi_nan_get_version);
-    populateStubFor(&hal_fn->wifi_nan_get_capabilities);
-    populateStubFor(&hal_fn->wifi_nan_data_interface_create);
-    populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
-    populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
-    populateStubFor(&hal_fn->wifi_nan_data_indication_response);
-    populateStubFor(&hal_fn->wifi_nan_data_end);
-    populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
-    populateStubFor(&hal_fn->wifi_set_packet_filter);
-    populateStubFor(&hal_fn->wifi_read_packet_filter);
-    populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
-    populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
-    populateStubFor(&hal_fn->wifi_configure_roaming);
-    populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
-    populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
-    populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
-    populateStubFor(&hal_fn->wifi_set_latency_mode);
-    populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
-    populateStubFor(&hal_fn->wifi_virtual_interface_create);
-    populateStubFor(&hal_fn->wifi_virtual_interface_delete);
-    populateStubFor(&hal_fn->wifi_map_dscp_access_category);
-    populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
-    populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
-    populateStubFor(&hal_fn->wifi_get_supported_iface_name);
-    populateStubFor(&hal_fn->wifi_early_initialize);
-    populateStubFor(&hal_fn->wifi_get_chip_feature_set);
-    populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
-    populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
-    populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels);
-    populateStubFor(&hal_fn->wifi_set_voip_mode);
-    populateStubFor(&hal_fn->wifi_twt_register_handler);
-    populateStubFor(&hal_fn->wifi_twt_get_capability);
-    populateStubFor(&hal_fn->wifi_twt_setup_request);
-    populateStubFor(&hal_fn->wifi_twt_teardown_request);
-    populateStubFor(&hal_fn->wifi_twt_info_frame_request);
-    populateStubFor(&hal_fn->wifi_twt_get_stats);
-    populateStubFor(&hal_fn->wifi_twt_clear_stats);
-    populateStubFor(&hal_fn->wifi_set_dtim_config);
-    populateStubFor(&hal_fn->wifi_get_usable_channels);
-    populateStubFor(&hal_fn->wifi_trigger_subsystem_restart);
-    return true;
-}
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.h b/wifi/1.5/default/wifi_legacy_hal_stubs.h
deleted file mode 100644
index 480389b..0000000
--- a/wifi/1.5/default/wifi_legacy_hal_stubs.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
-
-#include <hardware_legacy/wifi_hal.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace legacy_hal {
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.5/default/wifi_mode_controller.cpp b/wifi/1.5/default/wifi_mode_controller.cpp
deleted file mode 100644
index b1db8b3..0000000
--- a/wifi/1.5/default/wifi_mode_controller.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#include "wifi_mode_controller.h"
-
-using android::hardware::wifi::V1_0::IfaceType;
-using android::wifi_hal::DriverTool;
-
-namespace {
-int convertIfaceTypeToFirmwareMode(IfaceType type) {
-    int mode;
-    switch (type) {
-        case IfaceType::AP:
-            mode = DriverTool::kFirmwareModeAp;
-            break;
-        case IfaceType::P2P:
-            mode = DriverTool::kFirmwareModeP2p;
-            break;
-        case IfaceType::NAN:
-            // NAN is exposed in STA mode currently.
-            mode = DriverTool::kFirmwareModeSta;
-            break;
-        case IfaceType::STA:
-            mode = DriverTool::kFirmwareModeSta;
-            break;
-    }
-    return mode;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace mode_controller {
-
-WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
-
-bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
-    return driver_tool_->IsFirmwareModeChangeNeeded(
-        convertIfaceTypeToFirmwareMode(type));
-}
-
-bool WifiModeController::initialize() {
-    if (!driver_tool_->LoadDriver()) {
-        LOG(ERROR) << "Failed to load WiFi driver";
-        return false;
-    }
-    return true;
-}
-
-bool WifiModeController::changeFirmwareMode(IfaceType type) {
-    if (!driver_tool_->ChangeFirmwareMode(
-            convertIfaceTypeToFirmwareMode(type))) {
-        LOG(ERROR) << "Failed to change firmware mode";
-        return false;
-    }
-    return true;
-}
-
-bool WifiModeController::deinitialize() {
-    if (!driver_tool_->UnloadDriver()) {
-        LOG(ERROR) << "Failed to unload WiFi driver";
-        return false;
-    }
-    return true;
-}
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_mode_controller.h b/wifi/1.5/default/wifi_mode_controller.h
deleted file mode 100644
index 2eeca78..0000000
--- a/wifi/1.5/default/wifi_mode_controller.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_MODE_CONTROLLER_H_
-#define WIFI_MODE_CONTROLLER_H_
-
-#include <wifi_hal/driver_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-namespace mode_controller {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * Class that encapsulates all firmware mode configuration.
- * This class will perform the necessary firmware reloads to put the chip in the
- * required state (essentially a wrapper over DriverTool).
- */
-class WifiModeController {
-   public:
-    WifiModeController();
-    virtual ~WifiModeController() = default;
-
-    // Checks if a firmware mode change is necessary to support the specified
-    // iface type operations.
-    virtual bool isFirmwareModeChangeNeeded(IfaceType type);
-    virtual bool initialize();
-    // Change the firmware mode to support the specified iface type operations.
-    virtual bool changeFirmwareMode(IfaceType type);
-    // Unload the driver. This should be invoked whenever |IWifi.stop()| is
-    // invoked.
-    virtual bool deinitialize();
-
-   private:
-    std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
-};
-
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.5/default/wifi_nan_iface.cpp b/wifi/1.5/default/wifi_nan_iface.cpp
deleted file mode 100644
index 0cc6cd5..0000000
--- a/wifi/1.5/default/wifi_nan_iface.cpp
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_nan_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiNanIface::WifiNanIface(
-    const std::string& ifname, bool is_dedicated_iface,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
-    : ifname_(ifname),
-      is_dedicated_iface_(is_dedicated_iface),
-      legacy_hal_(legacy_hal),
-      iface_util_(iface_util),
-      is_valid_(true) {
-    if (is_dedicated_iface_) {
-        // If using a dedicated iface, set the iface up first.
-        if (!iface_util_.lock()->setUpState(ifname_, true)) {
-            // Fatal failure, invalidate the iface object.
-            invalidate();
-            return;
-        }
-    }
-    // Register all the callbacks here. these should be valid for the lifetime
-    // of the object. Whenever the mode changes legacy HAL will remove
-    // all of these callbacks.
-    legacy_hal::NanCallbackHandlers callback_handlers;
-    android::wp<WifiNanIface> weak_ptr_this(this);
-
-    // Callback for response.
-    callback_handlers
-        .on_notify_response = [weak_ptr_this](
-                                  legacy_hal::transaction_id id,
-                                  const legacy_hal::NanResponseMsg& msg) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        WifiNanStatus wifiNanStatus;
-        if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(
-                msg, &wifiNanStatus)) {
-            LOG(ERROR) << "Failed to convert nan response header";
-            return;
-        }
-
-        switch (msg.response_type) {
-            case legacy_hal::NAN_RESPONSE_ENABLED: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyEnableResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_DISABLED: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyDisableResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_PUBLISH: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyStartPublishResponse(
-                                 id, wifiNanStatus,
-                                 msg.body.publish_response.publish_id)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyStopPublishResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyTransmitFollowupResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyStartSubscribeResponse(
-                                 id, wifiNanStatus,
-                                 msg.body.subscribe_response.subscribe_id)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyStopSubscribeResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_CONFIG: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyConfigResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_GET_CAPABILITIES: {
-                NanCapabilities hidl_struct;
-                if (!hidl_struct_util::
-                        convertLegacyNanCapabilitiesResponseToHidl(
-                            msg.body.nan_capabilities, &hidl_struct)) {
-                    LOG(ERROR) << "Failed to convert nan capabilities response";
-                    return;
-                }
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks_1_5()) {
-                    if (!callback
-                             ->notifyCapabilitiesResponse_1_5(id, wifiNanStatus,
-                                                              hidl_struct)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_INTERFACE_CREATE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyCreateDataInterfaceResponse(id,
-                                                                 wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_INTERFACE_DELETE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyDeleteDataInterfaceResponse(id,
-                                                                 wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyInitiateDataPathResponse(
-                                 id, wifiNanStatus,
-                                 msg.body.data_request_response.ndp_instance_id)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyRespondToDataPathIndicationResponse(
-                                 id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_END: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyTerminateDataPathResponse(id,
-                                                               wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
-            /* fall through */
-            case legacy_hal::NAN_RESPONSE_TCA:
-            /* fall through */
-            case legacy_hal::NAN_RESPONSE_STATS:
-            /* fall through */
-            case legacy_hal::NAN_RESPONSE_ERROR:
-            /* fall through */
-            default:
-                LOG(ERROR) << "Unknown or unhandled response type: "
-                           << msg.response_type;
-                return;
-        }
-    };
-
-    callback_handlers.on_event_disc_eng_event =
-        [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanClusterEventInd hidl_struct;
-            // event types defined identically - hence can be cast
-            hidl_struct.eventType = (NanClusterEventType)msg.event_type;
-            hidl_struct.addr = msg.data.mac_addr.addr;
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventClusterEvent(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_disabled =
-        [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventDisabled(status).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_publish_terminated =
-        [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventPublishTerminated(msg.publish_id, status)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_subscribe_terminated =
-        [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback
-                         ->eventSubscribeTerminated(msg.subscribe_id, status)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_match =
-        [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanMatchInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventMatch(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_match_expired =
-        [weak_ptr_this](const legacy_hal::NanMatchExpiredInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback
-                         ->eventMatchExpired(msg.publish_subscribe_id,
-                                             msg.requestor_instance_id)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_followup =
-        [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanFollowupReceivedInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_transmit_follow_up =
-        [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_data_path_request =
-        [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanDataPathRequestInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_data_path_confirm =
-        [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            V1_2::NanDataPathConfirmInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback :
-                 shared_ptr_this->getEventCallbacks_1_2()) {
-                if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_data_path_end =
-        [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                for (int i = 0; i < msg.num_ndp_instances; ++i) {
-                    if (!callback
-                             ->eventDataPathTerminated(msg.ndp_instance_id[i])
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-            }
-        };
-
-    callback_handlers.on_event_beacon_sdf_payload =
-        [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
-            LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
-        };
-
-    callback_handlers.on_event_range_request =
-        [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
-            LOG(ERROR) << "on_event_range_request - should not be called";
-        };
-
-    callback_handlers.on_event_range_report =
-        [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
-            LOG(ERROR) << "on_event_range_report - should not be called";
-        };
-
-    callback_handlers
-        .on_event_schedule_update = [weak_ptr_this](
-                                        const legacy_hal::
-                                            NanDataPathScheduleUpdateInd& msg) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        V1_2::NanDataPathScheduleUpdateInd hidl_struct;
-        if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
-                msg, &hidl_struct)) {
-            LOG(ERROR) << "Failed to convert nan capabilities response";
-            return;
-        }
-
-        for (const auto& callback : shared_ptr_this->getEventCallbacks_1_2()) {
-            if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
-                LOG(ERROR) << "Failed to invoke the callback";
-            }
-        }
-    };
-
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
-                                                        callback_handlers);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
-        invalidate();
-    }
-
-    // Register for iface state toggle events.
-    iface_util::IfaceEventHandlers event_handlers = {};
-    event_handlers.on_state_toggle_off_on =
-        [weak_ptr_this](const std::string& /* iface_name */) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            // Tell framework that NAN has been disabled.
-            WifiNanStatus status = {
-                NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventDisabled(status).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-    iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
-}
-
-void WifiNanIface::invalidate() {
-    if (!isValid()) {
-        return;
-    }
-    // send commands to HAL to actually disable and destroy interfaces
-    legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
-    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
-    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
-    iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
-    legacy_hal_.reset();
-    event_cb_handler_.invalidate();
-    event_cb_handler_1_2_.invalidate();
-    event_cb_handler_1_5_.invalidate();
-    is_valid_ = false;
-    if (is_dedicated_iface_) {
-        // If using a dedicated iface, set the iface down.
-        iface_util_.lock()->setUpState(ifname_, false);
-    }
-}
-
-bool WifiNanIface::isValid() { return is_valid_; }
-
-std::string WifiNanIface::getName() { return ifname_; }
-
-std::set<sp<V1_0::IWifiNanIfaceEventCallback>>
-WifiNanIface::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-std::set<sp<V1_2::IWifiNanIfaceEventCallback>>
-WifiNanIface::getEventCallbacks_1_2() {
-    return event_cb_handler_1_2_.getCallbacks();
-}
-
-std::set<sp<IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_5() {
-    return event_cb_handler_1_5_.getCallbacks();
-}
-
-Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::registerEventCallback(
-    const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallbackInternal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::getCapabilitiesRequest(
-    uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getCapabilitiesRequestInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
-                                         const V1_0::NanEnableRequest& msg,
-                                         enableRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequestInternal, hidl_status_cb,
-                           cmd_id, msg);
-}
-
-Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
-                                         const V1_0::NanConfigRequest& msg,
-                                         configRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequestInternal, hidl_status_cb,
-                           cmd_id, msg);
-}
-
-Return<void> WifiNanIface::disableRequest(uint16_t cmd_id,
-                                          disableRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::disableRequestInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::startPublishRequest(
-    uint16_t cmd_id, const NanPublishRequest& msg,
-    startPublishRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::startPublishRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::stopPublishRequest(
-    uint16_t cmd_id, uint8_t sessionId, stopPublishRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::stopPublishRequestInternal,
-                           hidl_status_cb, cmd_id, sessionId);
-}
-
-Return<void> WifiNanIface::startSubscribeRequest(
-    uint16_t cmd_id, const NanSubscribeRequest& msg,
-    startSubscribeRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::startSubscribeRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::stopSubscribeRequest(
-    uint16_t cmd_id, uint8_t sessionId,
-    stopSubscribeRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::stopSubscribeRequestInternal,
-                           hidl_status_cb, cmd_id, sessionId);
-}
-
-Return<void> WifiNanIface::transmitFollowupRequest(
-    uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
-    transmitFollowupRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::transmitFollowupRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::createDataInterfaceRequest(
-    uint16_t cmd_id, const hidl_string& iface_name,
-    createDataInterfaceRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::createDataInterfaceRequestInternal,
-                           hidl_status_cb, cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::deleteDataInterfaceRequest(
-    uint16_t cmd_id, const hidl_string& iface_name,
-    deleteDataInterfaceRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::deleteDataInterfaceRequestInternal,
-                           hidl_status_cb, cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::initiateDataPathRequest(
-    uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
-    initiateDataPathRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::initiateDataPathRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::respondToDataPathIndicationRequest(
-    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
-    respondToDataPathIndicationRequest_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiNanIface::respondToDataPathIndicationRequestInternal,
-        hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::terminateDataPathRequest(
-    uint16_t cmd_id, uint32_t ndpInstanceId,
-    terminateDataPathRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::terminateDataPathRequestInternal,
-                           hidl_status_cb, cmd_id, ndpInstanceId);
-}
-
-Return<void> WifiNanIface::registerEventCallback_1_2(
-    const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
-    registerEventCallback_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallback_1_2Internal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::enableRequest_1_2(
-    uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2,
-    enableRequest_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_2Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_2(
-    uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2,
-    configRequest_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_2Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::enableRequest_1_4(
-    uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2,
-    enableRequest_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_4Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_4(
-    uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2,
-    configRequest_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_4Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::registerEventCallback_1_5(
-    const sp<IWifiNanIfaceEventCallback>& callback,
-    registerEventCallback_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallback_1_5Internal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::enableRequest_1_5(
-    uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-    const NanConfigRequestSupplemental& msg2,
-    enableRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_5Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_5(
-    uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-    const NanConfigRequestSupplemental& msg2,
-    configRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_5Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::getCapabilitiesRequest_1_5(
-    uint16_t cmd_id, getCapabilitiesRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getCapabilitiesRequest_1_5Internal,
-                           hidl_status_cb, cmd_id);
-}
-
-std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
-}
-
-WifiStatus WifiNanIface::registerEventCallbackInternal(
-    const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
-    if (!event_cb_handler_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t /* cmd_id */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::enableRequestInternal(
-    uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequestInternal(
-    uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startPublishRequestInternal(
-    uint16_t cmd_id, const NanPublishRequest& msg) {
-    legacy_hal::NanPublishRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
-                                                                &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id,
-                                                    uint8_t sessionId) {
-    legacy_hal::NanPublishCancelRequest legacy_msg;
-    legacy_msg.publish_id = sessionId;
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id,
-                                                    legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startSubscribeRequestInternal(
-    uint16_t cmd_id, const NanSubscribeRequest& msg) {
-    legacy_hal::NanSubscribeRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id,
-                                                      uint8_t sessionId) {
-    legacy_hal::NanSubscribeCancelRequest legacy_msg;
-    legacy_msg.subscribe_id = sessionId;
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id,
-                                                      legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::transmitFollowupRequestInternal(
-    uint16_t cmd_id, const NanTransmitFollowupRequest& msg) {
-    legacy_hal::NanTransmitFollowupRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id,
-                                                       legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::createDataInterfaceRequestInternal(
-    uint16_t cmd_id, const std::string& iface_name) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(
-    uint16_t cmd_id, const std::string& iface_name) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::initiateDataPathRequestInternal(
-    uint16_t cmd_id, const NanInitiateDataPathRequest& msg) {
-    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id,
-                                                    legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
-    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
-    legacy_hal::NanDataPathIndicationResponse legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id,
-                                                      legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::terminateDataPathRequestInternal(
-    uint16_t cmd_id, uint32_t ndpInstanceId) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
-    const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
-    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
-    if (!event_cb_handler_.addCallback(callback_1_0)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    if (!event_cb_handler_1_2_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_2Internal(
-    uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */,
-    const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequest_1_2Internal(
-    uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg1 */,
-    const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_4Internal(
-    uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
-    const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequest_1_4Internal(
-    uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
-    const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::registerEventCallback_1_5Internal(
-    const sp<IWifiNanIfaceEventCallback>& callback) {
-    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
-    if (!event_cb_handler_.addCallback(callback_1_0)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
-    if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    if (!event_cb_handler_1_5_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::getCapabilitiesRequest_1_5Internal(uint16_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_5Internal(
-    uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-    const NanConfigRequestSupplemental& msg2) {
-    legacy_hal::NanEnableRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanEnableRequest_1_5ToLegacy(
-            msg1, msg2, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::configRequest_1_5Internal(
-    uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-    const NanConfigRequestSupplemental& msg2) {
-    legacy_hal::NanConfigRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanConfigRequest_1_5ToLegacy(
-            msg1, msg2, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_nan_iface.h b/wifi/1.5/default/wifi_nan_iface.h
deleted file mode 100644
index fb9c047..0000000
--- a/wifi/1.5/default/wifi_nan_iface.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_NAN_IFACE_H_
-#define WIFI_NAN_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.5/IWifiNanIface.h>
-#include <android/hardware/wifi/1.5/IWifiNanIfaceEventCallback.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-using namespace android::hardware::wifi::V1_2;
-
-/**
- * HIDL interface object used to control a NAN Iface instance.
- */
-class WifiNanIface : public V1_5::IWifiNanIface {
-   public:
-    WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
-                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(
-        const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilitiesRequest(
-        uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
-    Return<void> enableRequest(uint16_t cmd_id,
-                               const V1_0::NanEnableRequest& msg,
-                               enableRequest_cb hidl_status_cb) override;
-    Return<void> configRequest(uint16_t cmd_id,
-                               const V1_0::NanConfigRequest& msg,
-                               configRequest_cb hidl_status_cb) override;
-    Return<void> disableRequest(uint16_t cmd_id,
-                                disableRequest_cb hidl_status_cb) override;
-    Return<void> startPublishRequest(
-        uint16_t cmd_id, const NanPublishRequest& msg,
-        startPublishRequest_cb hidl_status_cb) override;
-    Return<void> stopPublishRequest(
-        uint16_t cmd_id, uint8_t sessionId,
-        stopPublishRequest_cb hidl_status_cb) override;
-    Return<void> startSubscribeRequest(
-        uint16_t cmd_id, const NanSubscribeRequest& msg,
-        startSubscribeRequest_cb hidl_status_cb) override;
-    Return<void> stopSubscribeRequest(
-        uint16_t cmd_id, uint8_t sessionId,
-        stopSubscribeRequest_cb hidl_status_cb) override;
-    Return<void> transmitFollowupRequest(
-        uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
-        transmitFollowupRequest_cb hidl_status_cb) override;
-    Return<void> createDataInterfaceRequest(
-        uint16_t cmd_id, const hidl_string& iface_name,
-        createDataInterfaceRequest_cb hidl_status_cb) override;
-    Return<void> deleteDataInterfaceRequest(
-        uint16_t cmd_id, const hidl_string& iface_name,
-        deleteDataInterfaceRequest_cb hidl_status_cb) override;
-    Return<void> initiateDataPathRequest(
-        uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
-        initiateDataPathRequest_cb hidl_status_cb) override;
-    Return<void> respondToDataPathIndicationRequest(
-        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
-        respondToDataPathIndicationRequest_cb hidl_status_cb) override;
-    Return<void> terminateDataPathRequest(
-        uint16_t cmd_id, uint32_t ndpInstanceId,
-        terminateDataPathRequest_cb hidl_status_cb) override;
-
-    Return<void> registerEventCallback_1_2(
-        const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_1_2_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_2(
-        uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2,
-        enableRequest_1_2_cb hidl_status_cb) override;
-    Return<void> configRequest_1_2(
-        uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2,
-        configRequest_1_2_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_4(
-        uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2,
-        enableRequest_1_4_cb hidl_status_cb) override;
-    Return<void> configRequest_1_4(
-        uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2,
-        configRequest_1_4_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_5(
-        const sp<IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_1_5_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_5(
-        uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-        const NanConfigRequestSupplemental& msg2,
-        enableRequest_1_4_cb hidl_status_cb) override;
-    Return<void> configRequest_1_5(
-        uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-        const NanConfigRequestSupplemental& msg2,
-        configRequest_1_4_cb hidl_status_cb) override;
-    Return<void> getCapabilitiesRequest_1_5(
-        uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus registerEventCallbackInternal(
-        const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
-    WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
-    WifiStatus enableRequestInternal(uint16_t cmd_id,
-                                     const V1_0::NanEnableRequest& msg);
-    WifiStatus configRequestInternal(uint16_t cmd_id,
-                                     const V1_0::NanConfigRequest& msg);
-    WifiStatus disableRequestInternal(uint16_t cmd_id);
-    WifiStatus startPublishRequestInternal(uint16_t cmd_id,
-                                           const NanPublishRequest& msg);
-    WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-    WifiStatus startSubscribeRequestInternal(uint16_t cmd_id,
-                                             const NanSubscribeRequest& msg);
-    WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-    WifiStatus transmitFollowupRequestInternal(
-        uint16_t cmd_id, const NanTransmitFollowupRequest& msg);
-    WifiStatus createDataInterfaceRequestInternal(
-        uint16_t cmd_id, const std::string& iface_name);
-    WifiStatus deleteDataInterfaceRequestInternal(
-        uint16_t cmd_id, const std::string& iface_name);
-    WifiStatus initiateDataPathRequestInternal(
-        uint16_t cmd_id, const NanInitiateDataPathRequest& msg);
-    WifiStatus respondToDataPathIndicationRequestInternal(
-        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
-    WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
-                                                uint32_t ndpInstanceId);
-
-    WifiStatus registerEventCallback_1_2Internal(
-        const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
-    WifiStatus enableRequest_1_2Internal(
-        uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_2Internal(
-        uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
-        const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus enableRequest_1_4Internal(
-        uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_4Internal(
-        uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
-        const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus registerEventCallback_1_5Internal(
-        const sp<IWifiNanIfaceEventCallback>& callback);
-    WifiStatus enableRequest_1_5Internal(
-        uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-        const NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_5Internal(
-        uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
-        const NanConfigRequestSupplemental& msg2);
-    WifiStatus getCapabilitiesRequest_1_5Internal(uint16_t cmd_id);
-
-    // all 1_0 and descendant callbacks
-    std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
-    // all 1_2 and descendant callbacks
-    std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
-    // all 1_5 and descendant callbacks
-    std::set<sp<IWifiNanIfaceEventCallback>> getEventCallbacks_1_5();
-
-    std::string ifname_;
-    bool is_dedicated_iface_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    bool is_valid_;
-    hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback>
-        event_cb_handler_;
-    hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback>
-        event_cb_handler_1_2_;
-    hidl_callback_util::HidlCallbackHandler<IWifiNanIfaceEventCallback>
-        event_cb_handler_1_5_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.5/default/wifi_p2p_iface.cpp b/wifi/1.5/default/wifi_p2p_iface.cpp
deleted file mode 100644
index b8893da..0000000
--- a/wifi/1.5/default/wifi_p2p_iface.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiP2pIface::WifiP2pIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
-
-void WifiP2pIface::invalidate() {
-    legacy_hal_.reset();
-    is_valid_ = false;
-}
-
-bool WifiP2pIface::isValid() { return is_valid_; }
-
-std::string WifiP2pIface::getName() { return ifname_; }
-
-Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiP2pIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiP2pIface::getTypeInternal, hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
-}
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_p2p_iface.h b/wifi/1.5/default/wifi_p2p_iface.h
deleted file mode 100644
index c1adc50..0000000
--- a/wifi/1.5/default/wifi_p2p_iface.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_P2P_IFACE_H_
-#define WIFI_P2P_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a P2P Iface instance.
- */
-class WifiP2pIface : public V1_0::IWifiP2pIface {
-   public:
-    WifiP2pIface(const std::string& ifname,
-                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.5/default/wifi_rtt_controller.cpp b/wifi/1.5/default/wifi_rtt_controller.cpp
deleted file mode 100644
index a0f9969..0000000
--- a/wifi/1.5/default/wifi_rtt_controller.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiRttController::WifiRttController(
-    const std::string& iface_name, const sp<IWifiIface>& bound_iface,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(iface_name),
-      bound_iface_(bound_iface),
-      legacy_hal_(legacy_hal),
-      is_valid_(true) {}
-
-void WifiRttController::invalidate() {
-    legacy_hal_.reset();
-    event_callbacks_.clear();
-    is_valid_ = false;
-}
-
-bool WifiRttController::isValid() { return is_valid_; }
-
-std::vector<sp<V1_4::IWifiRttControllerEventCallback>>
-WifiRttController::getEventCallbacks() {
-    return event_callbacks_;
-}
-
-std::string WifiRttController::getIfaceName() { return ifname_; }
-
-Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::registerEventCallback(
-    const sp<V1_0::IWifiRttControllerEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this,
-                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::registerEventCallbackInternal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiRttController::rangeRequest(
-    uint32_t cmd_id, const hidl_vec<V1_0::RttConfig>& rtt_configs,
-    rangeRequest_cb hidl_status_cb) {
-    return validateAndCall(this,
-                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::rangeRequestInternal,
-                           hidl_status_cb, cmd_id, rtt_configs);
-}
-
-Return<void> WifiRttController::rangeCancel(
-    uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-    rangeCancel_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
-}
-
-Return<void> WifiRttController::getCapabilities(
-    getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::setLci(uint32_t cmd_id,
-                                       const RttLciInformation& lci,
-                                       setLci_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
-}
-
-Return<void> WifiRttController::setLcr(uint32_t cmd_id,
-                                       const RttLcrInformation& lcr,
-                                       setLcr_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
-}
-
-Return<void> WifiRttController::getResponderInfo(
-    getResponderInfo_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getResponderInfoInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder(
-    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const V1_0::RttResponder& info,
-    enableResponder_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
-        channel_hint, max_duration_seconds, info);
-}
-
-Return<void> WifiRttController::disableResponder(
-    uint32_t cmd_id, disableResponder_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiRttController::registerEventCallback_1_4(
-    const sp<V1_4::IWifiRttControllerEventCallback>& callback,
-    registerEventCallback_1_4_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb,
-        callback);
-}
-
-Return<void> WifiRttController::rangeRequest_1_4(
-    uint32_t cmd_id, const hidl_vec<V1_4::RttConfig>& rtt_configs,
-    rangeRequest_1_4_cb hidl_status_cb) {
-    return validateAndCall(this,
-                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::rangeRequestInternal_1_4,
-                           hidl_status_cb, cmd_id, rtt_configs);
-}
-
-Return<void> WifiRttController::getCapabilities_1_4(
-    getCapabilities_1_4_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb);
-}
-
-Return<void> WifiRttController::getResponderInfo_1_4(
-    getResponderInfo_1_4_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder_1_4(
-    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const V1_4::RttResponder& info,
-    enableResponder_1_4_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id,
-        channel_hint, max_duration_seconds, info);
-}
-
-std::pair<WifiStatus, sp<IWifiIface>>
-WifiRttController::getBoundIfaceInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal(
-    const sp<V1_0::IWifiRttControllerEventCallback>& /* callback */) {
-    // Deprecated support for this api
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal(
-    uint32_t /* cmd_id */,
-    const std::vector<V1_0::RttConfig>& /* rtt_configs */) {
-    // Deprecated support for this api
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiRttController::rangeCancelInternal(
-    uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
-    std::vector<std::array<uint8_t, 6>> legacy_addrs;
-    for (const auto& addr : addrs) {
-        legacy_addrs.push_back(addr);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id,
-                                                  legacy_addrs);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_0::RttCapabilities>
-WifiRttController::getCapabilitiesInternal() {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
-                                             const RttLciInformation& lci) {
-    legacy_hal::wifi_lci_information legacy_lci;
-    if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
-                                                                &legacy_lci)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
-                                             const RttLcrInformation& lcr) {
-    legacy_hal::wifi_lcr_information legacy_lcr;
-    if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
-                                                                &legacy_lcr)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_0::RttResponder>
-WifiRttController::getResponderInfoInternal() {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-WifiStatus WifiRttController::enableResponderInternal(
-    uint32_t /* cmd_id */, const WifiChannelInfo& /* channel_hint */,
-    uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
-}
-
-WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
-    const sp<V1_4::IWifiRttControllerEventCallback>& callback) {
-    // TODO(b/31632518): remove the callback when the client is destroyed
-    event_callbacks_.emplace_back(callback);
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal_1_4(
-    uint32_t cmd_id, const std::vector<V1_4::RttConfig>& rtt_configs) {
-    std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
-    if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
-            rtt_configs, &legacy_configs)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    android::wp<WifiRttController> weak_ptr_this(this);
-    const auto& on_results_callback =
-        [weak_ptr_this](
-            legacy_hal::wifi_request_id id,
-            const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            std::vector<V1_4::RttResult> hidl_results;
-            if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
-                    results, &hidl_results)) {
-                LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                callback->onResults_1_4(id, hidl_results);
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startRttRangeRequest(
-            ifname_, cmd_id, legacy_configs, on_results_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_4::RttCapabilities>
-WifiRttController::getCapabilitiesInternal_1_4() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_rtt_capabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getRttCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    V1_4::RttCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
-                                                              &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, V1_4::RttResponder>
-WifiRttController::getResponderInfoInternal_1_4() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_rtt_responder legacy_responder;
-    std::tie(legacy_status, legacy_responder) =
-        legacy_hal_.lock()->getRttResponderInfo(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    V1_4::RttResponder hidl_responder;
-    if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
-                                                           &hidl_responder)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
-}
-
-WifiStatus WifiRttController::enableResponderInternal_1_4(
-    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const V1_4::RttResponder& info) {
-    legacy_hal::wifi_channel_info legacy_channel_info;
-    if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
-            channel_hint, &legacy_channel_info)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_rtt_responder legacy_responder;
-    if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
-                                                           &legacy_responder)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->enableRttResponder(
-            ifname_, cmd_id, legacy_channel_info, max_duration_seconds,
-            legacy_responder);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_rtt_controller.h b/wifi/1.5/default/wifi_rtt_controller.h
deleted file mode 100644
index 9ac3e06..0000000
--- a/wifi/1.5/default/wifi_rtt_controller.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_RTT_CONTROLLER_H_
-#define WIFI_RTT_CONTROLLER_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiIface.h>
-#include <android/hardware/wifi/1.4/IWifiRttController.h>
-#include <android/hardware/wifi/1.4/IWifiRttControllerEventCallback.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-/**
- * HIDL interface object used to control all RTT operations.
- */
-class WifiRttController : public V1_4::IWifiRttController {
-   public:
-    WifiRttController(
-        const std::string& iface_name, const sp<IWifiIface>& bound_iface,
-        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::vector<sp<V1_4::IWifiRttControllerEventCallback>> getEventCallbacks();
-    std::string getIfaceName();
-
-    // HIDL methods exposed.
-    Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(
-        const sp<V1_0::IWifiRttControllerEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> rangeRequest(uint32_t cmd_id,
-                              const hidl_vec<V1_0::RttConfig>& rtt_configs,
-                              rangeRequest_cb hidl_status_cb) override;
-    Return<void> rangeCancel(uint32_t cmd_id,
-                             const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-                             rangeCancel_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
-                        setLci_cb hidl_status_cb) override;
-    Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
-                        setLcr_cb hidl_status_cb) override;
-    Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
-    Return<void> enableResponder(uint32_t cmd_id,
-                                 const WifiChannelInfo& channel_hint,
-                                 uint32_t max_duration_seconds,
-                                 const V1_0::RttResponder& info,
-                                 enableResponder_cb hidl_status_cb) override;
-    Return<void> disableResponder(uint32_t cmd_id,
-                                  disableResponder_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_4(
-        const sp<V1_4::IWifiRttControllerEventCallback>& callback,
-        registerEventCallback_1_4_cb hidl_status_cb) override;
-    Return<void> rangeRequest_1_4(uint32_t cmd_id,
-                                  const hidl_vec<V1_4::RttConfig>& rtt_configs,
-                                  rangeRequest_1_4_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_4(
-        getCapabilities_1_4_cb hidl_status_cb) override;
-    Return<void> getResponderInfo_1_4(
-        getResponderInfo_1_4_cb hidl_status_cb) override;
-    Return<void> enableResponder_1_4(
-        uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-        uint32_t max_duration_seconds, const V1_4::RttResponder& info,
-        enableResponder_1_4_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
-    WifiStatus registerEventCallbackInternal(
-        const sp<V1_0::IWifiRttControllerEventCallback>& callback);
-    WifiStatus rangeRequestInternal(
-        uint32_t cmd_id, const std::vector<V1_0::RttConfig>& rtt_configs);
-    WifiStatus rangeCancelInternal(
-        uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
-    std::pair<WifiStatus, V1_0::RttCapabilities> getCapabilitiesInternal();
-    WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
-    WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
-    std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
-    WifiStatus enableResponderInternal(uint32_t cmd_id,
-                                       const WifiChannelInfo& channel_hint,
-                                       uint32_t max_duration_seconds,
-                                       const V1_0::RttResponder& info);
-    WifiStatus disableResponderInternal(uint32_t cmd_id);
-    WifiStatus registerEventCallbackInternal_1_4(
-        const sp<V1_4::IWifiRttControllerEventCallback>& callback);
-    WifiStatus rangeRequestInternal_1_4(
-        uint32_t cmd_id, const std::vector<V1_4::RttConfig>& rtt_configs);
-    std::pair<WifiStatus, V1_4::RttCapabilities> getCapabilitiesInternal_1_4();
-    std::pair<WifiStatus, V1_4::RttResponder> getResponderInfoInternal_1_4();
-    WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
-                                           const WifiChannelInfo& channel_hint,
-                                           uint32_t max_duration_seconds,
-                                           const V1_4::RttResponder& info);
-
-    std::string ifname_;
-    sp<IWifiIface> bound_iface_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::vector<sp<V1_4::IWifiRttControllerEventCallback>> event_callbacks_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiRttController);
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.5/default/wifi_sta_iface.cpp b/wifi/1.5/default/wifi_sta_iface.cpp
deleted file mode 100644
index 92c9fe4..0000000
--- a/wifi/1.5/default/wifi_sta_iface.cpp
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * Copyright (C) 2016 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 <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_sta_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiStaIface::WifiStaIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
-    : ifname_(ifname),
-      legacy_hal_(legacy_hal),
-      iface_util_(iface_util),
-      is_valid_(true) {
-    // Turn on DFS channel usage for STA iface.
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setDfsFlag(ifname_, true);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR)
-            << "Failed to set DFS flag; DFS channels may be unavailable.";
-    }
-}
-
-void WifiStaIface::invalidate() {
-    legacy_hal_.reset();
-    event_cb_handler_.invalidate();
-    is_valid_ = false;
-}
-
-bool WifiStaIface::isValid() { return is_valid_; }
-
-std::string WifiStaIface::getName() { return ifname_; }
-
-std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::registerEventCallback(
-    const sp<IWifiStaIfaceEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::registerEventCallbackInternal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getCapabilitiesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getApfPacketFilterCapabilities(
-    getApfPacketFilterCapabilities_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::installApfPacketFilter(
-    uint32_t cmd_id, const hidl_vec<uint8_t>& program,
-    installApfPacketFilter_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::installApfPacketFilterInternal,
-                           hidl_status_cb, cmd_id, program);
-}
-
-Return<void> WifiStaIface::readApfPacketFilterData(
-    readApfPacketFilterData_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::readApfPacketFilterDataInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getBackgroundScanCapabilities(
-    getBackgroundScanCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getBackgroundScanCapabilitiesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getValidFrequenciesForBand(
-    V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getValidFrequenciesForBandInternal,
-                           hidl_status_cb, band);
-}
-
-Return<void> WifiStaIface::startBackgroundScan(
-    uint32_t cmd_id, const StaBackgroundScanParameters& params,
-    startBackgroundScan_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startBackgroundScanInternal,
-                           hidl_status_cb, cmd_id, params);
-}
-
-Return<void> WifiStaIface::stopBackgroundScan(
-    uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopBackgroundScanInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::enableLinkLayerStatsCollection(
-    bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
-        debug);
-}
-
-Return<void> WifiStaIface::disableLinkLayerStatsCollection(
-    disableLinkLayerStatsCollection_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats(
-    getLinkLayerStats_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats_1_3(
-    getLinkLayerStats_1_3_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal_1_3,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats_1_5(
-    getLinkLayerStats_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal_1_5,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::startRssiMonitoring(
-    uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
-    startRssiMonitoring_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startRssiMonitoringInternal,
-                           hidl_status_cb, cmd_id, max_rssi, min_rssi);
-}
-
-Return<void> WifiStaIface::stopRssiMonitoring(
-    uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopRssiMonitoringInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::getRoamingCapabilities(
-    getRoamingCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getRoamingCapabilitiesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::configureRoaming(
-    const StaRoamingConfig& config, configureRoaming_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::configureRoamingInternal,
-                           hidl_status_cb, config);
-}
-
-Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
-                                           setRoamingState_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setRoamingStateInternal,
-                           hidl_status_cb, state);
-}
-
-Return<void> WifiStaIface::enableNdOffload(bool enable,
-                                           enableNdOffload_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::enableNdOffloadInternal,
-                           hidl_status_cb, enable);
-}
-
-Return<void> WifiStaIface::startSendingKeepAlivePackets(
-    uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
-    uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
-    const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
-    startSendingKeepAlivePackets_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startSendingKeepAlivePacketsInternal,
-                           hidl_status_cb, cmd_id, ip_packet_data, ether_type,
-                           src_address, dst_address, period_in_ms);
-}
-
-Return<void> WifiStaIface::stopSendingKeepAlivePackets(
-    uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopSendingKeepAlivePacketsInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::setScanningMacOui(
-    const hidl_array<uint8_t, 3>& oui, setScanningMacOui_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setScanningMacOuiInternal,
-                           hidl_status_cb, oui);
-}
-
-Return<void> WifiStaIface::startDebugPacketFateMonitoring(
-    startDebugPacketFateMonitoring_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugTxPacketFates(
-    getDebugTxPacketFates_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getDebugTxPacketFatesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugRxPacketFates(
-    getDebugRxPacketFates_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getDebugRxPacketFatesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                                         setMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setMacAddressInternal, hidl_status_cb,
-                           mac);
-}
-
-Return<void> WifiStaIface::getFactoryMacAddress(
-    getFactoryMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getFactoryMacAddressInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::setScanMode(bool enable,
-                                       setScanMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setScanModeInternal, hidl_status_cb,
-                           enable);
-}
-
-std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
-}
-
-WifiStatus WifiStaIface::registerEventCallbackInternal(
-    const sp<IWifiStaIfaceEventCallback>& callback) {
-    if (!event_cb_handler_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    uint64_t legacy_feature_set;
-    std::tie(legacy_status, legacy_feature_set) =
-        legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), 0};
-    }
-    uint32_t legacy_logger_feature_set;
-    std::tie(legacy_status, legacy_logger_feature_set) =
-        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        // some devices don't support querying logger feature set
-        legacy_logger_feature_set = 0;
-    }
-    uint32_t hidl_caps;
-    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
-            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, StaApfPacketFilterCapabilities>
-WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::PacketFilterCapabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaApfPacketFilterCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
-                                                              &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::installApfPacketFilterInternal(
-    uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setPacketFilter(ifname_, program);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiStaIface::readApfPacketFilterDataInternal() {
-    const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>>
-        legacy_status_and_data =
-            legacy_hal_.lock()->readApfPacketFilterData(ifname_);
-    return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
-            std::move(legacy_status_and_data.second)};
-}
-
-std::pair<WifiStatus, StaBackgroundScanCapabilities>
-WifiStaIface::getBackgroundScanCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_gscan_capabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getGscanCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaBackgroundScanCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
-                                                                &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
-    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
-                  "Size mismatch");
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint32_t> valid_frequencies;
-    std::tie(legacy_status, valid_frequencies) =
-        legacy_hal_.lock()->getValidFrequenciesForBand(
-            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
-    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-
-WifiStatus WifiStaIface::startBackgroundScanInternal(
-    uint32_t cmd_id, const StaBackgroundScanParameters& params) {
-    legacy_hal::wifi_scan_cmd_params legacy_params;
-    if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
-                                                          &legacy_params)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    android::wp<WifiStaIface> weak_ptr_this(this);
-    const auto& on_failure_callback =
-        [weak_ptr_this](legacy_hal::wifi_request_id id) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onBackgroundScanFailure(id).isOk()) {
-                    LOG(ERROR)
-                        << "Failed to invoke onBackgroundScanFailure callback";
-                }
-            }
-        };
-    const auto& on_results_callback =
-        [weak_ptr_this](
-            legacy_hal::wifi_request_id id,
-            const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            std::vector<StaScanData> hidl_scan_datas;
-            if (!hidl_struct_util::
-                    convertLegacyVectorOfCachedGscanResultsToHidl(
-                        results, &hidl_scan_datas)) {
-                LOG(ERROR) << "Failed to convert scan results to HIDL structs";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onBackgroundScanResults(id, hidl_scan_datas)
-                         .isOk()) {
-                    LOG(ERROR)
-                        << "Failed to invoke onBackgroundScanResults callback";
-                }
-            }
-        };
-    const auto& on_full_result_callback = [weak_ptr_this](
-                                              legacy_hal::wifi_request_id id,
-                                              const legacy_hal::
-                                                  wifi_scan_result* result,
-                                              uint32_t buckets_scanned) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        StaScanResult hidl_scan_result;
-        if (!hidl_struct_util::convertLegacyGscanResultToHidl(
-                *result, true, &hidl_scan_result)) {
-            LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback
-                     ->onBackgroundFullScanResult(id, buckets_scanned,
-                                                  hidl_scan_result)
-                     .isOk()) {
-                LOG(ERROR)
-                    << "Failed to invoke onBackgroundFullScanResult callback";
-            }
-        }
-    };
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startGscan(
-        ifname_, cmd_id, legacy_params, on_failure_callback,
-        on_results_callback, on_full_result_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->disableLinkLayerStats(ifname_);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_0::StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal() {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_3::StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal_1_3() {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_5::StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal_1_5() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::LinkLayerStats legacy_stats;
-    std::tie(legacy_status, legacy_stats) =
-        legacy_hal_.lock()->getLinkLayerStats(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    V1_5::StaLinkLayerStats hidl_stats;
-    if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
-                                                             &hidl_stats)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
-                                                     int32_t max_rssi,
-                                                     int32_t min_rssi) {
-    android::wp<WifiStaIface> weak_ptr_this(this);
-    const auto& on_threshold_breached_callback =
-        [weak_ptr_this](legacy_hal::wifi_request_id id,
-                        std::array<uint8_t, 6> bssid, int8_t rssi) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onRssiThresholdBreached(id, bssid, rssi)
-                         .isOk()) {
-                    LOG(ERROR)
-                        << "Failed to invoke onRssiThresholdBreached callback";
-                }
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startRssiMonitoring(ifname_, cmd_id, max_rssi,
-                                                min_rssi,
-                                                on_threshold_breached_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, StaRoamingCapabilities>
-WifiStaIface::getRoamingCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_roaming_capabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getRoamingCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaRoamingCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps,
-                                                                  &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::configureRoamingInternal(
-    const StaRoamingConfig& config) {
-    legacy_hal::wifi_roaming_config legacy_config;
-    if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config,
-                                                            &legacy_config)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->enableFirmwareRoaming(
-            ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->configureNdOffload(ifname_, enable);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
-    uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
-    uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
-    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startSendingOffloadedPacket(
-            ifname_, cmd_id, ether_type, ip_packet_data, src_address,
-            dst_address, period_in_ms);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setScanningMacOuiInternal(
-    const std::array<uint8_t, 3>& /* oui */) {
-    // deprecated.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startPktFateMonitoring(ifname_);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-WifiStaIface::getDebugTxPacketFatesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<legacy_hal::wifi_tx_report> legacy_fates;
-    std::tie(legacy_status, legacy_fates) =
-        legacy_hal_.lock()->getTxPktFates(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugTxPacketFateReport> hidl_fates;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
-            legacy_fates, &hidl_fates)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-WifiStaIface::getDebugRxPacketFatesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<legacy_hal::wifi_rx_report> legacy_fates;
-    std::tie(legacy_status, legacy_fates) =
-        legacy_hal_.lock()->getRxPktFates(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugRxPacketFateReport> hidl_fates;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
-            legacy_fates, &hidl_fates)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-WifiStatus WifiStaIface::setMacAddressInternal(
-    const std::array<uint8_t, 6>& mac) {
-    bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
-    if (!status) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::array<uint8_t, 6>>
-WifiStaIface::getFactoryMacAddressInternal() {
-    std::array<uint8_t, 6> mac =
-        iface_util_.lock()->getFactoryMacAddress(ifname_);
-    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 &&
-        mac[4] == 0 && mac[5] == 0) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
-}
-
-WifiStatus WifiStaIface::setScanModeInternal(bool enable) {
-    // OEM's need to implement this on their devices if needed.
-    LOG(WARNING) << "setScanModeInternal(" << enable << ") not supported";
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_sta_iface.h b/wifi/1.5/default/wifi_sta_iface.h
deleted file mode 100644
index f9058b8..0000000
--- a/wifi/1.5/default/wifi_sta_iface.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_STA_IFACE_H_
-#define WIFI_STA_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.5/IWifiStaIface.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a STA Iface instance.
- */
-class WifiStaIface : public V1_5::IWifiStaIface {
-   public:
-    WifiStaIface(const std::string& ifname,
-                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(
-        const sp<IWifiStaIfaceEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> getApfPacketFilterCapabilities(
-        getApfPacketFilterCapabilities_cb hidl_status_cb) override;
-    Return<void> installApfPacketFilter(
-        uint32_t cmd_id, const hidl_vec<uint8_t>& program,
-        installApfPacketFilter_cb hidl_status_cb) override;
-    Return<void> readApfPacketFilterData(
-        readApfPacketFilterData_cb hidl_status_cb) override;
-    Return<void> getBackgroundScanCapabilities(
-        getBackgroundScanCapabilities_cb hidl_status_cb) override;
-    Return<void> getValidFrequenciesForBand(
-        V1_0::WifiBand band,
-        getValidFrequenciesForBand_cb hidl_status_cb) override;
-    Return<void> startBackgroundScan(
-        uint32_t cmd_id, const StaBackgroundScanParameters& params,
-        startBackgroundScan_cb hidl_status_cb) override;
-    Return<void> stopBackgroundScan(
-        uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
-    Return<void> enableLinkLayerStatsCollection(
-        bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
-    Return<void> disableLinkLayerStatsCollection(
-        disableLinkLayerStatsCollection_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats(
-        getLinkLayerStats_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats_1_3(
-        getLinkLayerStats_1_3_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats_1_5(
-        getLinkLayerStats_1_5_cb hidl_status_cb) override;
-    Return<void> startRssiMonitoring(
-        uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
-        startRssiMonitoring_cb hidl_status_cb) override;
-    Return<void> stopRssiMonitoring(
-        uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
-    Return<void> getRoamingCapabilities(
-        getRoamingCapabilities_cb hidl_status_cb) override;
-    Return<void> configureRoaming(const StaRoamingConfig& config,
-                                  configureRoaming_cb hidl_status_cb) override;
-    Return<void> setRoamingState(StaRoamingState state,
-                                 setRoamingState_cb hidl_status_cb) override;
-    Return<void> enableNdOffload(bool enable,
-                                 enableNdOffload_cb hidl_status_cb) override;
-    Return<void> startSendingKeepAlivePackets(
-        uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
-        uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
-        const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
-        startSendingKeepAlivePackets_cb hidl_status_cb) override;
-    Return<void> stopSendingKeepAlivePackets(
-        uint32_t cmd_id,
-        stopSendingKeepAlivePackets_cb hidl_status_cb) override;
-    Return<void> setScanningMacOui(
-        const hidl_array<uint8_t, 3>& oui,
-        setScanningMacOui_cb hidl_status_cb) override;
-    Return<void> startDebugPacketFateMonitoring(
-        startDebugPacketFateMonitoring_cb hidl_status_cb) override;
-    Return<void> getDebugTxPacketFates(
-        getDebugTxPacketFates_cb hidl_status_cb) override;
-    Return<void> getDebugRxPacketFates(
-        getDebugRxPacketFates_cb hidl_status_cb) override;
-    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                               setMacAddress_cb hidl_status_cb) override;
-    Return<void> getFactoryMacAddress(
-        getFactoryMacAddress_cb hidl_status_cb) override;
-    Return<void> setScanMode(bool enable,
-                             setScanMode_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus registerEventCallbackInternal(
-        const sp<IWifiStaIfaceEventCallback>& callback);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-    std::pair<WifiStatus, StaApfPacketFilterCapabilities>
-    getApfPacketFilterCapabilitiesInternal();
-    WifiStatus installApfPacketFilterInternal(
-        uint32_t cmd_id, const std::vector<uint8_t>& program);
-    std::pair<WifiStatus, std::vector<uint8_t>>
-    readApfPacketFilterDataInternal();
-    std::pair<WifiStatus, StaBackgroundScanCapabilities>
-    getBackgroundScanCapabilitiesInternal();
-    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-    getValidFrequenciesForBandInternal(V1_0::WifiBand band);
-    WifiStatus startBackgroundScanInternal(
-        uint32_t cmd_id, const StaBackgroundScanParameters& params);
-    WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
-    WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
-    WifiStatus disableLinkLayerStatsCollectionInternal();
-    std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
-    std::pair<WifiStatus, V1_3::StaLinkLayerStats>
-    getLinkLayerStatsInternal_1_3();
-    std::pair<WifiStatus, V1_5::StaLinkLayerStats>
-    getLinkLayerStatsInternal_1_5();
-    WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
-                                           int32_t min_rssi);
-    WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
-    std::pair<WifiStatus, StaRoamingCapabilities>
-    getRoamingCapabilitiesInternal();
-    WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
-    WifiStatus setRoamingStateInternal(StaRoamingState state);
-    WifiStatus enableNdOffloadInternal(bool enable);
-    WifiStatus startSendingKeepAlivePacketsInternal(
-        uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
-        uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
-        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
-    WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
-    WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
-    WifiStatus startDebugPacketFateMonitoringInternal();
-    std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-    getDebugTxPacketFatesInternal();
-    std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-    getDebugRxPacketFatesInternal();
-    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
-    std::pair<WifiStatus, std::array<uint8_t, 6>>
-    getFactoryMacAddressInternal();
-    WifiStatus setScanModeInternal(bool enable);
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    bool is_valid_;
-    hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
-        event_cb_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/1.5/default/wifi_status_util.cpp b/wifi/1.5/default/wifi_status_util.cpp
deleted file mode 100644
index eb8c869..0000000
--- a/wifi/1.5/default/wifi_status_util.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2016 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 "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-
-std::string legacyErrorToString(legacy_hal::wifi_error error) {
-    switch (error) {
-        case legacy_hal::WIFI_SUCCESS:
-            return "SUCCESS";
-        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
-            return "UNINITIALIZED";
-        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
-            return "NOT_AVAILABLE";
-        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
-            return "NOT_SUPPORTED";
-        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
-            return "INVALID_ARGS";
-        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
-            return "INVALID_REQUEST_ID";
-        case legacy_hal::WIFI_ERROR_TIMED_OUT:
-            return "TIMED_OUT";
-        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
-            return "TOO_MANY_REQUESTS";
-        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
-            return "OUT_OF_MEMORY";
-        case legacy_hal::WIFI_ERROR_BUSY:
-            return "BUSY";
-        case legacy_hal::WIFI_ERROR_UNKNOWN:
-            return "UNKNOWN";
-        default:
-            return "UNKNOWN ERROR";
-    }
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code,
-                            const std::string& description) {
-    return {code, description};
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code) {
-    return createWifiStatus(code, "");
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
-                                           const std::string& desc) {
-    switch (error) {
-        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
-        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
-            return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
-
-        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
-            return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
-
-        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
-        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
-            return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
-
-        case legacy_hal::WIFI_ERROR_TIMED_OUT:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                                    desc + ", timed out");
-
-        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                                    desc + ", too many requests");
-
-        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                                    desc + ", out of memory");
-
-        case legacy_hal::WIFI_ERROR_BUSY:
-            return createWifiStatus(WifiStatusCode::ERROR_BUSY);
-
-        case legacy_hal::WIFI_ERROR_NONE:
-            return createWifiStatus(WifiStatusCode::SUCCESS, desc);
-
-        case legacy_hal::WIFI_ERROR_UNKNOWN:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
-
-        default:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                                    "unknown error");
-    }
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
-    return createWifiStatusFromLegacyError(error, "");
-}
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.5/default/wifi_status_util.h b/wifi/1.5/default/wifi_status_util.h
deleted file mode 100644
index 68f2168..0000000
--- a/wifi/1.5/default/wifi_status_util.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_STATUS_UTIL_H_
-#define WIFI_STATUS_UTIL_H_
-
-#include <android/hardware/wifi/1.4/IWifi.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_5 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-std::string legacyErrorToString(legacy_hal::wifi_error error);
-WifiStatus createWifiStatus(WifiStatusCode code,
-                            const std::string& description);
-WifiStatus createWifiStatus(WifiStatusCode code);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
-                                           const std::string& description);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
-
-}  // namespace implementation
-}  // namespace V1_5
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.6/Android.bp b/wifi/1.6/Android.bp
new file mode 100644
index 0000000..14cb2e0
--- /dev/null
+++ b/wifi/1.6/Android.bp
@@ -0,0 +1,39 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+hidl_interface {
+    name: "android.hardware.wifi@1.6",
+    root: "android.hardware",
+    srcs: [
+        "IWifi.hal",
+        "IWifiChip.hal",
+        "IWifiNanIface.hal",
+        "IWifiNanIfaceEventCallback.hal",
+        "IWifiRttController.hal",
+        "IWifiRttControllerEventCallback.hal",
+        "IWifiStaIface.hal",
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
+}
diff --git a/wifi/1.6/IWifi.hal b/wifi/1.6/IWifi.hal
new file mode 100644
index 0000000..0123e6c
--- /dev/null
+++ b/wifi/1.6/IWifi.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.5::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() must return @1.5::IWifiChip
+ */
+interface IWifi extends @1.5::IWifi {};
diff --git a/wifi/1.6/IWifiChip.hal b/wifi/1.6/IWifiChip.hal
new file mode 100644
index 0000000..eaa2400
--- /dev/null
+++ b/wifi/1.6/IWifiChip.hal
@@ -0,0 +1,102 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.0::IWifiIface;
+import @1.0::WifiStatus;
+import @1.5::WifiBand;
+import @1.5::IWifiChip;
+import @1.5::WifiIfaceMode;
+import IWifiRttController;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+interface IWifiChip extends @1.5::IWifiChip {
+    /**
+     * Usable Wifi channels filter masks.
+     */
+    enum UsableChannelFilter : @1.5::IWifiChip.UsableChannelFilter {
+        /**
+         * Filter Wifi channels that are supported for NAN3.1 Instant communication mode. This
+         * filter should only be applied to NAN interface.
+         * - If 5G is supported default discovery channel 149/44 is considered,
+         * - If 5G is not supported then channel 6 has to be considered.
+         */
+        NAN_INSTANT_MODE = 1 << 2,
+    };
+
+    /**
+     * Create a RTTController instance.
+     *
+     * RTT controller can be either:
+     * a) Bound to a specific iface by passing in the corresponding |IWifiIface|
+     * object in |iface| param, OR
+     * b) Let the implementation decide the iface to use for RTT operations by
+     * passing null in |iface| param.
+     *
+     * @param boundIface HIDL interface object representing the iface if
+     *        the responder must be bound to a specific iface, null otherwise.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+     */
+    createRttController_1_6(IWifiIface boundIface)
+        generates (WifiStatus status, IWifiRttController rtt);
+
+    /**
+     * Retrieve list of usable Wifi channels for the specified band &
+     * operational modes.
+     *
+     * The list of usable Wifi channels in a given band depends on factors
+     * like current country code, operational mode (e.g. STA, SAP, WFD-CLI,
+     * WFD-GO, TDLS, NAN) and other restrictons due to DFS, cellular coexistence
+     * and conncurency state of the device.
+     *
+     * @param band |WifiBand| for which list of usable channels is requested.
+     * @param ifaceModeMask Bitmask of the modes represented by |WifiIfaceMode|
+     *        Bitmask respresents all the modes that the caller is interested
+     *        in (e.g. STA, SAP, CLI, GO, TDLS, NAN). E.g. If the caller is
+     *        interested in knowing usable channels for P2P CLI, P2P GO & NAN,
+     *        ifaceModeMask would be set to
+     *        IFACE_MODE_P2P_CLIENT|IFACE_MODE_P2P_GO|IFACE_MODE_NAN.
+     * @param filterMask Bitmask of filters represented by
+     *        |UsableChannelFilter|. Specifies whether driver should filter
+     *        channels based on additional criteria. If no filter is specified
+     *        driver should return usable channels purely based on regulatory
+     *        constraints.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.FAILURE_UNKNOWN|
+     * @return channels List of channels represented by |WifiUsableChannel|
+     *         Each entry represents a channel frequency, bandwidth and
+     *         bitmask of modes (e.g. STA, SAP, CLI, GO, TDLS, NAN) that are
+     *         allowed on that channel. E.g. If only STA mode can be supported
+     *         on an indoor channel, only the IFACE_MODE_STA bit would be set
+     *         for that channel. If 5GHz SAP cannot be supported, then none of
+     *         the 5GHz channels will have IFACE_MODE_SOFTAP bit set.
+     *         Note: Bits do not represent concurrency state. Each bit only
+     *         represents whether particular mode is allowed on that channel.
+     */
+    getUsableChannels_1_6(WifiBand band, bitfield<WifiIfaceMode> ifaceModeMask,
+        bitfield<UsableChannelFilter> filterMask)
+        generates (WifiStatus status, vec<WifiUsableChannel> channels);
+};
diff --git a/wifi/1.6/IWifiNanIface.hal b/wifi/1.6/IWifiNanIface.hal
new file mode 100644
index 0000000..7ffd278
--- /dev/null
+++ b/wifi/1.6/IWifiNanIface.hal
@@ -0,0 +1,155 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.0::WifiStatus;
+import @1.0::CommandIdShort;
+import @1.4::NanConfigRequest;
+import @1.4::NanEnableRequest;
+import @1.5::IWifiNanIface;
+import IWifiNanIfaceEventCallback;
+import NanConfigRequestSupplemental;
+import NanInitiateDataPathRequest;
+import NanPublishRequest;
+import NanRespondToDataPathIndicationRequest;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.5::IWifiNanIface {
+    /**
+     * Requests notifications of significant events on this iface. Multiple calls
+     * to this must register multiple callbacks each of which must receive all
+     * events.
+     *
+     * @param callback An instance of the |IWifiNanIfaceEventCallback| HIDL interface
+     *        object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+     */
+    registerEventCallback_1_6(IWifiNanIfaceEventCallback callback) generates (WifiStatus status);
+
+    /**
+     * Initiate a data-path (NDP) setup operation: Initiator.
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyInitiateDataPathResponse|.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.respondToDataPathIndicationRequest() method which is
+     * deprecated as of HAL version 1.6.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg Instance of |NanInitiateDataPathRequest|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    initiateDataPathRequest_1_6(CommandIdShort cmdId, NanInitiateDataPathRequest msg)
+        generates (WifiStatus status);
+
+    /**
+     * Respond to a received data indication as part of a data-path (NDP) setup operation. An
+     * indication is received by the Responder from the Initiator.
+     * Asynchronous response is with
+     * |IWifiNanIfaceEventCallback.notifyRespondToDataPathIndicationResponse|.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.respondToDataPathIndicationRequest() method which is
+     * deprecated as of HAL version 1.6.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg Instance of |NanRespondToDataPathIndicationRequest|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    respondToDataPathIndicationRequest_1_6(CommandIdShort cmdId,
+        NanRespondToDataPathIndicationRequest msg) generates (WifiStatus status);
+
+    /**
+     * Enable NAN: configures and activates NAN clustering (does not start
+     * a discovery session or set up data-interfaces or data-paths). Use the
+     * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+     * NAN interface.
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+     *
+     * Note: supersedes the @1.5::IWifiNanIface.enableRequest() method which is deprecated as of
+     * HAL version 1.6.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanEnableRequest|.
+     * @param msg2 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    enableRequest_1_6(CommandIdShort cmdId, NanEnableRequest msg1,
+        NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+
+    /**
+     * Configure NAN: configures an existing NAN functionality (i.e. assumes
+     * |IWifiNanIface.enableRequest| already submitted and succeeded).
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+     *
+     * Note: supersedes the @1.5::IWifiNanIface.configRequest() method which is deprecated as of
+     * HAL version 1.6.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanConfigRequest|.
+     * @param msg2 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    configRequest_1_6(CommandIdShort cmdId, NanConfigRequest msg1,
+        NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+
+    /**
+     * Publish request to start advertising a discovery service.
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyStartPublishResponse|.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.startPublishRequest() method which is deprecated as
+     * of HAL version 1.6.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg Instance of |NanPublishRequest|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    startPublishRequest_1_6(CommandIdShort cmdId, NanPublishRequest msg)
+        generates (WifiStatus status);
+};
diff --git a/wifi/1.6/IWifiNanIfaceEventCallback.hal b/wifi/1.6/IWifiNanIfaceEventCallback.hal
new file mode 100644
index 0000000..f19f900
--- /dev/null
+++ b/wifi/1.6/IWifiNanIfaceEventCallback.hal
@@ -0,0 +1,74 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.0::CommandIdShort;
+import @1.0::WifiNanStatus;
+import @1.5::IWifiNanIfaceEventCallback;
+
+/**
+ * NAN Response and Asynchronous Event Callbacks.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIfaceEventCallback extends @1.5::IWifiNanIfaceEventCallback {
+    /**
+     * Asynchronous callback indicating a data-path (NDP) setup has been completed: received by
+     * both Initiator and Responder.
+     *
+     * Note: supersedes the @1.0::IWifiNanIfaceEventCallback.eventDataPathConfirm() method which is
+     * deprecated as of HAL version 1.2.
+     *
+     * @param event: NanDataPathConfirmInd containing event details.
+     */
+    oneway eventDataPathConfirm_1_6(NanDataPathConfirmInd event);
+
+    /**
+     * Asynchronous callback indicating a data-path (NDP) schedule has been updated (e.g. channels
+     * have been changed).
+     *
+     * @param event: NanDataPathScheduleUpdateInd containing event details.
+     */
+    oneway eventDataPathScheduleUpdate_1_6(NanDataPathScheduleUpdateInd event);
+
+    /**
+     * Asynchronous callback indicating that a match has occurred: i.e. a service has been
+     * discovered.
+     *
+     * Note: supersedes the @1.0::IWifiNanIfaceEventCallback.eventMatch(NanMatchInd event) method
+     * which is deprecated as of HAL version 1.6.
+     *
+     * @param event: NanMatchInd containing event details.
+     */
+    oneway eventMatch_1_6(NanMatchInd event);
+
+    /**
+     * Asynchronous callback invoked in response to a capability request
+     * |IWifiNanIface.getCapabilitiesRequest|.
+     *
+     * Note: supersedes the @1.5::IWifiNanIfaceEventCallback.notifyCapabilitiesResponse() method
+     * which is deprecated as of HAL version 1.6.
+     *
+     * @param cmdId command Id corresponding to the original request.
+     * @param status WifiNanStatus of the operation. Possible status codes are:
+     *        |NanStatusType.SUCCESS|
+     * @param capabilities Capability data.
+     */
+    oneway notifyCapabilitiesResponse_1_6(CommandIdShort id, WifiNanStatus status,
+        NanCapabilities capabilities);
+};
diff --git a/wifi/1.6/IWifiRttController.hal b/wifi/1.6/IWifiRttController.hal
new file mode 100644
index 0000000..a08f7e4
--- /dev/null
+++ b/wifi/1.6/IWifiRttController.hal
@@ -0,0 +1,101 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.0::CommandId;
+import @1.0::WifiStatus;
+import @1.4::IWifiRttController;
+import IWifiRttControllerEventCallback;
+
+/**
+ * Interface used to perform RTT(Round trip time) operations.
+ */
+interface IWifiRttController extends @1.4::IWifiRttController {
+    /**
+     * Requests notifications of significant events on this rtt controller.
+     * Multiple calls to this must register multiple callbacks each of which must
+     * receive all events.
+     *
+     * @param callback An instance of the |IWifiRttControllerEventCallback| HIDL
+     *        interface object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+     */
+    registerEventCallback_1_6(IWifiRttControllerEventCallback callback)
+        generates (WifiStatus status);
+
+    /**
+     * API to request RTT measurement.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param rttConfigs Vector of |RttConfig| parameters.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    rangeRequest_1_6(CommandId cmdId, vec<RttConfig> rttConfigs) generates (WifiStatus status);
+
+    /**
+     * Get RTT responder information e.g. WiFi channel to enable responder on.
+     *
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return info Instance of |RttResponderInfo|.
+     */
+    getResponderInfo_1_6() generates (WifiStatus status, RttResponder info);
+
+    /**
+     * Enable RTT responder mode.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @parm channelHint Hint of the channel information where RTT responder must
+     *       be enabled on.
+     * @param maxDurationInSeconds Timeout of responder mode.
+     * @param info Instance of |RttResponderInfo|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    enableResponder_1_6(CommandId cmdId, WifiChannelInfo channelHint,
+        uint32_t maxDurationInSeconds, RttResponder info) generates (WifiStatus status);
+
+    /**
+     * RTT capabilities of the device.
+     *
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return capabilities Instance of |RttCapabilities|.
+     */
+    getCapabilities_1_6() generates (WifiStatus status, RttCapabilities capabilities);
+};
diff --git a/wifi/1.6/IWifiRttControllerEventCallback.hal b/wifi/1.6/IWifiRttControllerEventCallback.hal
new file mode 100644
index 0000000..0857b66
--- /dev/null
+++ b/wifi/1.6/IWifiRttControllerEventCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.4::IWifiRttControllerEventCallback;
+import @1.0::CommandId;
+
+/**
+ * RTT Response and Event Callbacks.
+ */
+interface IWifiRttControllerEventCallback extends @1.4::IWifiRttControllerEventCallback {
+    /*
+     * Invoked when an RTT result is available.
+     *
+     * @param cmdId command Id corresponding to the original request.
+     * @param results Vector of |RttResult| instances.
+     */
+    oneway onResults_1_6(CommandId cmdId, vec<RttResult> results);
+};
diff --git a/wifi/1.6/IWifiStaIface.hal b/wifi/1.6/IWifiStaIface.hal
new file mode 100644
index 0000000..c26e1a0
--- /dev/null
+++ b/wifi/1.6/IWifiStaIface.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.0::WifiStatus;
+import @1.5::IWifiStaIface;
+
+/**
+ * Interface used to represent a single STA iface.
+ *
+ * IWifiChip.createStaIface() must return a @1.6::IWifiStaIface when supported.
+ */
+interface IWifiStaIface extends @1.5::IWifiStaIface {
+    /**
+     * Retrieve the latest link layer stats.
+     * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set or if
+     * link layer stats collection hasn't been explicitly enabled.
+     *
+     * @return status WifiStatus of the operation.
+     *     Possible status codes:
+     *     |WifiStatusCode.SUCCESS|,
+     *     |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *     |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *     |WifiStatusCode.ERROR_NOT_STARTED|,
+     *     |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *     |WifiStatusCode.ERROR_UNKNOWN|
+     * @return stats Instance of |LinkLayerStats|.
+     */
+    getLinkLayerStats_1_6() generates (WifiStatus status, StaLinkLayerStats stats);
+};
diff --git a/wifi/1.6/default/Android.bp b/wifi/1.6/default/Android.bp
new file mode 100644
index 0000000..d48d183
--- /dev/null
+++ b/wifi/1.6/default/Android.bp
@@ -0,0 +1,107 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+filegroup {
+    name: "android.hardware.wifi@1.0-service_srcs",
+    srcs: ["service.cpp"],
+}
+
+cc_defaults {
+    name: "android.hardware.wifi@1.0-service_default",
+    srcs: [":android.hardware.wifi@1.0-service_srcs"],
+    relative_install_path: "hw",
+    soc_specific: true,
+    shared_libs: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "android.hardware.wifi@1.6",
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libnl",
+        "libutils",
+        "libwifi-system-iface",
+        "libxml2",
+    ],
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
+
+filegroup {
+    name: "android.hardware.wifi@1.0-service-lib_srcs",
+    srcs: [
+        "hidl_struct_util.cpp",
+        "hidl_sync_util.cpp",
+        "ringbuffer.cpp",
+        "wifi.cpp",
+        "wifi_ap_iface.cpp",
+        "wifi_chip.cpp",
+        "wifi_feature_flags.cpp",
+        "wifi_iface_util.cpp",
+        "wifi_legacy_hal.cpp",
+        "wifi_legacy_hal_factory.cpp",
+        "wifi_legacy_hal_stubs.cpp",
+        "wifi_mode_controller.cpp",
+        "wifi_nan_iface.cpp",
+        "wifi_p2p_iface.cpp",
+        "wifi_rtt_controller.cpp",
+        "wifi_sta_iface.cpp",
+        "wifi_status_util.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "android.hardware.wifi@1.0-service-lib_defaults",
+    srcs: [":android.hardware.wifi@1.0-service-lib_srcs"],
+    relative_install_path: "hw",
+    soc_specific: true,
+    shared_libs: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "android.hardware.wifi@1.6",
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libnl",
+        "libutils",
+        "libwifi-system-iface",
+        "libxml2",
+    ],
+    // Generated by building android.hardware.wifi@1.0-service-lib and printing LOCAL_CPPFLAGS.
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-DWIFI_HIDL_FEATURE_DUAL_INTERFACE",
+    ],
+    export_include_dirs: ["."],
+    include_dirs: ["external/libxml2/include"],
+}
diff --git a/wifi/1.6/default/Android.mk b/wifi/1.6/default/Android.mk
new file mode 100644
index 0000000..ca1c022
--- /dev/null
+++ b/wifi/1.6/default/Android.mk
@@ -0,0 +1,202 @@
+# Copyright (C) 2016 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.
+LOCAL_PATH := $(call my-dir)
+
+###
+### android.hardware.wifi static library
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)"
+endif
+ifdef WIFI_HIDL_FEATURE_AWARE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
+endif
+ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
+endif
+ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
+endif
+ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+endif
+ifdef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+LOCAL_CPPFLAGS += -DWIFI_AVOID_IFACE_RESET_MAC_CHANGE
+endif
+# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
+LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
+LOCAL_SRC_FILES := \
+    hidl_struct_util.cpp \
+    hidl_sync_util.cpp \
+    ringbuffer.cpp \
+    wifi.cpp \
+    wifi_ap_iface.cpp \
+    wifi_chip.cpp \
+    wifi_feature_flags.cpp \
+    wifi_iface_util.cpp \
+    wifi_legacy_hal.cpp \
+    wifi_legacy_hal_factory.cpp \
+    wifi_legacy_hal_stubs.cpp \
+    wifi_mode_controller.cpp \
+    wifi_nan_iface.cpp \
+    wifi_p2p_iface.cpp \
+    wifi_rtt_controller.cpp \
+    wifi_sta_iface.cpp \
+    wifi_status_util.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    libxml2 \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5 \
+    android.hardware.wifi@1.6
+LOCAL_C_INCLUDES += $(TOP)/external/libxml2/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+###
+### android.hardware.wifi daemon
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
+LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+    service.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    libxml2 \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5 \
+    android.hardware.wifi@1.6
+LOCAL_STATIC_LIBRARIES := \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
+include $(BUILD_EXECUTABLE)
+
+###
+### android.hardware.wifi daemon
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
+LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
+LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service
+LOCAL_CFLAGS := -DLAZY_SERVICE
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+    service.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    libxml2 \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5 \
+    android.hardware.wifi@1.6
+LOCAL_STATIC_LIBRARIES := \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
+include $(BUILD_EXECUTABLE)
+
+###
+### android.hardware.wifi unit tests.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+    tests/hidl_struct_util_unit_tests.cpp \
+    tests/main.cpp \
+    tests/mock_interface_tool.cpp \
+    tests/mock_wifi_feature_flags.cpp \
+    tests/mock_wifi_iface_util.cpp \
+    tests/mock_wifi_legacy_hal.cpp \
+    tests/mock_wifi_mode_controller.cpp \
+    tests/ringbuffer_unit_tests.cpp \
+    tests/wifi_nan_iface_unit_tests.cpp \
+    tests/wifi_chip_unit_tests.cpp \
+    tests/wifi_iface_util_unit_tests.cpp
+LOCAL_STATIC_LIBRARIES := \
+    libgmock \
+    libgtest \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5 \
+    android.hardware.wifi@1.6 \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface
+include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.5/default/OWNERS b/wifi/1.6/default/OWNERS
similarity index 100%
rename from wifi/1.5/default/OWNERS
rename to wifi/1.6/default/OWNERS
diff --git a/wifi/1.5/default/THREADING.README b/wifi/1.6/default/THREADING.README
similarity index 100%
rename from wifi/1.5/default/THREADING.README
rename to wifi/1.6/default/THREADING.README
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
new file mode 100644
index 0000000..ee8c818
--- /dev/null
+++ b/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
@@ -0,0 +1,14 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service-lazy
+    interface android.hardware.wifi@1.0::IWifi default
+    interface android.hardware.wifi@1.1::IWifi default
+    interface android.hardware.wifi@1.2::IWifi default
+    interface android.hardware.wifi@1.3::IWifi default
+    interface android.hardware.wifi@1.4::IWifi default
+    interface android.hardware.wifi@1.5::IWifi default
+    interface android.hardware.wifi@1.6::IWifi default
+    oneshot
+    disabled
+    class hal
+    capabilities NET_ADMIN NET_RAW SYS_MODULE
+    user wifi
+    group wifi gps
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service.rc b/wifi/1.6/default/android.hardware.wifi@1.0-service.rc
new file mode 100644
index 0000000..18f40d0
--- /dev/null
+++ b/wifi/1.6/default/android.hardware.wifi@1.0-service.rc
@@ -0,0 +1,12 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
+    interface android.hardware.wifi@1.0::IWifi default
+    interface android.hardware.wifi@1.1::IWifi default
+    interface android.hardware.wifi@1.2::IWifi default
+    interface android.hardware.wifi@1.3::IWifi default
+    interface android.hardware.wifi@1.4::IWifi default
+    interface android.hardware.wifi@1.5::IWifi default
+    interface android.hardware.wifi@1.6::IWifi default
+    class hal
+    capabilities NET_ADMIN NET_RAW SYS_MODULE
+    user wifi
+    group wifi gps
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service.xml b/wifi/1.6/default/android.hardware.wifi@1.0-service.xml
new file mode 100644
index 0000000..771fbaa
--- /dev/null
+++ b/wifi/1.6/default/android.hardware.wifi@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.wifi</name>
+        <transport>hwbinder</transport>
+        <version>1.6</version>
+        <interface>
+            <name>IWifi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/wifi/1.6/default/hidl_callback_util.h b/wifi/1.6/default/hidl_callback_util.h
new file mode 100644
index 0000000..3ac54c1
--- /dev/null
+++ b/wifi/1.6/default/hidl_callback_util.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_CALLBACK_UTIL_H_
+#define HIDL_CALLBACK_UTIL_H_
+
+#include <set>
+
+#include <hidl/HidlSupport.h>
+
+namespace {
+// Type of callback invoked by the death handler.
+using on_death_cb_function = std::function<void(uint64_t)>;
+
+// Private class used to keep track of death of individual
+// callbacks stored in HidlCallbackHandler.
+template <typename CallbackType>
+class HidlDeathHandler : public android::hardware::hidl_death_recipient {
+  public:
+    HidlDeathHandler(const on_death_cb_function& user_cb_function)
+        : cb_function_(user_cb_function) {}
+    ~HidlDeathHandler() = default;
+
+    // Death notification for callbacks.
+    void serviceDied(uint64_t cookie,
+                     const android::wp<android::hidl::base::V1_0::IBase>& /* who */) override {
+        cb_function_(cookie);
+    }
+
+  private:
+    on_death_cb_function cb_function_;
+
+    DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
+};
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_callback_util {
+template <typename CallbackType>
+// Provides a class to manage callbacks for the various HIDL interfaces and
+// handle the death of the process hosting each callback.
+class HidlCallbackHandler {
+  public:
+    HidlCallbackHandler()
+        : death_handler_(new HidlDeathHandler<CallbackType>(
+                  std::bind(&HidlCallbackHandler::onObjectDeath, this, std::placeholders::_1))) {}
+    ~HidlCallbackHandler() = default;
+
+    bool addCallback(const sp<CallbackType>& cb) {
+        // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
+        // (callback proxy's raw pointer) to track the death of individual
+        // clients.
+        uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
+        if (cb_set_.find(cb) != cb_set_.end()) {
+            LOG(WARNING) << "Duplicate death notification registration";
+            return true;
+        }
+        if (!cb->linkToDeath(death_handler_, cookie)) {
+            LOG(ERROR) << "Failed to register death notification";
+            return false;
+        }
+        cb_set_.insert(cb);
+        return true;
+    }
+
+    const std::set<android::sp<CallbackType>>& getCallbacks() { return cb_set_; }
+
+    // Death notification for callbacks.
+    void onObjectDeath(uint64_t cookie) {
+        CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
+        const auto& iter = cb_set_.find(cb);
+        if (iter == cb_set_.end()) {
+            LOG(ERROR) << "Unknown callback death notification received";
+            return;
+        }
+        cb_set_.erase(iter);
+        LOG(DEBUG) << "Dead callback removed from list";
+    }
+
+    void invalidate() {
+        for (const sp<CallbackType>& cb : cb_set_) {
+            if (!cb->unlinkToDeath(death_handler_)) {
+                LOG(ERROR) << "Failed to deregister death notification";
+            }
+        }
+        cb_set_.clear();
+    }
+
+  private:
+    std::set<sp<CallbackType>> cb_set_;
+    sp<HidlDeathHandler<CallbackType>> death_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
+};
+
+}  // namespace hidl_callback_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.6/default/hidl_return_util.h b/wifi/1.6/default/hidl_return_util.h
new file mode 100644
index 0000000..a0efac2
--- /dev/null
+++ b/wifi/1.6/default/hidl_return_util.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_RETURN_UTIL_H_
+#define HIDL_RETURN_UTIL_H_
+
+#include "hidl_sync_util.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_return_util {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * These utility functions are used to invoke a method on the provided
+ * HIDL interface object.
+ * These functions checks if the provided HIDL interface object is valid.
+ * a) if valid, Invokes the corresponding internal implementation function of
+ * the HIDL method. It then invokes the HIDL continuation callback with
+ * the status and any returned values.
+ * b) if invalid, invokes the HIDL continuation callback with the
+ * provided error status and default values.
+ */
+// Use for HIDL methods which return only an instance of WifiStatus.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+                             const std::function<void(const WifiStatus&)>& hidl_cb,
+                             Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        hidl_cb((obj->*work)(std::forward<Args>(args)...));
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid));
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return only an instance of WifiStatus.
+// This version passes the global lock acquired to the body of the method.
+// Note: Only used by IWifi::stop() currently.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCallWithLock(ObjT* obj, WifiStatusCode status_code_if_invalid,
+                                     WorkFuncT&& work,
+                                     const std::function<void(const WifiStatus&)>& hidl_cb,
+                                     Args&&... args) {
+    auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid));
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and a single return
+// value.
+template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+Return<void> validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+                             const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
+                             Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
+        const WifiStatus& status = std::get<0>(ret_pair);
+        const auto& ret_value = std::get<1>(ret_pair);
+        hidl_cb(status, ret_value);
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid),
+                typename std::remove_reference<ReturnT>::type());
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and 2 return
+// values.
+template <typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2, typename... Args>
+Return<void> validateAndCall(
+        ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+        const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb, Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
+        const WifiStatus& status = std::get<0>(ret_tuple);
+        const auto& ret_value1 = std::get<1>(ret_tuple);
+        const auto& ret_value2 = std::get<2>(ret_tuple);
+        hidl_cb(status, ret_value1, ret_value2);
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid),
+                typename std::remove_reference<ReturnT1>::type(),
+                typename std::remove_reference<ReturnT2>::type());
+    }
+    return Void();
+}
+
+}  // namespace hidl_return_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.6/default/hidl_struct_util.cpp b/wifi/1.6/default/hidl_struct_util.cpp
new file mode 100644
index 0000000..76341ff
--- /dev/null
+++ b/wifi/1.6/default/hidl_struct_util.cpp
@@ -0,0 +1,2915 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "hidl_struct_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_struct_util {
+
+using V1_6::NanConfigRequestSupplemental;
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(legacy_hal::wifi_channel_width type);
+
+hidl_string safeConvertChar(const char* str, size_t max_len) {
+    const char* c = str;
+    size_t size = 0;
+    while (*c && (unsigned char)*c < 128 && size < max_len) {
+        ++size;
+        ++c;
+    }
+    return hidl_string(str, size);
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(uint32_t feature) {
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
+            return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
+        case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
+            return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
+        case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
+        case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
+        case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask convertLegacyLoggerFeatureToHidlStaIfaceCapability(
+        uint32_t feature) {
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
+            return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+V1_5::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(uint64_t feature) {
+    using HidlChipCaps = V1_5::IWifiChip::ChipCapabilityMask;
+    switch (feature) {
+        case WIFI_FEATURE_SET_TX_POWER_LIMIT:
+            return HidlChipCaps::SET_TX_POWER_LIMIT;
+        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+            return HidlChipCaps::USE_BODY_HEAD_SAR;
+        case WIFI_FEATURE_D2D_RTT:
+            return HidlChipCaps::D2D_RTT;
+        case WIFI_FEATURE_D2AP_RTT:
+            return HidlChipCaps::D2AP_RTT;
+        case WIFI_FEATURE_INFRA_60G:
+            return HidlChipCaps::WIGIG;
+        case WIFI_FEATURE_SET_LATENCY_MODE:
+            return HidlChipCaps::SET_LATENCY_MODE;
+        case WIFI_FEATURE_P2P_RAND_MAC:
+            return HidlChipCaps::P2P_RAND_MAC;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask convertLegacyFeatureToHidlStaIfaceCapability(
+        uint64_t feature) {
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    switch (feature) {
+        case WIFI_FEATURE_GSCAN:
+            return HidlStaIfaceCaps::BACKGROUND_SCAN;
+        case WIFI_FEATURE_LINK_LAYER_STATS:
+            return HidlStaIfaceCaps::LINK_LAYER_STATS;
+        case WIFI_FEATURE_RSSI_MONITOR:
+            return HidlStaIfaceCaps::RSSI_MONITOR;
+        case WIFI_FEATURE_CONTROL_ROAMING:
+            return HidlStaIfaceCaps::CONTROL_ROAMING;
+        case WIFI_FEATURE_IE_WHITELIST:
+            return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
+        case WIFI_FEATURE_SCAN_RAND:
+            return HidlStaIfaceCaps::SCAN_RAND;
+        case WIFI_FEATURE_INFRA_5G:
+            return HidlStaIfaceCaps::STA_5G;
+        case WIFI_FEATURE_HOTSPOT:
+            return HidlStaIfaceCaps::HOTSPOT;
+        case WIFI_FEATURE_PNO:
+            return HidlStaIfaceCaps::PNO;
+        case WIFI_FEATURE_TDLS:
+            return HidlStaIfaceCaps::TDLS;
+        case WIFI_FEATURE_TDLS_OFFCHANNEL:
+            return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
+        case WIFI_FEATURE_CONFIG_NDO:
+            return HidlStaIfaceCaps::ND_OFFLOAD;
+        case WIFI_FEATURE_MKEEP_ALIVE:
+            return HidlStaIfaceCaps::KEEP_ALIVE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+bool convertLegacyFeaturesToHidlChipCapabilities(uint64_t legacy_feature_set,
+                                                 uint32_t legacy_logger_feature_set,
+                                                 uint32_t* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *hidl_caps |= convertLegacyLoggerFeatureToHidlChipCapability(feature);
+        }
+    }
+    std::vector<uint64_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+                                      WIFI_FEATURE_USE_BODY_HEAD_SAR,
+                                      WIFI_FEATURE_D2D_RTT,
+                                      WIFI_FEATURE_D2AP_RTT,
+                                      WIFI_FEATURE_INFRA_60G,
+                                      WIFI_FEATURE_SET_LATENCY_MODE,
+                                      WIFI_FEATURE_P2P_RAND_MAC};
+    for (const auto feature : features) {
+        if (feature & legacy_feature_set) {
+            *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
+        }
+    }
+
+    // There are no flags for these 3 in the legacy feature set. Adding them to
+    // the set because all the current devices support it.
+    *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
+    *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
+    *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
+    return true;
+}
+
+WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(uint32_t flag) {
+    switch (flag) {
+        case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
+        case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
+    };
+    CHECK(false) << "Unknown legacy flag: " << flag;
+    return {};
+}
+
+bool convertLegacyDebugRingBufferStatusToHidl(
+        const legacy_hal::wifi_ring_buffer_status& legacy_status,
+        WifiDebugRingBufferStatus* hidl_status) {
+    if (!hidl_status) {
+        return false;
+    }
+    *hidl_status = {};
+    hidl_status->ringName = safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
+                                            sizeof(legacy_status.name));
+    hidl_status->flags = 0;
+    for (const auto flag :
+         {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES, WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
+        if (flag & legacy_status.flags) {
+            hidl_status->flags |= static_cast<std::underlying_type<WifiDebugRingBufferFlags>::type>(
+                    convertLegacyDebugRingBufferFlagsToHidl(flag));
+        }
+    }
+    hidl_status->ringId = legacy_status.ring_id;
+    hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
+    // Calculate free size of the ring the buffer. We don't need to send the
+    // exact read/write pointers that were there in the legacy HAL interface.
+    if (legacy_status.written_bytes >= legacy_status.read_bytes) {
+        hidl_status->freeSizeInBytes = legacy_status.ring_buffer_byte_size -
+                                       (legacy_status.written_bytes - legacy_status.read_bytes);
+    } else {
+        hidl_status->freeSizeInBytes = legacy_status.read_bytes - legacy_status.written_bytes;
+    }
+    hidl_status->verboseLevel = legacy_status.verbose_level;
+    return true;
+}
+
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+        const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+        std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
+    if (!hidl_status_vec) {
+        return false;
+    }
+    *hidl_status_vec = {};
+    for (const auto& legacy_status : legacy_status_vec) {
+        WifiDebugRingBufferStatus hidl_status;
+        if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status, &hidl_status)) {
+            return false;
+        }
+        hidl_status_vec->push_back(hidl_status);
+    }
+    return true;
+}
+
+bool convertLegacyWakeReasonStatsToHidl(const legacy_hal::WakeReasonStats& legacy_stats,
+                                        WifiDebugHostWakeReasonStats* hidl_stats) {
+    if (!hidl_stats) {
+        return false;
+    }
+    *hidl_stats = {};
+    hidl_stats->totalCmdEventWakeCnt = legacy_stats.wake_reason_cnt.total_cmd_event_wake;
+    hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
+    hidl_stats->totalDriverFwLocalWakeCnt = legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
+    hidl_stats->driverFwLocalWakeCntPerType = legacy_stats.driver_fw_local_wake_cnt;
+    hidl_stats->totalRxPacketWakeCnt = legacy_stats.wake_reason_cnt.total_rx_data_wake;
+    hidl_stats->rxPktWakeDetails.rxUnicastCnt =
+            legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
+    hidl_stats->rxPktWakeDetails.rxMulticastCnt =
+            legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
+    hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
+            legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
+            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
+            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
+            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt;
+    hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
+    return true;
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+        V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+        V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+        case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+        // Those are the supported scenarios for V1_2
+        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+        V1_3::IWifiChip::LatencyMode hidl_latency_mode) {
+    switch (hidl_latency_mode) {
+        case V1_3::IWifiChip::LatencyMode::NORMAL:
+            return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
+        case V1_3::IWifiChip::LatencyMode::LOW:
+            return legacy_hal::WIFI_LATENCY_MODE_LOW;
+    }
+    CHECK(false);
+}
+
+bool convertLegacyWifiMacInfoToHidl(
+        const legacy_hal::WifiMacInfo& legacy_mac_info,
+        V1_4::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+    if (!hidl_radio_mode_info) {
+        return false;
+    }
+    *hidl_radio_mode_info = {};
+
+    hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
+    // Convert from bitmask of bands in the legacy HAL to enum value in
+    // the HIDL interface.
+    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
+               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ;
+    } else {
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_UNSPECIFIED;
+    }
+    std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
+        V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
+        iface_info.name = legacy_iface_info.name;
+        iface_info.channel = legacy_iface_info.channel;
+        iface_info_vec.push_back(iface_info);
+    }
+    hidl_radio_mode_info->ifaceInfos = iface_info_vec;
+    return true;
+}
+
+uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand hidl_band) {
+    switch (hidl_band) {
+        case V1_5::WifiBand::BAND_24GHZ:
+            return legacy_hal::WLAN_MAC_2_4_BAND;
+        case V1_5::WifiBand::BAND_5GHZ:
+        case V1_5::WifiBand::BAND_5GHZ_DFS:
+        case V1_5::WifiBand::BAND_5GHZ_WITH_DFS:
+            return legacy_hal::WLAN_MAC_5_0_BAND;
+        case V1_5::WifiBand::BAND_24GHZ_5GHZ:
+        case V1_5::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+            return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND);
+        case V1_5::WifiBand::BAND_6GHZ:
+            return legacy_hal::WLAN_MAC_6_0_BAND;
+        case V1_5::WifiBand::BAND_5GHZ_6GHZ:
+            return (legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_6_0_BAND);
+        case V1_5::WifiBand::BAND_24GHZ_5GHZ_6GHZ:
+        case V1_5::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS_6GHZ:
+            return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND |
+                    legacy_hal::WLAN_MAC_6_0_BAND);
+        case V1_5::WifiBand::BAND_60GHZ:
+            return legacy_hal::WLAN_MAC_60_0_BAND;
+        default:
+            return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND |
+                    legacy_hal::WLAN_MAC_6_0_BAND | legacy_hal::WLAN_MAC_60_0_BAND);
+    }
+}
+
+uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask) {
+    uint32_t legacy_iface_mask = 0;
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_STA) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_STA);
+    }
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_SOFTAP);
+    }
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT);
+    }
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_GO);
+    }
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_NAN) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_NAN);
+    }
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_TDLS) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_TDLS);
+    }
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_MESH) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_MESH);
+    }
+    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_IBSS) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_IBSS);
+    }
+    return legacy_iface_mask;
+}
+
+uint32_t convertLegacyWifiInterfaceModeToHidl(uint32_t legacy_iface_mask) {
+    uint32_t hidl_iface_mask = 0;
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_STA)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_STA;
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_SOFTAP)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP;
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT;
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_GO)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO;
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_NAN)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_NAN;
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_TDLS)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_TDLS;
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_MESH)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_MESH;
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_IBSS)) {
+        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_IBSS;
+    }
+    return hidl_iface_mask;
+}
+
+uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask) {
+    uint32_t legacy_filter_mask = 0;
+    if (hidl_filter_mask & V1_5::IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) {
+        legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+    }
+    if (hidl_filter_mask & V1_5::IWifiChip::UsableChannelFilter::CONCURRENCY) {
+        legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
+    }
+    if (hidl_filter_mask & V1_6::IWifiChip::UsableChannelFilter::NAN_INSTANT_MODE) {
+        legacy_filter_mask |= WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE;
+    }
+    return legacy_filter_mask;
+}
+
+bool convertLegacyWifiUsableChannelToHidl(
+        const legacy_hal::wifi_usable_channel& legacy_usable_channel,
+        V1_6::WifiUsableChannel* hidl_usable_channel) {
+    if (!hidl_usable_channel) {
+        return false;
+    }
+    *hidl_usable_channel = {};
+    hidl_usable_channel->channel = legacy_usable_channel.freq;
+    hidl_usable_channel->channelBandwidth =
+            convertLegacyWifiChannelWidthToHidl(legacy_usable_channel.width);
+    hidl_usable_channel->ifaceModeMask =
+            convertLegacyWifiInterfaceModeToHidl(legacy_usable_channel.iface_mode_mask);
+
+    return true;
+}
+
+bool convertLegacyWifiUsableChannelsToHidl(
+        const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
+        std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels) {
+    if (!hidl_usable_channels) {
+        return false;
+    }
+    *hidl_usable_channels = {};
+    for (const auto& legacy_usable_channel : legacy_usable_channels) {
+        V1_6::WifiUsableChannel hidl_usable_channel;
+        if (!convertLegacyWifiUsableChannelToHidl(legacy_usable_channel, &hidl_usable_channel)) {
+            return false;
+        }
+        hidl_usable_channels->push_back(hidl_usable_channel);
+    }
+    return true;
+}
+
+bool convertLegacyWifiMacInfosToHidl(
+        const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+        std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+    if (!hidl_radio_mode_infos) {
+        return false;
+    }
+    *hidl_radio_mode_infos = {};
+
+    for (const auto& legacy_mac_info : legacy_mac_infos) {
+        V1_4::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+        if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info, &hidl_radio_mode_info)) {
+            return false;
+        }
+        hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
+    }
+    return true;
+}
+
+bool convertLegacyFeaturesToHidlStaCapabilities(uint64_t legacy_feature_set,
+                                                uint32_t legacy_logger_feature_set,
+                                                uint32_t* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *hidl_caps |= convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
+        }
+    }
+    for (const auto feature :
+         {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS, WIFI_FEATURE_RSSI_MONITOR,
+          WIFI_FEATURE_CONTROL_ROAMING, WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
+          WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS,
+          WIFI_FEATURE_TDLS_OFFCHANNEL, WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
+        if (feature & legacy_feature_set) {
+            *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
+        }
+    }
+    // There is no flag for this one in the legacy feature set. Adding it to the
+    // set because all the current devices support it.
+    *hidl_caps |= HidlStaIfaceCaps::APF;
+    return true;
+}
+
+bool convertLegacyApfCapabilitiesToHidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
+                                        StaApfPacketFilterCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->version = legacy_caps.version;
+    hidl_caps->maxLength = legacy_caps.max_len;
+    return true;
+}
+
+uint8_t convertHidlGscanReportEventFlagToLegacy(
+        StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
+    using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+    switch (hidl_flag) {
+        case HidlFlag::EACH_SCAN:
+            return REPORT_EVENTS_EACH_SCAN;
+        case HidlFlag::FULL_RESULTS:
+            return REPORT_EVENTS_FULL_RESULTS;
+        case HidlFlag::NO_BATCH:
+            return REPORT_EVENTS_NO_BATCH;
+    };
+    CHECK(false);
+}
+
+StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
+    switch (legacy_flag) {
+        case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
+            return StaScanDataFlagMask::INTERRUPTED;
+    };
+    CHECK(false) << "Unknown legacy flag: " << legacy_flag;
+    // To silence the compiler warning about reaching the end of non-void
+    // function.
+    return {};
+}
+
+bool convertLegacyGscanCapabilitiesToHidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+                                          StaBackgroundScanCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
+    hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
+    hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
+    hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
+    return true;
+}
+
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) {
+    switch (band) {
+        case V1_0::WifiBand::BAND_UNSPECIFIED:
+            return legacy_hal::WIFI_BAND_UNSPECIFIED;
+        case V1_0::WifiBand::BAND_24GHZ:
+            return legacy_hal::WIFI_BAND_BG;
+        case V1_0::WifiBand::BAND_5GHZ:
+            return legacy_hal::WIFI_BAND_A;
+        case V1_0::WifiBand::BAND_5GHZ_DFS:
+            return legacy_hal::WIFI_BAND_A_DFS;
+        case V1_0::WifiBand::BAND_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_A_WITH_DFS;
+        case V1_0::WifiBand::BAND_24GHZ_5GHZ:
+            return legacy_hal::WIFI_BAND_ABG;
+        case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
+    };
+    CHECK(false);
+}
+
+bool convertHidlGscanParamsToLegacy(const StaBackgroundScanParameters& hidl_scan_params,
+                                    legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
+    if (!legacy_scan_params) {
+        return false;
+    }
+    *legacy_scan_params = {};
+    legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
+    legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
+    legacy_scan_params->report_threshold_percent = hidl_scan_params.reportThresholdPercent;
+    legacy_scan_params->report_threshold_num_scans = hidl_scan_params.reportThresholdNumScans;
+    if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
+        return false;
+    }
+    legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
+    for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size(); bucket_idx++) {
+        const StaBackgroundScanBucketParameters& hidl_bucket_spec =
+                hidl_scan_params.buckets[bucket_idx];
+        legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
+                legacy_scan_params->buckets[bucket_idx];
+        if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+            return false;
+        }
+        legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
+        legacy_bucket_spec.band = convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
+        legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
+        legacy_bucket_spec.max_period = hidl_bucket_spec.exponentialMaxPeriodInMs;
+        legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
+        legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
+        legacy_bucket_spec.report_events = 0;
+        using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+        for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS, HidlFlag::NO_BATCH}) {
+            if (hidl_bucket_spec.eventReportScheme &
+                static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
+                legacy_bucket_spec.report_events |= convertHidlGscanReportEventFlagToLegacy(flag);
+            }
+        }
+        if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
+            return false;
+        }
+        legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
+        for (uint32_t freq_idx = 0; freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
+            legacy_bucket_spec.channels[freq_idx].channel = hidl_bucket_spec.frequencies[freq_idx];
+        }
+    }
+    return true;
+}
+
+bool convertLegacyIeToHidl(const legacy_hal::wifi_information_element& legacy_ie,
+                           WifiInformationElement* hidl_ie) {
+    if (!hidl_ie) {
+        return false;
+    }
+    *hidl_ie = {};
+    hidl_ie->id = legacy_ie.id;
+    hidl_ie->data = std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+    return true;
+}
+
+bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
+                               std::vector<WifiInformationElement>* hidl_ies) {
+    if (!ie_blob || !hidl_ies) {
+        return false;
+    }
+    *hidl_ies = {};
+    const uint8_t* ies_begin = ie_blob;
+    const uint8_t* ies_end = ie_blob + ie_blob_len;
+    const uint8_t* next_ie = ies_begin;
+    using wifi_ie = legacy_hal::wifi_information_element;
+    constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
+    // Each IE should atleast have the header (i.e |id| & |len| fields).
+    while (next_ie + kIeHeaderLen <= ies_end) {
+        const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
+        uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
+        if (next_ie + curr_ie_len > ies_end) {
+            LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
+                       << ", Curr IE len: " << curr_ie_len << ", IEs End: " << (void*)ies_end;
+            break;
+        }
+        WifiInformationElement hidl_ie;
+        if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
+            LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id << ", len: " << legacy_ie.len;
+            break;
+        }
+        hidl_ies->push_back(std::move(hidl_ie));
+        next_ie += curr_ie_len;
+    }
+    // Check if the blob has been fully consumed.
+    if (next_ie != ies_end) {
+        LOG(ERROR) << "Failed to fully parse IE blob. Next IE: " << (void*)next_ie
+                   << ", IEs End: " << (void*)ies_end;
+    }
+    return true;
+}
+
+bool convertLegacyGscanResultToHidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
+                                    bool has_ie_data, StaScanResult* hidl_scan_result) {
+    if (!hidl_scan_result) {
+        return false;
+    }
+    *hidl_scan_result = {};
+    hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
+    hidl_scan_result->ssid = std::vector<uint8_t>(
+            legacy_scan_result.ssid,
+            legacy_scan_result.ssid +
+                    strnlen(legacy_scan_result.ssid, sizeof(legacy_scan_result.ssid) - 1));
+    memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
+           hidl_scan_result->bssid.size());
+    hidl_scan_result->frequency = legacy_scan_result.channel;
+    hidl_scan_result->rssi = legacy_scan_result.rssi;
+    hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
+    hidl_scan_result->capability = legacy_scan_result.capability;
+    if (has_ie_data) {
+        std::vector<WifiInformationElement> ies;
+        if (!convertLegacyIeBlobToHidl(reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
+                                       legacy_scan_result.ie_length, &ies)) {
+            return false;
+        }
+        hidl_scan_result->informationElements = std::move(ies);
+    }
+    return true;
+}
+
+bool convertLegacyCachedGscanResultsToHidl(
+        const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
+        StaScanData* hidl_scan_data) {
+    if (!hidl_scan_data) {
+        return false;
+    }
+    *hidl_scan_data = {};
+    hidl_scan_data->flags = 0;
+    for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
+        if (legacy_cached_scan_result.flags & flag) {
+            hidl_scan_data->flags |= static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
+                    convertLegacyGscanDataFlagToHidl(flag));
+        }
+    }
+    hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
+
+    CHECK(legacy_cached_scan_result.num_results >= 0 &&
+          legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
+    std::vector<StaScanResult> hidl_scan_results;
+    for (int32_t result_idx = 0; result_idx < legacy_cached_scan_result.num_results; result_idx++) {
+        StaScanResult hidl_scan_result;
+        if (!convertLegacyGscanResultToHidl(legacy_cached_scan_result.results[result_idx], false,
+                                            &hidl_scan_result)) {
+            return false;
+        }
+        hidl_scan_results.push_back(hidl_scan_result);
+    }
+    hidl_scan_data->results = std::move(hidl_scan_results);
+    return true;
+}
+
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+        const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
+        std::vector<StaScanData>* hidl_scan_datas) {
+    if (!hidl_scan_datas) {
+        return false;
+    }
+    *hidl_scan_datas = {};
+    for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
+        StaScanData hidl_scan_data;
+        if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result, &hidl_scan_data)) {
+            return false;
+        }
+        hidl_scan_datas->push_back(hidl_scan_data);
+    }
+    return true;
+}
+
+WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(legacy_hal::wifi_tx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::TX_PKT_FATE_ACKED:
+            return WifiDebugTxPacketFate::ACKED;
+        case legacy_hal::TX_PKT_FATE_SENT:
+            return WifiDebugTxPacketFate::SENT;
+        case legacy_hal::TX_PKT_FATE_FW_QUEUED:
+            return WifiDebugTxPacketFate::FW_QUEUED;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugTxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugTxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugTxPacketFate::DRV_QUEUED;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugTxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugTxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(legacy_hal::wifi_rx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::RX_PKT_FATE_SUCCESS:
+            return WifiDebugRxPacketFate::SUCCESS;
+        case legacy_hal::RX_PKT_FATE_FW_QUEUED:
+            return WifiDebugRxPacketFate::FW_QUEUED;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
+            return WifiDebugRxPacketFate::FW_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugRxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugRxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugRxPacketFate::DRV_QUEUED;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
+            return WifiDebugRxPacketFate::DRV_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugRxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugRxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
+        legacy_hal::frame_type type) {
+    switch (type) {
+        case legacy_hal::FRAME_TYPE_UNKNOWN:
+            return WifiDebugPacketFateFrameType::UNKNOWN;
+        case legacy_hal::FRAME_TYPE_ETHERNET_II:
+            return WifiDebugPacketFateFrameType::ETHERNET_II;
+        case legacy_hal::FRAME_TYPE_80211_MGMT:
+            return WifiDebugPacketFateFrameType::MGMT_80211;
+    };
+    CHECK(false) << "Unknown legacy frame type: " << type;
+}
+
+bool convertLegacyDebugPacketFateFrameToHidl(const legacy_hal::frame_info& legacy_frame,
+                                             WifiDebugPacketFateFrameInfo* hidl_frame) {
+    if (!hidl_frame) {
+        return false;
+    }
+    *hidl_frame = {};
+    hidl_frame->frameType = convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
+    hidl_frame->frameLen = legacy_frame.frame_len;
+    hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
+    hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
+    const uint8_t* frame_begin =
+            reinterpret_cast<const uint8_t*>(legacy_frame.frame_content.ethernet_ii_bytes);
+    hidl_frame->frameContent =
+            std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
+    return true;
+}
+
+bool convertLegacyDebugTxPacketFateToHidl(const legacy_hal::wifi_tx_report& legacy_fate,
+                                          WifiDebugTxPacketFateReport* hidl_fate) {
+    if (!hidl_fate) {
+        return false;
+    }
+    *hidl_fate = {};
+    hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf, &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+        const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+        std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
+    if (!hidl_fates) {
+        return false;
+    }
+    *hidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugTxPacketFateReport hidl_fate;
+        if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+            return false;
+        }
+        hidl_fates->push_back(hidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyDebugRxPacketFateToHidl(const legacy_hal::wifi_rx_report& legacy_fate,
+                                          WifiDebugRxPacketFateReport* hidl_fate) {
+    if (!hidl_fate) {
+        return false;
+    }
+    *hidl_fate = {};
+    hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf, &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+        const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+        std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
+    if (!hidl_fates) {
+        return false;
+    }
+    *hidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugRxPacketFateReport hidl_fate;
+        if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+            return false;
+        }
+        hidl_fates->push_back(hidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyLinkLayerRadioStatsToHidl(
+        const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
+        V1_6::StaLinkLayerRadioStats* hidl_radio_stat) {
+    if (!hidl_radio_stat) {
+        return false;
+    }
+    *hidl_radio_stat = {};
+
+    hidl_radio_stat->radioId = legacy_radio_stat.stats.radio;
+    hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
+    hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
+    hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
+    hidl_radio_stat->V1_0.onTimeInMsForScan = legacy_radio_stat.stats.on_time_scan;
+    hidl_radio_stat->V1_0.txTimeInMsPerLevel = legacy_radio_stat.tx_time_per_levels;
+    hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
+    hidl_radio_stat->onTimeInMsForBgScan = legacy_radio_stat.stats.on_time_gscan;
+    hidl_radio_stat->onTimeInMsForRoamScan = legacy_radio_stat.stats.on_time_roam_scan;
+    hidl_radio_stat->onTimeInMsForPnoScan = legacy_radio_stat.stats.on_time_pno_scan;
+    hidl_radio_stat->onTimeInMsForHs20Scan = legacy_radio_stat.stats.on_time_hs20;
+
+    std::vector<V1_6::WifiChannelStats> hidl_channel_stats;
+
+    for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
+        V1_6::WifiChannelStats hidl_channel_stat;
+        hidl_channel_stat.onTimeInMs = channel_stat.on_time;
+        hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
+        /*
+         * TODO once b/119142899 is fixed,
+         * replace below code with convertLegacyWifiChannelInfoToHidl()
+         */
+        hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
+        hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
+        hidl_channel_stat.channel.centerFreq0 = channel_stat.channel.center_freq0;
+        hidl_channel_stat.channel.centerFreq1 = channel_stat.channel.center_freq1;
+        hidl_channel_stats.push_back(hidl_channel_stat);
+    }
+
+    hidl_radio_stat->channelStats = hidl_channel_stats;
+
+    return true;
+}
+
+bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
+                                       V1_6::StaLinkLayerStats* hidl_stats) {
+    if (!hidl_stats) {
+        return false;
+    }
+    *hidl_stats = {};
+    // iface legacy_stats conversion.
+    hidl_stats->iface.V1_0.beaconRx = legacy_stats.iface.beacon_rx;
+    hidl_stats->iface.V1_0.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+    hidl_stats->iface.V1_0.wmeBePktStats.rxMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+    hidl_stats->iface.V1_0.wmeBePktStats.txMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+    hidl_stats->iface.V1_0.wmeBePktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+    hidl_stats->iface.V1_0.wmeBePktStats.retries =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
+    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
+    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
+    hidl_stats->iface.wmeBeContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
+    hidl_stats->iface.V1_0.wmeBkPktStats.rxMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+    hidl_stats->iface.V1_0.wmeBkPktStats.txMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+    hidl_stats->iface.V1_0.wmeBkPktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+    hidl_stats->iface.V1_0.wmeBkPktStats.retries =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
+    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
+    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
+    hidl_stats->iface.wmeBkContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
+    hidl_stats->iface.V1_0.wmeViPktStats.rxMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+    hidl_stats->iface.V1_0.wmeViPktStats.txMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+    hidl_stats->iface.V1_0.wmeViPktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+    hidl_stats->iface.V1_0.wmeViPktStats.retries =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
+    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
+    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
+    hidl_stats->iface.wmeViContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
+    hidl_stats->iface.V1_0.wmeVoPktStats.rxMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+    hidl_stats->iface.V1_0.wmeVoPktStats.txMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+    hidl_stats->iface.V1_0.wmeVoPktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+    hidl_stats->iface.V1_0.wmeVoPktStats.retries =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
+    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
+    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
+    hidl_stats->iface.wmeVoContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
+    hidl_stats->iface.timeSliceDutyCycleInPercent =
+            legacy_stats.iface.info.time_slicing_duty_cycle_percent;
+    // peer info legacy_stats conversion.
+    std::vector<V1_6::StaPeerInfo> hidl_peers_info_stats;
+    for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
+        V1_6::StaPeerInfo hidl_peer_info_stats;
+        if (!convertLegacyPeerInfoStatsToHidl(legacy_peer_info_stats, &hidl_peer_info_stats)) {
+            return false;
+        }
+        hidl_peers_info_stats.push_back(hidl_peer_info_stats);
+    }
+    hidl_stats->iface.peers = hidl_peers_info_stats;
+    // radio legacy_stats conversion.
+    std::vector<V1_6::StaLinkLayerRadioStats> hidl_radios_stats;
+    for (const auto& legacy_radio_stats : legacy_stats.radios) {
+        V1_6::StaLinkLayerRadioStats hidl_radio_stats;
+        if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats, &hidl_radio_stats)) {
+            return false;
+        }
+        hidl_radios_stats.push_back(hidl_radio_stats);
+    }
+    hidl_stats->radios = hidl_radios_stats;
+    // Timestamp in the HAL wrapper here since it's not provided in the legacy
+    // HAL API.
+    hidl_stats->timeStampInMs = uptimeMillis();
+    return true;
+}
+
+bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+                                      V1_6::StaPeerInfo* hidl_peer_info_stats) {
+    if (!hidl_peer_info_stats) {
+        return false;
+    }
+    *hidl_peer_info_stats = {};
+    hidl_peer_info_stats->staCount = legacy_peer_info_stats.peer_info.bssload.sta_count;
+    hidl_peer_info_stats->chanUtil = legacy_peer_info_stats.peer_info.bssload.chan_util;
+
+    std::vector<V1_6::StaRateStat> hidlRateStats;
+    for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
+        V1_6::StaRateStat rateStat;
+        if (!convertLegacyWifiRateInfoToHidl(legacy_rate_stats.rate, &rateStat.rateInfo)) {
+            return false;
+        }
+        rateStat.txMpdu = legacy_rate_stats.tx_mpdu;
+        rateStat.rxMpdu = legacy_rate_stats.rx_mpdu;
+        rateStat.mpduLost = legacy_rate_stats.mpdu_lost;
+        rateStat.retries = legacy_rate_stats.retries;
+        hidlRateStats.push_back(rateStat);
+    }
+    hidl_peer_info_stats->rateStats = hidlRateStats;
+    return true;
+}
+
+bool convertLegacyRoamingCapabilitiesToHidl(
+        const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+        StaRoamingCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
+    hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
+    return true;
+}
+
+bool convertHidlRoamingConfigToLegacy(const StaRoamingConfig& hidl_config,
+                                      legacy_hal::wifi_roaming_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
+        hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
+        return false;
+    }
+    legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
+    uint32_t i = 0;
+    for (const auto& bssid : hidl_config.bssidBlacklist) {
+        CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
+        memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
+    }
+    legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
+    i = 0;
+    for (const auto& ssid : hidl_config.ssidWhitelist) {
+        CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
+        legacy_config->whitelist_ssid[i].length = ssid.size();
+        memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(), ssid.size());
+        i++;
+    }
+    return true;
+}
+
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(StaRoamingState state) {
+    switch (state) {
+        case StaRoamingState::ENABLED:
+            return legacy_hal::ROAMING_ENABLE;
+        case StaRoamingState::DISABLED:
+            return legacy_hal::ROAMING_DISABLE;
+    };
+    CHECK(false);
+}
+
+legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
+    switch (type) {
+        case NanMatchAlg::MATCH_ONCE:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
+        case NanMatchAlg::MATCH_CONTINUOUS:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+        case NanMatchAlg::MATCH_NEVER:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(NanPublishType type) {
+    switch (type) {
+        case NanPublishType::UNSOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
+        case NanPublishType::SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
+        case NanPublishType::UNSOLICITED_SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
+    switch (type) {
+        case NanTxType::BROADCAST:
+            return legacy_hal::NAN_TX_TYPE_BROADCAST;
+        case NanTxType::UNICAST:
+            return legacy_hal::NAN_TX_TYPE_UNICAST;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(NanSubscribeType type) {
+    switch (type) {
+        case NanSubscribeType::PASSIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
+        case NanSubscribeType::ACTIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
+    switch (type) {
+        case NanSrfType::BLOOM_FILTER:
+            return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
+        case NanSrfType::PARTIAL_MAC_ADDR:
+            return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
+        NanDataPathChannelCfg type) {
+    switch (type) {
+        case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
+            return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
+        case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
+        case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
+    }
+    CHECK(false);
+}
+
+NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
+    switch (type) {
+        case legacy_hal::NAN_STATUS_SUCCESS:
+            return NanStatusType::SUCCESS;
+        case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
+            return NanStatusType::INTERNAL_FAILURE;
+        case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
+            return NanStatusType::PROTOCOL_FAILURE;
+        case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
+            return NanStatusType::INVALID_SESSION_ID;
+        case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
+            return NanStatusType::NO_RESOURCES_AVAILABLE;
+        case legacy_hal::NAN_STATUS_INVALID_PARAM:
+            return NanStatusType::INVALID_ARGS;
+        case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
+            return NanStatusType::INVALID_PEER_ID;
+        case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
+            return NanStatusType::INVALID_NDP_ID;
+        case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
+            return NanStatusType::NAN_NOT_ALLOWED;
+        case legacy_hal::NAN_STATUS_NO_OTA_ACK:
+            return NanStatusType::NO_OTA_ACK;
+        case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
+            return NanStatusType::ALREADY_ENABLED;
+        case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
+            return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
+        case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
+            return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+    }
+    CHECK(false);
+}
+
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
+                            WifiNanStatus* wifiNanStatus) {
+    wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
+    wifiNanStatus->description = safeConvertChar(str, max_len);
+}
+
+bool convertHidlNanEnableRequestToLegacy(const V1_4::NanEnableRequest& hidl_request,
+                                         legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->config_2dot4g_support = 1;
+    legacy_request->support_2dot4g_val =
+            hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_support_5g = 1;
+    legacy_request->support_5g_val =
+            hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_hop_count_limit = 1;
+    legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
+    legacy_request->master_pref = hidl_request.configParams.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+            hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->sid_beacon_val =
+            (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+            (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+            (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+            (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val = hidl_request.configParams.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+            hidl_request.configParams.macAddressRandomizationIntervalSec;
+    legacy_request->config_2dot4g_rssi_close = 1;
+    if (hidl_request.configParams.bandSpecificConfig.size() != 3) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "bandSpecificConfig.size() != 3";
+        return false;
+    }
+    legacy_request->rssi_close_2dot4g_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .rssiClose;
+    legacy_request->config_2dot4g_rssi_middle = 1;
+    legacy_request->rssi_middle_2dot4g_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .rssiMiddle;
+    legacy_request->config_2dot4g_rssi_proximity = 1;
+    legacy_request->rssi_proximity_2dot4g_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .rssiCloseProximity;
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .discoveryWindowIntervalVal;
+    legacy_request->config_5g_rssi_close = 1;
+    legacy_request->rssi_close_5g_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .rssiClose;
+    legacy_request->config_5g_rssi_middle = 1;
+    legacy_request->rssi_middle_5g_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .rssiMiddle;
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .rssiCloseProximity;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .scanPeriodSec;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .discoveryWindowIntervalVal;
+    if (hidl_request.debugConfigs.validClusterIdVals) {
+        legacy_request->cluster_low = hidl_request.debugConfigs.clusterIdBottomRangeVal;
+        legacy_request->cluster_high = hidl_request.debugConfigs.clusterIdTopRangeVal;
+    } else {  // need 'else' since not configurable in legacy HAL
+        legacy_request->cluster_low = 0x0000;
+        legacy_request->cluster_high = 0xFFFF;
+    }
+    legacy_request->config_intf_addr = hidl_request.debugConfigs.validIntfAddrVal;
+    memcpy(legacy_request->intf_addr_val, hidl_request.debugConfigs.intfAddrVal.data(), 6);
+    legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
+    legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
+    legacy_request->config_random_factor_force =
+            hidl_request.debugConfigs.validRandomFactorForceVal;
+    legacy_request->random_factor_force_val = hidl_request.debugConfigs.randomFactorForceVal;
+    legacy_request->config_hop_count_force = hidl_request.debugConfigs.validHopCountForceVal;
+    legacy_request->hop_count_force_val = hidl_request.debugConfigs.hopCountForceVal;
+    legacy_request->config_24g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_24g_val =
+            hidl_request.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_5g_val =
+            hidl_request.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_2dot4g_val =
+            hidl_request.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_5g_val =
+            hidl_request.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_2dot4g_val =
+            hidl_request.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_5g_val =
+            hidl_request.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+
+    /* TODO: b/145609058
+     * Missing updates needed to legacy_hal::NanEnableRequest and conversion to
+     * it for 6GHz band */
+
+    return true;
+}
+
+bool convertHidlNanEnableRequest_1_6ToLegacy(const V1_4::NanEnableRequest& hidl_request1,
+                                             const NanConfigRequestSupplemental& hidl_request2,
+                                             legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanEnableRequest_1_6ToLegacy: null legacy_request";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval = hidl_request2.V1_5.V1_2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.V1_5.V1_2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+            hidl_request2.V1_5.V1_2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = hidl_request2.V1_5.V1_2.enableRanging;
+
+    legacy_request->config_enable_instant_mode = 1;
+    legacy_request->enable_instant_mode = hidl_request2.V1_5.enableInstantCommunicationMode;
+    legacy_request->config_instant_mode_channel = 1;
+    legacy_request->instant_mode_channel = hidl_request2.instantModeChannel;
+
+    return true;
+}
+
+bool convertHidlNanConfigRequest_1_6ToLegacy(const V1_4::NanConfigRequest& hidl_request1,
+                                             const NanConfigRequestSupplemental& hidl_request2,
+                                             legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanConfigRequest_1_6ToLegacy: null legacy_request";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval = hidl_request2.V1_5.V1_2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.V1_5.V1_2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+            hidl_request2.V1_5.V1_2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = hidl_request2.V1_5.V1_2.enableRanging;
+
+    return true;
+
+    legacy_request->config_enable_instant_mode = 1;
+    legacy_request->enable_instant_mode = hidl_request2.V1_5.enableInstantCommunicationMode;
+    legacy_request->config_instant_mode_channel = 1;
+    legacy_request->instant_mode_channel = hidl_request2.instantModeChannel;
+
+    return true;
+}
+
+bool convertHidlNanPublishRequestToLegacy(const V1_6::NanPublishRequest& hidl_request,
+                                          legacy_hal::NanPublishRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
+    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
+                      "too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->publish_match_indicator =
+            convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+            hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter, hidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter, hidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+            hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->recv_indication_cfg |= 0x8;
+    legacy_request->cipher_type = (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+
+    legacy_request->scid_len = hidl_request.baseConfigs.securityConfig.scid.size();
+    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: scid_len too large";
+        return false;
+    }
+    memcpy(legacy_request->scid, hidl_request.baseConfigs.securityConfig.scid.data(),
+           legacy_request->scid_len);
+
+    if (hidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+                hidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                hidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+            (hidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+
+    legacy_request->sdea_params.ranging_state = hidl_request.baseConfigs.rangingRequired
+                                                        ? legacy_hal::NAN_RANGING_ENABLE
+                                                        : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec =
+            hidl_request.baseConfigs.rangingIntervalMsec;
+    legacy_request->ranging_cfg.config_ranging_indications =
+            hidl_request.baseConfigs.configRangingIndications;
+    legacy_request->ranging_cfg.distance_ingress_mm =
+            hidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm = hidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response = hidl_request.baseConfigs.rangingRequired
+                                                    ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+                                                    : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->publish_type = convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
+    legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
+    legacy_request->service_responder_policy = hidl_request.autoAcceptDataPathRequests
+                                                       ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
+                                                       : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
+
+    return true;
+}
+
+bool convertHidlNanSubscribeRequestToLegacy(const V1_0::NanSubscribeRequest& hidl_request,
+                                            legacy_hal::NanSubscribeRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
+    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->subscribe_match_indicator =
+            convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+            hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter, hidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter, hidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+            hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->cipher_type = (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+    if (hidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+                hidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                hidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+            (hidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->sdea_params.ranging_state = hidl_request.baseConfigs.rangingRequired
+                                                        ? legacy_hal::NAN_RANGING_ENABLE
+                                                        : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec =
+            hidl_request.baseConfigs.rangingIntervalMsec;
+    legacy_request->ranging_cfg.config_ranging_indications =
+            hidl_request.baseConfigs.configRangingIndications;
+    legacy_request->ranging_cfg.distance_ingress_mm =
+            hidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm = hidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response = hidl_request.baseConfigs.rangingRequired
+                                                    ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+                                                    : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->subscribe_type =
+            convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
+    legacy_request->serviceResponseFilter = convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
+    legacy_request->serviceResponseInclude = hidl_request.srfRespondIfInAddressSet
+                                                     ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
+                                                     : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+    legacy_request->useServiceResponseFilter =
+            hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF : legacy_hal::NAN_DO_NOT_USE_SRF;
+    legacy_request->ssiRequiredForMatchIndication =
+            hidl_request.isSsiRequiredForMatch ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
+                                               : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+    legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
+    if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "num_intf_addr_present - too many";
+        return false;
+    }
+    for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
+        memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(), 6);
+    }
+
+    return true;
+}
+
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+        const NanTransmitFollowupRequest& hidl_request,
+        legacy_hal::NanTransmitFollowupRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
+    legacy_request->requestor_instance_id = hidl_request.peerId;
+    memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
+    legacy_request->priority = hidl_request.isHighPriority ? legacy_hal::NAN_TX_PRIORITY_HIGH
+                                                           : legacy_hal::NAN_TX_PRIORITY_NORMAL;
+    legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
+                                        ? legacy_hal::NAN_TRANSMIT_IN_DW
+                                        : legacy_hal::NAN_TRANSMIT_IN_FAW;
+    legacy_request->service_specific_info_len = hidl_request.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info, hidl_request.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+            hidl_request.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->recv_indication_cfg = hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
+
+    return true;
+}
+
+bool convertHidlNanConfigRequestToLegacy(const V1_4::NanConfigRequest& hidl_request,
+                                         legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
+    // defaults
+    legacy_request->master_pref = hidl_request.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+            hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->sid_beacon = (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+                                 (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+            (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+            (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+            hidl_request.macAddressRandomizationIntervalSec;
+    /* TODO : missing
+    legacy_request->config_2dot4g_rssi_close = 1;
+    legacy_request->rssi_close_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
+    legacy_request->config_2dot4g_rssi_middle = 1;
+    legacy_request->rssi_middle_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
+    legacy_request->config_2dot4g_rssi_proximity = 1;
+    legacy_request->rssi_proximity_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
+    */
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .discoveryWindowIntervalVal;
+    /* TODO: missing
+    legacy_request->config_5g_rssi_close = 1;
+    legacy_request->rssi_close_5g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
+    legacy_request->config_5g_rssi_middle = 1;
+    legacy_request->rssi_middle_5g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
+    */
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].rssiCloseProximity;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .discoveryWindowIntervalVal;
+    /* TODO: b/145609058
+     * Missing updates needed to legacy_hal::NanConfigRequest and conversion to
+     * it for 6GHz band */
+
+    return true;
+}
+
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+        const V1_0::NanInitiateDataPathRequest& hidl_request,
+        legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->requestor_instance_id = hidl_request.peerId;
+    memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
+    legacy_request->channel_request_type =
+            convertHidlNanDataPathChannelCfgToLegacy(hidl_request.channelRequestType);
+    legacy_request->channel = hidl_request.channel;
+    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+            (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+
+    return true;
+}
+
+bool convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(
+        const V1_6::NanInitiateDataPathRequest& hidl_request,
+        legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->requestor_instance_id = hidl_request.peerId;
+    memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
+    legacy_request->channel_request_type =
+            convertHidlNanDataPathChannelCfgToLegacy(hidl_request.channelRequestType);
+    legacy_request->channel = hidl_request.channel;
+    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+            (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+    legacy_request->scid_len = hidl_request.securityConfig.scid.size();
+    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: scid_len too large";
+        return false;
+    }
+    memcpy(legacy_request->scid, hidl_request.securityConfig.scid.data(), legacy_request->scid_len);
+
+    return true;
+}
+
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+        const V1_0::NanRespondToDataPathIndicationRequest& hidl_request,
+        legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->rsp_code = hidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+                                                          : legacy_hal::NAN_DP_REQUEST_REJECT;
+    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
+    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+            (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+
+    return true;
+}
+
+bool convertHidlNanDataPathIndicationResponse_1_6ToLegacy(
+        const V1_6::NanRespondToDataPathIndicationRequest& hidl_request,
+        legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->rsp_code = hidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+                                                          : legacy_hal::NAN_DP_REQUEST_REJECT;
+    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
+    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+            (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+    legacy_request->scid_len = hidl_request.securityConfig.scid.size();
+    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: scid_len too large";
+        return false;
+    }
+    memcpy(legacy_request->scid, hidl_request.securityConfig.scid.data(), legacy_request->scid_len);
+
+    return true;
+}
+
+bool convertLegacyNanResponseHeaderToHidl(const legacy_hal::NanResponseMsg& legacy_response,
+                                          WifiNanStatus* wifiNanStatus) {
+    if (!wifiNanStatus) {
+        LOG(ERROR) << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
+        return false;
+    }
+    *wifiNanStatus = {};
+
+    convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
+                           sizeof(legacy_response.nan_error), wifiNanStatus);
+    return true;
+}
+
+bool convertLegacyNanCapabilitiesResponseToHidl(const legacy_hal::NanCapabilities& legacy_response,
+                                                V1_6::NanCapabilities* hidl_response) {
+    if (!hidl_response) {
+        LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
+                      "hidl_response is null";
+        return false;
+    }
+    *hidl_response = {};
+
+    hidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters;
+    hidl_response->maxPublishes = legacy_response.max_publishes;
+    hidl_response->maxSubscribes = legacy_response.max_subscribes;
+    hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
+    hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
+    hidl_response->maxTotalMatchFilterLen = legacy_response.max_total_match_filter_len;
+    hidl_response->maxServiceSpecificInfoLen = legacy_response.max_service_specific_info_len;
+    hidl_response->maxExtendedServiceSpecificInfoLen =
+            legacy_response.max_sdea_service_specific_info_len;
+    hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
+    hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
+    hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
+    hidl_response->maxQueuedTransmitFollowupMsgs =
+            legacy_response.max_queued_transmit_followup_msgs;
+    hidl_response->maxSubscribeInterfaceAddresses = legacy_response.max_subscribe_address;
+    hidl_response->supportedCipherSuites = legacy_response.cipher_suites_supported;
+    hidl_response->instantCommunicationModeSupportFlag = legacy_response.is_instant_mode_supported;
+
+    return true;
+}
+
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    V1_6::NanMatchInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    hidl_ind->peerId = legacy_ind.requestor_instance_id;
+    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+    hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.service_specific_info,
+            legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
+    hidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.sdea_service_specific_info,
+            legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
+    hidl_ind->matchFilter =
+            std::vector<uint8_t>(legacy_ind.sdf_match_filter,
+                                 legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
+    hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
+    hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
+    hidl_ind->rssiValue = legacy_ind.rssi_value;
+    hidl_ind->peerCipherType = (V1_6::NanCipherSuiteType)legacy_ind.peer_cipher_type;
+    hidl_ind->peerRequiresSecurityEnabledInNdp =
+            legacy_ind.peer_sdea_params.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+    hidl_ind->peerRequiresRanging =
+            legacy_ind.peer_sdea_params.ranging_state == legacy_hal::NAN_RANGING_ENABLE;
+    hidl_ind->rangingMeasurementInMm = legacy_ind.range_info.range_measurement_mm;
+    hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
+    hidl_ind->scid = std::vector<uint8_t>(legacy_ind.scid, legacy_ind.scid + legacy_ind.scid_len);
+    return true;
+}
+
+bool convertLegacyNanFollowupIndToHidl(const legacy_hal::NanFollowupInd& legacy_ind,
+                                       NanFollowupReceivedInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    hidl_ind->peerId = legacy_ind.requestor_instance_id;
+    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+    hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
+    hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.service_specific_info,
+            legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
+    hidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.sdea_service_specific_info,
+            legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
+
+    return true;
+}
+
+bool convertLegacyNanDataPathRequestIndToHidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
+                                              NanDataPathRequestInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
+    hidl_ind->peerDiscMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
+    hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
+    hidl_ind->securityRequired =
+            legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+    hidl_ind->appInfo = std::vector<uint8_t>(
+            legacy_ind.app_info.ndp_app_info,
+            legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
+
+    return true;
+}
+
+bool convertLegacyNdpChannelInfoToHidl(const legacy_hal::NanChannelInfo& legacy_struct,
+                                       V1_6::NanDataPathChannelInfo* hidl_struct) {
+    if (!hidl_struct) {
+        LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
+        return false;
+    }
+    *hidl_struct = {};
+
+    hidl_struct->channelFreq = legacy_struct.channel;
+    hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
+            (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
+    hidl_struct->numSpatialStreams = legacy_struct.nss;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+                                              V1_6::NanDataPathConfirmInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
+    hidl_ind->V1_0.dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
+    hidl_ind->V1_0.peerNdiMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
+    hidl_ind->V1_0.appInfo = std::vector<uint8_t>(
+            legacy_ind.app_info.ndp_app_info,
+            legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
+    hidl_ind->V1_0.status.status = convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
+    hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
+
+    std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        V1_6::NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+        const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+        V1_6::NanDataPathScheduleUpdateInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
+                      "hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->peerDiscoveryAddress = hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
+    std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        V1_6::NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+    std::vector<uint32_t> ndpInstanceIds;
+    for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+        ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+    }
+    hidl_ind->ndpInstanceIds = ndpInstanceIds;
+
+    return true;
+}
+
+legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
+    switch (type) {
+        case RttType::ONE_SIDED:
+            return legacy_hal::RTT_TYPE_1_SIDED;
+        case RttType::TWO_SIDED:
+            return legacy_hal::RTT_TYPE_2_SIDED;
+    };
+    CHECK(false);
+}
+
+RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
+    switch (type) {
+        case legacy_hal::RTT_TYPE_1_SIDED:
+            return RttType::ONE_SIDED;
+        case legacy_hal::RTT_TYPE_2_SIDED:
+            return RttType::TWO_SIDED;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
+    switch (type) {
+        case RttPeerType::AP:
+            return legacy_hal::RTT_PEER_AP;
+        case RttPeerType::STA:
+            return legacy_hal::RTT_PEER_STA;
+        case RttPeerType::P2P_GO:
+            return legacy_hal::RTT_PEER_P2P_GO;
+        case RttPeerType::P2P_CLIENT:
+            return legacy_hal::RTT_PEER_P2P_CLIENT;
+        case RttPeerType::NAN:
+            return legacy_hal::RTT_PEER_NAN;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(WifiChannelWidthInMhz type) {
+    switch (type) {
+        case WifiChannelWidthInMhz::WIDTH_20:
+            return legacy_hal::WIFI_CHAN_WIDTH_20;
+        case WifiChannelWidthInMhz::WIDTH_40:
+            return legacy_hal::WIFI_CHAN_WIDTH_40;
+        case WifiChannelWidthInMhz::WIDTH_80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80;
+        case WifiChannelWidthInMhz::WIDTH_160:
+            return legacy_hal::WIFI_CHAN_WIDTH_160;
+        case WifiChannelWidthInMhz::WIDTH_80P80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80P80;
+        case WifiChannelWidthInMhz::WIDTH_5:
+            return legacy_hal::WIFI_CHAN_WIDTH_5;
+        case WifiChannelWidthInMhz::WIDTH_10:
+            return legacy_hal::WIFI_CHAN_WIDTH_10;
+        case V1_6::WifiChannelWidthInMhz::WIDTH_320:
+            return legacy_hal::WIFI_CHAN_WIDTH_320;
+        case WifiChannelWidthInMhz::WIDTH_INVALID:
+            return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
+    };
+    CHECK(false);
+}
+
+V1_6::WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+        legacy_hal::wifi_channel_width type) {
+    switch (type) {
+        case legacy_hal::WIFI_CHAN_WIDTH_20:
+            return WifiChannelWidthInMhz::WIDTH_20;
+        case legacy_hal::WIFI_CHAN_WIDTH_40:
+            return WifiChannelWidthInMhz::WIDTH_40;
+        case legacy_hal::WIFI_CHAN_WIDTH_80:
+            return WifiChannelWidthInMhz::WIDTH_80;
+        case legacy_hal::WIFI_CHAN_WIDTH_160:
+            return WifiChannelWidthInMhz::WIDTH_160;
+        case legacy_hal::WIFI_CHAN_WIDTH_80P80:
+            return WifiChannelWidthInMhz::WIDTH_80P80;
+        case legacy_hal::WIFI_CHAN_WIDTH_5:
+            return WifiChannelWidthInMhz::WIDTH_5;
+        case legacy_hal::WIFI_CHAN_WIDTH_10:
+            return WifiChannelWidthInMhz::WIDTH_10;
+        case legacy_hal::WIFI_CHAN_WIDTH_320:
+            return V1_6::WifiChannelWidthInMhz::WIDTH_320;
+        default:
+            return WifiChannelWidthInMhz::WIDTH_INVALID;
+    };
+}
+
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(V1_6::RttPreamble type) {
+    switch (type) {
+        case V1_6::RttPreamble::LEGACY:
+            return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
+        case V1_6::RttPreamble::HT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_HT;
+        case V1_6::RttPreamble::VHT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
+        case V1_6::RttPreamble::HE:
+            return legacy_hal::WIFI_RTT_PREAMBLE_HE;
+        case V1_6::RttPreamble::EHT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_EHT;
+    };
+    CHECK(false);
+}
+
+V1_6::RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
+            return V1_6::RttPreamble::LEGACY;
+        case legacy_hal::WIFI_RTT_PREAMBLE_HT:
+            return V1_6::RttPreamble::HT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
+            return V1_6::RttPreamble::VHT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_HE:
+            return V1_6::RttPreamble::HE;
+        case legacy_hal::WIFI_RTT_PREAMBLE_EHT:
+            return V1_6::RttPreamble::EHT;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
+    switch (type) {
+        case RttBw::BW_5MHZ:
+            return legacy_hal::WIFI_RTT_BW_5;
+        case RttBw::BW_10MHZ:
+            return legacy_hal::WIFI_RTT_BW_10;
+        case RttBw::BW_20MHZ:
+            return legacy_hal::WIFI_RTT_BW_20;
+        case RttBw::BW_40MHZ:
+            return legacy_hal::WIFI_RTT_BW_40;
+        case RttBw::BW_80MHZ:
+            return legacy_hal::WIFI_RTT_BW_80;
+        case RttBw::BW_160MHZ:
+            return legacy_hal::WIFI_RTT_BW_160;
+        case RttBw::BW_320MHZ:
+            return legacy_hal::WIFI_RTT_BW_320;
+    };
+    CHECK(false);
+}
+
+RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_BW_5:
+            return RttBw::BW_5MHZ;
+        case legacy_hal::WIFI_RTT_BW_10:
+            return RttBw::BW_10MHZ;
+        case legacy_hal::WIFI_RTT_BW_20:
+            return RttBw::BW_20MHZ;
+        case legacy_hal::WIFI_RTT_BW_40:
+            return RttBw::BW_40MHZ;
+        case legacy_hal::WIFI_RTT_BW_80:
+            return RttBw::BW_80MHZ;
+        case legacy_hal::WIFI_RTT_BW_160:
+            return RttBw::BW_160MHZ;
+        case legacy_hal::WIFI_RTT_BW_320:
+            return RttBw::BW_320MHZ;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(RttMotionPattern type) {
+    switch (type) {
+        case RttMotionPattern::NOT_EXPECTED:
+            return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
+        case RttMotionPattern::EXPECTED:
+            return legacy_hal::WIFI_MOTION_EXPECTED;
+        case RttMotionPattern::UNKNOWN:
+            return legacy_hal::WIFI_MOTION_UNKNOWN;
+    };
+    CHECK(false);
+}
+
+V1_6::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+    switch (preamble) {
+        case 0:
+            return V1_6::WifiRatePreamble::OFDM;
+        case 1:
+            return V1_6::WifiRatePreamble::CCK;
+        case 2:
+            return V1_6::WifiRatePreamble::HT;
+        case 3:
+            return V1_6::WifiRatePreamble::VHT;
+        case 4:
+            return V1_6::WifiRatePreamble::HE;
+        case 5:
+            return V1_6::WifiRatePreamble::EHT;
+        default:
+            return V1_6::WifiRatePreamble::RESERVED;
+    };
+    CHECK(false) << "Unknown legacy preamble: " << preamble;
+}
+
+WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
+    switch (nss) {
+        case 0:
+            return WifiRateNss::NSS_1x1;
+        case 1:
+            return WifiRateNss::NSS_2x2;
+        case 2:
+            return WifiRateNss::NSS_3x3;
+        case 3:
+            return WifiRateNss::NSS_4x4;
+    };
+    CHECK(false) << "Unknown legacy nss: " << nss;
+    return {};
+}
+
+RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
+    switch (status) {
+        case legacy_hal::RTT_STATUS_SUCCESS:
+            return RttStatus::SUCCESS;
+        case legacy_hal::RTT_STATUS_FAILURE:
+            return RttStatus::FAILURE;
+        case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
+            return RttStatus::FAIL_NO_RSP;
+        case legacy_hal::RTT_STATUS_FAIL_REJECTED:
+            return RttStatus::FAIL_REJECTED;
+        case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
+            return RttStatus::FAIL_NOT_SCHEDULED_YET;
+        case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
+            return RttStatus::FAIL_TM_TIMEOUT;
+        case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
+            return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
+        case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
+            return RttStatus::FAIL_NO_CAPABILITY;
+        case legacy_hal::RTT_STATUS_ABORTED:
+            return RttStatus::ABORTED;
+        case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
+            return RttStatus::FAIL_INVALID_TS;
+        case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
+            return RttStatus::FAIL_PROTOCOL;
+        case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
+            return RttStatus::FAIL_SCHEDULE;
+        case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
+            return RttStatus::FAIL_BUSY_TRY_LATER;
+        case legacy_hal::RTT_STATUS_INVALID_REQ:
+            return RttStatus::INVALID_REQ;
+        case legacy_hal::RTT_STATUS_NO_WIFI:
+            return RttStatus::NO_WIFI;
+        case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
+            return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
+        case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
+            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
+        case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
+            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
+    };
+    CHECK(false) << "Unknown legacy status: " << status;
+}
+
+bool convertHidlWifiChannelInfoToLegacy(const WifiChannelInfo& hidl_info,
+                                        legacy_hal::wifi_channel_info* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
+    legacy_info->center_freq = hidl_info.centerFreq;
+    legacy_info->center_freq0 = hidl_info.centerFreq0;
+    legacy_info->center_freq1 = hidl_info.centerFreq1;
+    return true;
+}
+
+bool convertLegacyWifiChannelInfoToHidl(const legacy_hal::wifi_channel_info& legacy_info,
+                                        WifiChannelInfo* hidl_info) {
+    if (!hidl_info) {
+        return false;
+    }
+    *hidl_info = {};
+    hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
+    hidl_info->centerFreq = legacy_info.center_freq;
+    hidl_info->centerFreq0 = legacy_info.center_freq0;
+    hidl_info->centerFreq1 = legacy_info.center_freq1;
+    return true;
+}
+
+bool convertHidlRttConfigToLegacy(const V1_6::RttConfig& hidl_config,
+                                  legacy_hal::wifi_rtt_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
+    memcpy(legacy_config->addr, hidl_config.addr.data(), hidl_config.addr.size());
+    legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
+    legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
+    if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel, &legacy_config->channel)) {
+        return false;
+    }
+    legacy_config->burst_period = hidl_config.burstPeriod;
+    legacy_config->num_burst = hidl_config.numBurst;
+    legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
+    legacy_config->num_retries_per_rtt_frame = hidl_config.numRetriesPerRttFrame;
+    legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
+    legacy_config->LCI_request = hidl_config.mustRequestLci;
+    legacy_config->LCR_request = hidl_config.mustRequestLcr;
+    legacy_config->burst_duration = hidl_config.burstDuration;
+    legacy_config->preamble = convertHidlRttPreambleToLegacy(hidl_config.preamble);
+    legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
+    return true;
+}
+
+bool convertHidlVectorOfRttConfigToLegacy(
+        const std::vector<V1_6::RttConfig>& hidl_configs,
+        std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
+    if (!legacy_configs) {
+        return false;
+    }
+    *legacy_configs = {};
+    for (const auto& hidl_config : hidl_configs) {
+        legacy_hal::wifi_rtt_config legacy_config;
+        if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
+            return false;
+        }
+        legacy_configs->push_back(legacy_config);
+    }
+    return true;
+}
+
+bool convertHidlRttLciInformationToLegacy(const RttLciInformation& hidl_info,
+                                          legacy_hal::wifi_lci_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->latitude = hidl_info.latitude;
+    legacy_info->longitude = hidl_info.longitude;
+    legacy_info->altitude = hidl_info.altitude;
+    legacy_info->latitude_unc = hidl_info.latitudeUnc;
+    legacy_info->longitude_unc = hidl_info.longitudeUnc;
+    legacy_info->altitude_unc = hidl_info.altitudeUnc;
+    legacy_info->motion_pattern = convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
+    legacy_info->floor = hidl_info.floor;
+    legacy_info->height_above_floor = hidl_info.heightAboveFloor;
+    legacy_info->height_unc = hidl_info.heightUnc;
+    return true;
+}
+
+bool convertHidlRttLcrInformationToLegacy(const RttLcrInformation& hidl_info,
+                                          legacy_hal::wifi_lcr_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
+    memcpy(legacy_info->country_code, hidl_info.countryCode.data(), hidl_info.countryCode.size());
+    if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
+        return false;
+    }
+    legacy_info->length = hidl_info.civicInfo.size();
+    memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(), hidl_info.civicInfo.size());
+    return true;
+}
+
+bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
+                                     legacy_hal::wifi_rtt_responder* legacy_responder) {
+    if (!legacy_responder) {
+        return false;
+    }
+    *legacy_responder = {};
+    if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel, &legacy_responder->channel)) {
+        return false;
+    }
+    legacy_responder->preamble = convertHidlRttPreambleToLegacy(hidl_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
+                                     V1_6::RttResponder* hidl_responder) {
+    if (!hidl_responder) {
+        return false;
+    }
+    *hidl_responder = {};
+    if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel, &hidl_responder->channel)) {
+        return false;
+    }
+    hidl_responder->preamble = convertLegacyRttPreambleToHidl(legacy_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttCapabilitiesToHidl(
+        const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+        V1_6::RttCapabilities* hidl_capabilities) {
+    if (!hidl_capabilities) {
+        return false;
+    }
+    *hidl_capabilities = {};
+    hidl_capabilities->rttOneSidedSupported = legacy_capabilities.rtt_one_sided_supported;
+    hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
+    hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
+    hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
+    hidl_capabilities->responderSupported = legacy_capabilities.responder_supported;
+    hidl_capabilities->preambleSupport = 0;
+    for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, legacy_hal::WIFI_RTT_PREAMBLE_HT,
+                            legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE,
+                            legacy_hal::WIFI_RTT_PREAMBLE_EHT}) {
+        if (legacy_capabilities.preamble_support & flag) {
+            hidl_capabilities->preambleSupport |=
+                    static_cast<std::underlying_type<V1_6::RttPreamble>::type>(
+                            convertLegacyRttPreambleToHidl(flag));
+        }
+    }
+    hidl_capabilities->bwSupport = 0;
+    for (const auto flag :
+         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10, legacy_hal::WIFI_RTT_BW_20,
+          legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160,
+          legacy_hal::WIFI_RTT_BW_320}) {
+        if (legacy_capabilities.bw_support & flag) {
+            hidl_capabilities->bwSupport |=
+                    static_cast<std::underlying_type<RttBw>::type>(convertLegacyRttBwToHidl(flag));
+        }
+    }
+    hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+    return true;
+}
+
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     V1_6::WifiRateInfo* hidl_rate) {
+    if (!hidl_rate) {
+        return false;
+    }
+    *hidl_rate = {};
+    hidl_rate->preamble = convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
+    hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
+    hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
+            static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
+    hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
+    hidl_rate->bitRateInKbps = legacy_rate.bitrate;
+    return true;
+}
+
+bool convertLegacyRttResultToHidl(const legacy_hal::wifi_rtt_result& legacy_result,
+                                  V1_6::RttResult* hidl_result) {
+    if (!hidl_result) {
+        return false;
+    }
+    *hidl_result = {};
+    CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
+    memcpy(hidl_result->addr.data(), legacy_result.addr, sizeof(legacy_result.addr));
+    hidl_result->burstNum = legacy_result.burst_num;
+    hidl_result->measurementNumber = legacy_result.measurement_number;
+    hidl_result->successNumber = legacy_result.success_number;
+    hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
+    hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
+    hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
+    hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
+    hidl_result->rssi = legacy_result.rssi;
+    hidl_result->rssiSpread = legacy_result.rssi_spread;
+    if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate, &hidl_result->txRate)) {
+        return false;
+    }
+    if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate, &hidl_result->rxRate)) {
+        return false;
+    }
+    hidl_result->rtt = legacy_result.rtt;
+    hidl_result->rttSd = legacy_result.rtt_sd;
+    hidl_result->rttSpread = legacy_result.rtt_spread;
+    hidl_result->distanceInMm = legacy_result.distance_mm;
+    hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
+    hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
+    hidl_result->timeStampInUs = legacy_result.ts;
+    hidl_result->burstDurationInMs = legacy_result.burst_duration;
+    hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
+    if (legacy_result.LCI && !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
+        return false;
+    }
+    if (legacy_result.LCR && !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
+        return false;
+    }
+    return true;
+}
+
+bool convertLegacyVectorOfRttResultToHidl(
+        const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+        std::vector<V1_6::RttResult>* hidl_results) {
+    if (!hidl_results) {
+        return false;
+    }
+    *hidl_results = {};
+    for (const auto legacy_result : legacy_results) {
+        V1_6::RttResult hidl_result;
+        if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
+            return false;
+        }
+        hidl_results->push_back(hidl_result);
+    }
+    return true;
+}
+
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(IfaceType hidl_interface_type) {
+    switch (hidl_interface_type) {
+        case IfaceType::STA:
+            return legacy_hal::WIFI_INTERFACE_TYPE_STA;
+        case IfaceType::AP:
+            return legacy_hal::WIFI_INTERFACE_TYPE_AP;
+        case IfaceType::P2P:
+            return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
+        case IfaceType::NAN:
+            return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
+    }
+    CHECK(false);
+}
+
+legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
+        V1_5::IWifiChip::MultiStaUseCase use_case) {
+    switch (use_case) {
+        case V1_5::IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY:
+            return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
+        case V1_5::IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED:
+            return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
+    }
+    CHECK(false);
+}
+
+bool convertHidlCoexUnsafeChannelToLegacy(
+        const V1_5::IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+        legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) {
+    if (!legacy_unsafe_channel) {
+        return false;
+    }
+    *legacy_unsafe_channel = {};
+    switch (hidl_unsafe_channel.band) {
+        case V1_5::WifiBand::BAND_24GHZ:
+            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND;
+            break;
+        case V1_5::WifiBand::BAND_5GHZ:
+            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND;
+            break;
+        default:
+            return false;
+    };
+    legacy_unsafe_channel->channel = hidl_unsafe_channel.channel;
+    legacy_unsafe_channel->power_cap_dbm = hidl_unsafe_channel.powerCapDbm;
+    return true;
+}
+
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+        const std::vector<V1_5::IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+        std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels) {
+    if (!legacy_unsafe_channels) {
+        return false;
+    }
+    *legacy_unsafe_channels = {};
+    for (const auto& hidl_unsafe_channel : hidl_unsafe_channels) {
+        legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel;
+        if (!hidl_struct_util::convertHidlCoexUnsafeChannelToLegacy(hidl_unsafe_channel,
+                                                                    &legacy_unsafe_channel)) {
+            return false;
+        }
+        legacy_unsafe_channels->push_back(legacy_unsafe_channel);
+    }
+    return true;
+}
+
+}  // namespace hidl_struct_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/hidl_struct_util.h b/wifi/1.6/default/hidl_struct_util.h
new file mode 100644
index 0000000..26a6ebc
--- /dev/null
+++ b/wifi/1.6/default/hidl_struct_util.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_STRUCT_UTIL_H_
+#define HIDL_STRUCT_UTIL_H_
+
+#include <vector>
+
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/1.0/types.h>
+#include <android/hardware/wifi/1.2/types.h>
+#include <android/hardware/wifi/1.3/types.h>
+#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.4/types.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/types.h>
+
+#include "wifi_legacy_hal.h"
+
+/**
+ * This file contains a bunch of functions to convert structs from the legacy
+ * HAL to HIDL and vice versa.
+ * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
+ * suite.
+ */
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_struct_util {
+using namespace android::hardware::wifi::V1_0;
+
+// Chip conversion methods.
+bool convertLegacyFeaturesToHidlChipCapabilities(uint64_t legacy_feature_set,
+                                                 uint32_t legacy_logger_feature_set,
+                                                 uint32_t* hidl_caps);
+bool convertLegacyDebugRingBufferStatusToHidl(
+        const legacy_hal::wifi_ring_buffer_status& legacy_status,
+        WifiDebugRingBufferStatus* hidl_status);
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+        const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+        std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
+bool convertLegacyWakeReasonStatsToHidl(const legacy_hal::WakeReasonStats& legacy_stats,
+                                        WifiDebugHostWakeReasonStats* hidl_stats);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+        V1_1::IWifiChip::TxPowerScenario hidl_scenario);
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+        V1_3::IWifiChip::LatencyMode hidl_latency_mode);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+        V1_2::IWifiChip::TxPowerScenario hidl_scenario);
+bool convertLegacyWifiMacInfosToHidl(
+        const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+        std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(IfaceType hidl_interface_type);
+legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
+        V1_5::IWifiChip::MultiStaUseCase use_case);
+bool convertHidlCoexUnsafeChannelToLegacy(
+        const V1_5::IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+        legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+        const std::vector<V1_5::IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+        std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
+
+// STA iface conversion methods.
+bool convertLegacyFeaturesToHidlStaCapabilities(uint64_t legacy_feature_set,
+                                                uint32_t legacy_logger_feature_set,
+                                                uint32_t* hidl_caps);
+bool convertLegacyApfCapabilitiesToHidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
+                                        StaApfPacketFilterCapabilities* hidl_caps);
+bool convertLegacyGscanCapabilitiesToHidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+                                          StaBackgroundScanCapabilities* hidl_caps);
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band);
+bool convertHidlGscanParamsToLegacy(const StaBackgroundScanParameters& hidl_scan_params,
+                                    legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
+// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
+// Information Elements (IEs)
+bool convertLegacyGscanResultToHidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
+                                    bool has_ie_data, StaScanResult* hidl_scan_result);
+// |cached_results| is assumed to not include IEs.
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+        const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
+        std::vector<StaScanData>* hidl_scan_datas);
+bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
+                                       V1_6::StaLinkLayerStats* hidl_stats);
+bool convertLegacyRoamingCapabilitiesToHidl(
+        const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+        StaRoamingCapabilities* hidl_caps);
+bool convertHidlRoamingConfigToLegacy(const StaRoamingConfig& hidl_config,
+                                      legacy_hal::wifi_roaming_config* legacy_config);
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(StaRoamingState state);
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+        const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+        std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+        const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+        std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
+
+// NAN iface conversion methods.
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
+                            WifiNanStatus* wifiNanStatus);
+bool convertHidlNanEnableRequestToLegacy(const V1_4::NanEnableRequest& hidl_request,
+                                         legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequestToLegacy(const V1_4::NanConfigRequest& hidl_request,
+                                         legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_6ToLegacy(
+        const V1_4::NanEnableRequest& hidl_request1,
+        const V1_6::NanConfigRequestSupplemental& hidl_request2,
+        legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_6ToLegacy(
+        const V1_4::NanConfigRequest& hidl_request1,
+        const V1_6::NanConfigRequestSupplemental& hidl_request2,
+        legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanPublishRequestToLegacy(const V1_6::NanPublishRequest& hidl_request,
+                                          legacy_hal::NanPublishRequest* legacy_request);
+bool convertHidlNanSubscribeRequestToLegacy(const V1_0::NanSubscribeRequest& hidl_request,
+                                            legacy_hal::NanSubscribeRequest* legacy_request);
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+        const NanTransmitFollowupRequest& hidl_request,
+        legacy_hal::NanTransmitFollowupRequest* legacy_request);
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+        const V1_0::NanInitiateDataPathRequest& hidl_request,
+        legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+        const V1_0::NanRespondToDataPathIndicationRequest& hidl_response,
+        legacy_hal::NanDataPathIndicationResponse* legacy_response);
+bool convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(
+        const V1_6::NanInitiateDataPathRequest& hidl_request,
+        legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponse_1_6ToLegacy(
+        const V1_6::NanRespondToDataPathIndicationRequest& hidl_response,
+        legacy_hal::NanDataPathIndicationResponse* legacy_response);
+
+bool convertLegacyNanResponseHeaderToHidl(const legacy_hal::NanResponseMsg& legacy_response,
+                                          WifiNanStatus* wifiNanStatus);
+bool convertLegacyNanCapabilitiesResponseToHidl(const legacy_hal::NanCapabilities& legacy_response,
+                                                V1_6::NanCapabilities* hidl_response);
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    V1_6::NanMatchInd* hidl_ind);
+bool convertLegacyNanFollowupIndToHidl(const legacy_hal::NanFollowupInd& legacy_ind,
+                                       NanFollowupReceivedInd* hidl_ind);
+bool convertLegacyNanDataPathRequestIndToHidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
+                                              NanDataPathRequestInd* hidl_ind);
+bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+                                              V1_6::NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+        const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+        V1_6::NanDataPathScheduleUpdateInd* hidl_ind);
+
+// RTT controller conversion methods.
+bool convertHidlVectorOfRttConfigToLegacy(const std::vector<V1_6::RttConfig>& hidl_configs,
+                                          std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertHidlRttLciInformationToLegacy(const RttLciInformation& hidl_info,
+                                          legacy_hal::wifi_lci_information* legacy_info);
+bool convertHidlRttLcrInformationToLegacy(const RttLcrInformation& hidl_info,
+                                          legacy_hal::wifi_lcr_information* legacy_info);
+bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
+                                     legacy_hal::wifi_rtt_responder* legacy_responder);
+bool convertHidlWifiChannelInfoToLegacy(const V1_6::WifiChannelInfo& hidl_info,
+                                        legacy_hal::wifi_channel_info* legacy_info);
+bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
+                                     V1_6::RttResponder* hidl_responder);
+bool convertLegacyRttCapabilitiesToHidl(
+        const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+        V1_6::RttCapabilities* hidl_capabilities);
+bool convertLegacyVectorOfRttResultToHidl(
+        const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+        std::vector<V1_6::RttResult>* hidl_results);
+uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand band);
+uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask);
+uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask);
+bool convertLegacyWifiUsableChannelsToHidl(
+        const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
+        std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels);
+bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+                                      V1_6::StaPeerInfo* hidl_peer_info_stats);
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     V1_6::WifiRateInfo* hidl_rate);
+}  // namespace hidl_struct_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.6/default/hidl_sync_util.cpp b/wifi/1.6/default/hidl_sync_util.cpp
new file mode 100644
index 0000000..358d95e
--- /dev/null
+++ b/wifi/1.6/default/hidl_sync_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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 "hidl_sync_util.h"
+
+namespace {
+std::recursive_mutex g_mutex;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_sync_util {
+
+std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
+    return std::unique_lock<std::recursive_mutex>{g_mutex};
+}
+
+}  // namespace hidl_sync_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/hidl_sync_util.h b/wifi/1.6/default/hidl_sync_util.h
new file mode 100644
index 0000000..2c1c37b
--- /dev/null
+++ b/wifi/1.6/default/hidl_sync_util.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_SYNC_UTIL_H_
+#define HIDL_SYNC_UTIL_H_
+
+#include <mutex>
+
+// Utility that provides a global lock to synchronize access between
+// the HIDL thread and the legacy HAL's event loop.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_sync_util {
+std::unique_lock<std::recursive_mutex> acquireGlobalLock();
+}  // namespace hidl_sync_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.6/default/ringbuffer.cpp b/wifi/1.6/default/ringbuffer.cpp
new file mode 100644
index 0000000..6d4ed84
--- /dev/null
+++ b/wifi/1.6/default/ringbuffer.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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 <android-base/logging.h>
+
+#include "ringbuffer.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
+
+void Ringbuffer::append(const std::vector<uint8_t>& input) {
+    if (input.size() == 0) {
+        return;
+    }
+    if (input.size() > maxSize_) {
+        LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped";
+        return;
+    }
+    data_.push_back(input);
+    size_ += input.size() * sizeof(input[0]);
+    while (size_ > maxSize_) {
+        size_ -= data_.front().size() * sizeof(data_.front()[0]);
+        data_.pop_front();
+    }
+}
+
+const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
+    return data_;
+}
+
+void Ringbuffer::clear() {
+    data_.clear();
+    size_ = 0;
+}
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/ringbuffer.h b/wifi/1.6/default/ringbuffer.h
new file mode 100644
index 0000000..8571a9f
--- /dev/null
+++ b/wifi/1.6/default/ringbuffer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include <list>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+/**
+ * Ringbuffer object used to store debug data.
+ */
+class Ringbuffer {
+  public:
+    explicit Ringbuffer(size_t maxSize);
+
+    // Appends the data buffer and deletes from the front until buffer is
+    // within |maxSize_|.
+    void append(const std::vector<uint8_t>& input);
+    const std::list<std::vector<uint8_t>>& getData() const;
+    void clear();
+
+  private:
+    std::list<std::vector<uint8_t>> data_;
+    size_t size_;
+    size_t maxSize_;
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // RINGBUFFER_H_
diff --git a/wifi/1.6/default/service.cpp b/wifi/1.6/default/service.cpp
new file mode 100644
index 0000000..c874d8b
--- /dev/null
+++ b/wifi/1.6/default/service.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <signal.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include "wifi.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_mode_controller.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::wifi::V1_6::implementation::feature_flags::WifiFeatureFlags;
+using android::hardware::wifi::V1_6::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_6::implementation::legacy_hal::WifiLegacyHalFactory;
+using android::hardware::wifi::V1_6::implementation::mode_controller::WifiModeController;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main(int /*argc*/, char** argv) {
+    signal(SIGPIPE, SIG_IGN);
+    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+    LOG(INFO) << "Wifi Hal is booting up...";
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    const auto iface_tool = std::make_shared<android::wifi_system::InterfaceTool>();
+    const auto legacy_hal_factory = std::make_shared<WifiLegacyHalFactory>(iface_tool);
+
+    // Setup hwbinder service
+    android::sp<android::hardware::wifi::V1_6::IWifi> service =
+            new android::hardware::wifi::V1_6::implementation::Wifi(
+                    iface_tool, legacy_hal_factory, std::make_shared<WifiModeController>(),
+                    std::make_shared<WifiFeatureFlags>());
+    if (kLazyService) {
+        auto registrar = LazyServiceRegistrar::getInstance();
+        CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
+                << "Failed to register wifi HAL";
+    } else {
+        CHECK_EQ(service->registerAsService(), android::NO_ERROR) << "Failed to register wifi HAL";
+    }
+
+    joinRpcThreadpool();
+
+    LOG(INFO) << "Wifi Hal is terminating...";
+    return 0;
+}
diff --git a/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..077c6cc
--- /dev/null
+++ b/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2017, 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 <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "hidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+}  // namespace
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using ::android::hardware::wifi::V1_6::WifiChannelWidthInMhz;
+
+class HidlStructUtilTest : public Test {};
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+            .wlan_mac_id = kMacId1,
+            .mac_band = legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+
+    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(legacy_mac_infos,
+                                                                  &hidl_radio_mode_infos));
+
+    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
+    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
+    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
+    EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel), hidl_iface_info1.channel);
+    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel), hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {.wlan_mac_id = kMacId1,
+                                                .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
+    legacy_hal::WifiMacInfo legacy_mac_info2 = {.wlan_mac_id = kMacId2,
+                                                .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info2);
+
+    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(legacy_mac_infos,
+                                                                  &hidl_radio_mode_infos));
+
+    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
+
+    // Find mac info 1.
+    const auto hidl_radio_mode_info1 =
+            std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+                         [&legacy_mac_info1](const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
+                             return x.radioId == legacy_mac_info1.wlan_mac_id;
+                         });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
+    EXPECT_EQ(V1_4::WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel), hidl_iface_info1.channel);
+
+    // Find mac info 2.
+    const auto hidl_radio_mode_info2 =
+            std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+                         [&legacy_mac_info2](const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
+                             return x.radioId == legacy_mac_info2.wlan_mac_id;
+                         });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
+    EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
+    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel), hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
+    legacy_hal::LinkLayerStats legacy_stats{};
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+    legacy_stats.iface.beacon_rx = rand();
+    legacy_stats.iface.rssi_mgmt = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples = rand();
+
+    legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
+    legacy_stats.iface.num_peers = 1;
+
+    for (auto& radio : legacy_stats.radios) {
+        radio.stats.radio = rand();
+        radio.stats.on_time = rand();
+        radio.stats.tx_time = rand();
+        radio.stats.rx_time = rand();
+        radio.stats.on_time_scan = rand();
+        radio.stats.on_time_nbd = rand();
+        radio.stats.on_time_gscan = rand();
+        radio.stats.on_time_roam_scan = rand();
+        radio.stats.on_time_pno_scan = rand();
+        radio.stats.on_time_hs20 = rand();
+        for (int i = 0; i < 4; i++) {
+            radio.tx_time_per_levels.push_back(rand());
+        }
+
+        legacy_hal::wifi_channel_stat channel_stat1 = {
+                .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+                .on_time = 0x1111,
+                .cca_busy_time = 0x55,
+        };
+        legacy_hal::wifi_channel_stat channel_stat2 = {
+                .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+                .on_time = 0x2222,
+                .cca_busy_time = 0x66,
+        };
+        radio.channel_stats.push_back(channel_stat1);
+        radio.channel_stats.push_back(channel_stat2);
+    }
+
+    for (auto& peer : legacy_stats.peers) {
+        peer.peer_info.bssload.sta_count = rand();
+        peer.peer_info.bssload.chan_util = rand();
+        wifi_rate_stat rate_stat1 = {
+                .rate = {3, 1, 2, 5, 0, 0},
+                .tx_mpdu = 0,
+                .rx_mpdu = 1,
+                .mpdu_lost = 2,
+                .retries = 3,
+                .retries_short = 4,
+                .retries_long = 5,
+        };
+        wifi_rate_stat rate_stat2 = {
+                .rate = {2, 2, 1, 6, 0, 1},
+                .tx_mpdu = 6,
+                .rx_mpdu = 7,
+                .mpdu_lost = 8,
+                .retries = 9,
+                .retries_short = 10,
+                .retries_long = 11,
+        };
+        peer.rate_stats.push_back(rate_stat1);
+        peer.rate_stats.push_back(rate_stat2);
+    }
+
+    V1_6::StaLinkLayerStats converted{};
+    hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &converted);
+    EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.V1_0.beaconRx);
+    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.V1_0.avgRssiMgmt);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+              converted.iface.V1_0.wmeBePktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+              converted.iface.V1_0.wmeBePktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+              converted.iface.V1_0.wmeBePktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+              converted.iface.V1_0.wmeBePktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
+              converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
+              converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
+              converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
+              converted.iface.wmeBeContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+              converted.iface.V1_0.wmeBkPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+              converted.iface.V1_0.wmeBkPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+              converted.iface.V1_0.wmeBkPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+              converted.iface.V1_0.wmeBkPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
+              converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
+              converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
+              converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
+              converted.iface.wmeBkContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+              converted.iface.V1_0.wmeViPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+              converted.iface.V1_0.wmeViPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+              converted.iface.V1_0.wmeViPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+              converted.iface.V1_0.wmeViPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
+              converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
+              converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
+              converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
+              converted.iface.wmeViContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+              converted.iface.V1_0.wmeVoPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+              converted.iface.V1_0.wmeVoPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+              converted.iface.V1_0.wmeVoPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+              converted.iface.V1_0.wmeVoPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
+              converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
+              converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
+              converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
+              converted.iface.wmeVoContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
+              converted.iface.timeSliceDutyCycleInPercent);
+
+    EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
+    for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
+        EXPECT_EQ(legacy_stats.radios[i].stats.radio, converted.radios[i].radioId);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time, converted.radios[i].V1_0.onTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, converted.radios[i].V1_0.txTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, converted.radios[i].V1_0.rxTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
+                  converted.radios[i].V1_0.onTimeInMsForScan);
+        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
+                  converted.radios[i].V1_0.txTimeInMsPerLevel.size());
+        for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size(); j++) {
+            EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
+                      converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
+        }
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
+                  converted.radios[i].onTimeInMsForNanScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
+                  converted.radios[i].onTimeInMsForBgScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
+                  converted.radios[i].onTimeInMsForRoamScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
+                  converted.radios[i].onTimeInMsForPnoScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
+                  converted.radios[i].onTimeInMsForHs20Scan);
+        EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
+                  converted.radios[i].channelStats.size());
+        for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size(); k++) {
+            auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
+            EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+                      converted.radios[i].channelStats[k].channel.width);
+            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
+                      converted.radios[i].channelStats[k].channel.centerFreq);
+            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
+                      converted.radios[i].channelStats[k].channel.centerFreq0);
+            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
+                      converted.radios[i].channelStats[k].channel.centerFreq1);
+            EXPECT_EQ(legacy_channel_st.cca_busy_time,
+                      converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+            EXPECT_EQ(legacy_channel_st.on_time, converted.radios[i].channelStats[k].onTimeInMs);
+        }
+    }
+
+    EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size());
+    for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
+        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
+                  converted.iface.peers[i].staCount);
+        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
+                  converted.iface.peers[i].chanUtil);
+        for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.preamble);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
+                      converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
+                      converted.iface.peers[i].rateStats[j].txMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
+                      converted.iface.peers[i].rateStats[j].rxMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
+                      converted.iface.peers[i].rateStats[j].mpduLost);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
+                      converted.iface.peers[i].rateStats[j].retries);
+        }
+    }
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
+    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+
+    uint32_t hidle_caps;
+
+    uint32_t legacy_feature_set = WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
+    uint32_t legacy_logger_feature_set = legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+
+    ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+            legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
+
+    EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
+                      HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
+                      HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
+                      HidlChipCaps::SET_LATENCY_MODE | HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
+              hidle_caps);
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.5/default/tests/main.cpp b/wifi/1.6/default/tests/main.cpp
similarity index 100%
rename from wifi/1.5/default/tests/main.cpp
rename to wifi/1.6/default/tests/main.cpp
diff --git a/wifi/1.5/default/tests/mock_interface_tool.cpp b/wifi/1.6/default/tests/mock_interface_tool.cpp
similarity index 100%
rename from wifi/1.5/default/tests/mock_interface_tool.cpp
rename to wifi/1.6/default/tests/mock_interface_tool.cpp
diff --git a/wifi/1.6/default/tests/mock_interface_tool.h b/wifi/1.6/default/tests/mock_interface_tool.h
new file mode 100644
index 0000000..7ce3992
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_interface_tool.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_INTERFACE_TOOL_H
+#define MOCK_INTERFACE_TOOL_H
+
+#include <gmock/gmock.h>
+#include <wifi_system/interface_tool.h>
+
+namespace android {
+namespace wifi_system {
+
+class MockInterfaceTool : public InterfaceTool {
+  public:
+    MockInterfaceTool();
+
+    MOCK_METHOD1(GetUpState, bool(const char* if_name));
+    MOCK_METHOD2(SetUpState, bool(const char* if_name, bool request_up));
+    MOCK_METHOD1(SetWifiUpState, bool(bool request_up));
+    MOCK_METHOD2(SetMacAddress,
+                 bool(const char* if_name, const std::array<uint8_t, ETH_ALEN>& address));
+    MOCK_METHOD1(GetFactoryMacAddress, std::array<uint8_t, ETH_ALEN>(const char* if_name));
+
+};  // class MockInterfaceTool
+
+}  // namespace wifi_system
+}  // namespace android
+
+#endif  // MOCK_INTERFACE_TOOL_H
diff --git a/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp
new file mode 100644
index 0000000..d10b74c
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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 <gmock/gmock.h>
+
+#include "mock_wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+MockWifiFeatureFlags::MockWifiFeatureFlags() {}
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_feature_flags.h b/wifi/1.6/default/tests/mock_wifi_feature_flags.h
new file mode 100644
index 0000000..fa3600a
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_feature_flags.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
+#define MOCK_WIFI_FEATURE_FLAGS_H_
+
+#include <gmock/gmock.h>
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+class MockWifiFeatureFlags : public WifiFeatureFlags {
+  public:
+    MockWifiFeatureFlags();
+
+    MOCK_METHOD1(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>(bool is_primary));
+    MOCK_METHOD0(isApMacRandomizationDisabled, bool());
+};
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_iface_util.cpp b/wifi/1.6/default/tests/mock_wifi_iface_util.cpp
new file mode 100644
index 0000000..24b16cb
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_iface_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+MockWifiIfaceUtil::MockWifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                                     const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : WifiIfaceUtil(iface_tool, legacy_hal) {}
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_iface_util.h b/wifi/1.6/default/tests/mock_wifi_iface_util.h
new file mode 100644
index 0000000..2701c36
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_iface_util.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_IFACE_UTIL_H_
+#define MOCK_WIFI_IFACE_UTIL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+class MockWifiIfaceUtil : public WifiIfaceUtil {
+  public:
+    MockWifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    MOCK_METHOD1(getFactoryMacAddress, std::array<uint8_t, 6>(const std::string&));
+    MOCK_METHOD2(setMacAddress, bool(const std::string&, const std::array<uint8_t, 6>&));
+    MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
+    MOCK_METHOD2(registerIfaceEventHandlers, void(const std::string&, IfaceEventHandlers));
+    MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
+    MOCK_METHOD2(setUpState, bool(const std::string&, bool));
+    MOCK_METHOD1(ifNameToIndex, unsigned(const std::string&));
+};
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp
new file mode 100644
index 0000000..2c55861
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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 <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+MockWifiLegacyHal::MockWifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                                     const wifi_hal_fn& fn, bool is_primary)
+    : WifiLegacyHal(iface_tool, fn, is_primary) {}
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_legacy_hal.h b/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
new file mode 100644
index 0000000..b1f5327
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_LEGACY_HAL_H_
+#define MOCK_WIFI_LEGACY_HAL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+class MockWifiLegacyHal : public WifiLegacyHal {
+  public:
+    MockWifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                      const wifi_hal_fn& fn, bool is_primary);
+    MOCK_METHOD0(initialize, wifi_error());
+    MOCK_METHOD0(start, wifi_error());
+    MOCK_METHOD2(stop,
+                 wifi_error(std::unique_lock<std::recursive_mutex>*, const std::function<void()>&));
+    MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
+    MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
+                 wifi_error(const std::string&, const on_radio_mode_change_callback&));
+    MOCK_METHOD1(getFirmwareVersion,
+                 std::pair<wifi_error, std::string>(const std::string& iface_name));
+    MOCK_METHOD1(getDriverVersion,
+                 std::pair<wifi_error, std::string>(const std::string& iface_name));
+
+    MOCK_METHOD2(selectTxPowerScenario,
+                 wifi_error(const std::string& iface_name, wifi_power_scenario scenario));
+    MOCK_METHOD1(resetTxPowerScenario, wifi_error(const std::string& iface_name));
+    MOCK_METHOD2(nanRegisterCallbackHandlers,
+                 wifi_error(const std::string&, const NanCallbackHandlers&));
+    MOCK_METHOD2(nanDisableRequest, wifi_error(const std::string&, transaction_id));
+    MOCK_METHOD3(nanDataInterfaceDelete,
+                 wifi_error(const std::string&, transaction_id, const std::string&));
+    MOCK_METHOD2(createVirtualInterface,
+                 wifi_error(const std::string& ifname, wifi_interface_type iftype));
+    MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname));
+    MOCK_METHOD0(waitForDriverReady, wifi_error());
+};
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp
new file mode 100644
index 0000000..446f829
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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 <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+
+MockWifiModeController::MockWifiModeController() : WifiModeController() {}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_mode_controller.h b/wifi/1.6/default/tests/mock_wifi_mode_controller.h
new file mode 100644
index 0000000..addcc81
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_mode_controller.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
+#define MOCK_WIFI_MODE_CONTROLLER_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+
+class MockWifiModeController : public WifiModeController {
+  public:
+    MockWifiModeController();
+    MOCK_METHOD0(initialize, bool());
+    MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
+    MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
+    MOCK_METHOD0(deinitialize, bool());
+};
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp
new file mode 100644
index 0000000..eb86194
--- /dev/null
+++ b/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018, 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 <gmock/gmock.h>
+
+#include "ringbuffer.h"
+
+using testing::Return;
+using testing::Test;
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+class RingbufferTest : public Test {
+  public:
+    const uint32_t maxBufferSize_ = 10;
+    Ringbuffer buffer_{maxBufferSize_};
+};
+
+TEST_F(RingbufferTest, CreateEmptyBuffer) {
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+    EXPECT_EQ(input2, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3 = {'G'};
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input2, buffer_.getData().front());
+    EXPECT_EQ(input3, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3(maxBufferSize_, '2');
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input3, buffer_.getData().front());
+}
+
+TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
+    const std::vector<uint8_t> input = {};
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendIsDropped) {
+    const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
+    const std::vector<uint8_t> input(maxBufferSize_, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.5/default/tests/runtests.sh b/wifi/1.6/default/tests/runtests.sh
similarity index 100%
rename from wifi/1.5/default/tests/runtests.sh
rename to wifi/1.6/default/tests/runtests.sh
diff --git a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
new file mode 100644
index 0000000..542b180
--- /dev/null
+++ b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
@@ -0,0 +1,854 @@
+/*
+ * Copyright (C) 2017, 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 <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_chip.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+#include "mock_wifi_mode_controller.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+using android::hardware::wifi::V1_0::ChipId;
+
+constexpr ChipId kFakeChipId = 5;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+class WifiChipTest : public Test {
+  protected:
+    void setupV1IfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P}, 1}}}
+        };
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
+            {{{{IfaceType::AP}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV1_AwareIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
+            {{{{IfaceType::AP}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV1_AwareDisabledApIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV2_AwareIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::AP}, 1}}},
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV2_AwareDisabledApIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setup_MultiIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+            {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void assertNumberOfModes(uint32_t num_modes) {
+        chip_->getAvailableModes([num_modes](const WifiStatus& status,
+                                             const std::vector<WifiChip::ChipMode>& modes) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            // V2_Aware has 1 mode of operation.
+            ASSERT_EQ(num_modes, modes.size());
+        });
+    }
+
+    void findModeAndConfigureForIfaceType(const IfaceType& type) {
+        // This should be aligned with kInvalidModeId in wifi_chip.cpp.
+        ChipModeId mode_id = UINT32_MAX;
+        chip_->getAvailableModes([&mode_id, &type](const WifiStatus& status,
+                                                   const std::vector<WifiChip::ChipMode>& modes) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            for (const auto& mode : modes) {
+                for (const auto& combination : mode.availableCombinations) {
+                    for (const auto& limit : combination.limits) {
+                        if (limit.types.end() !=
+                            std::find(limit.types.begin(), limit.types.end(), type)) {
+                            mode_id = mode.id;
+                        }
+                    }
+                }
+            }
+        });
+        ASSERT_NE(UINT32_MAX, mode_id);
+
+        chip_->configureChip(mode_id, [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+    }
+
+    // Returns an empty string on error.
+    std::string createIface(const IfaceType& type) {
+        std::string iface_name;
+        if (type == IfaceType::AP) {
+            chip_->createApIface(
+                    [&iface_name](const WifiStatus& status, const sp<V1_0::IWifiApIface>& iface) {
+                        if (WifiStatusCode::SUCCESS == status.code) {
+                            ASSERT_NE(iface.get(), nullptr);
+                            iface->getName([&iface_name](const WifiStatus& status,
+                                                         const hidl_string& name) {
+                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                                iface_name = name.c_str();
+                            });
+                        }
+                    });
+        } else if (type == IfaceType::NAN) {
+            chip_->createNanIface(
+                    [&iface_name](const WifiStatus& status,
+                                  const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
+                        if (WifiStatusCode::SUCCESS == status.code) {
+                            ASSERT_NE(iface.get(), nullptr);
+                            iface->getName([&iface_name](const WifiStatus& status,
+                                                         const hidl_string& name) {
+                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                                iface_name = name.c_str();
+                            });
+                        }
+                    });
+        } else if (type == IfaceType::P2P) {
+            chip_->createP2pIface(
+                    [&iface_name](const WifiStatus& status, const sp<IWifiP2pIface>& iface) {
+                        if (WifiStatusCode::SUCCESS == status.code) {
+                            ASSERT_NE(iface.get(), nullptr);
+                            iface->getName([&iface_name](const WifiStatus& status,
+                                                         const hidl_string& name) {
+                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                                iface_name = name.c_str();
+                            });
+                        }
+                    });
+        } else if (type == IfaceType::STA) {
+            chip_->createStaIface(
+                    [&iface_name](const WifiStatus& status, const sp<V1_0::IWifiStaIface>& iface) {
+                        if (WifiStatusCode::SUCCESS == status.code) {
+                            ASSERT_NE(iface.get(), nullptr);
+                            iface->getName([&iface_name](const WifiStatus& status,
+                                                         const hidl_string& name) {
+                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                                iface_name = name.c_str();
+                            });
+                        }
+                    });
+        }
+        return iface_name;
+    }
+
+    void removeIface(const IfaceType& type, const std::string& iface_name) {
+        if (type == IfaceType::AP) {
+            chip_->removeApIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::NAN) {
+            chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::P2P) {
+            chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::STA) {
+            chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        }
+    }
+
+    bool createRttController() {
+        bool success = false;
+        chip_->createRttController_1_6(
+                NULL, [&success](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(rtt.get(), nullptr);
+                        success = true;
+                    }
+                });
+        return success;
+    }
+
+    static void subsystemRestartHandler(const std::string& /*error*/) {}
+
+    sp<WifiChip> chip_;
+    ChipId chip_id_ = kFakeChipId;
+    legacy_hal::wifi_hal_fn fake_func_table_;
+    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+            new NiceMock<wifi_system::MockInterfaceTool>};
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>> mode_controller_{
+            new NiceMock<mode_controller::MockWifiModeController>};
+    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+            new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
+    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>> feature_flags_{
+            new NiceMock<feature_flags::MockWifiFeatureFlags>};
+
+  public:
+    void SetUp() override {
+        chip_ = new WifiChip(chip_id_, true, legacy_hal_, mode_controller_, iface_util_,
+                             feature_flags_, subsystemRestartHandler);
+
+        EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
+                .WillRepeatedly(testing::Return(true));
+        EXPECT_CALL(*legacy_hal_, start())
+                .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
+    }
+
+    void TearDown() override {
+        // Restore default system iface names (This should ideally be using a
+        // mock).
+        property_set("wifi.interface", "wlan0");
+        property_set("wifi.concurrent.interface", "wlan1");
+        property_set("wifi.aware.interface", nullptr);
+    }
+};
+
+////////// V1 Iface Combinations ////////////
+// Mode 1 - STA + P2P
+// Mode 2 - AP
+class WifiChipV1IfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV1IfaceCombination();
+        WifiChipTest::SetUp();
+        // V1 has 2 modes of operation.
+        assertNumberOfModes(2u);
+    }
+};
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+////////// V1 + Aware Iface Combinations ////////////
+// Mode 1 - STA + P2P/NAN
+// Mode 2 - AP
+class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV1_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V1_Aware has 2 modes of operation.
+        assertNumberOfModes(2u);
+    }
+};
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_FALSE(createRttController());
+
+    removeIface(IfaceType::AP, ap_iface_name);
+
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+////////// V2 + Aware Iface Combinations ////////////
+// Mode 1 - STA + STA/AP
+//        - STA + P2P/NAN
+class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV2_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V2_Aware has 1 mode of operation.
+        assertNumberOfModes(1u);
+    }
+};
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_AfterStaApRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    const auto sta_iface_name = createIface(IfaceType::STA);
+    ASSERT_FALSE(sta_iface_name.empty());
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+
+    // After removing AP & STA iface, STA iface creation should succeed.
+    removeIface(IfaceType::STA, sta_iface_name);
+    removeIface(IfaceType::AP, ap_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_EnsureDifferentIfaceNames) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    const auto sta_iface_name = createIface(IfaceType::STA);
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(sta_iface_name.empty());
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_NE(sta_iface_name, ap_iface_name);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveNanOnStaRemove) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+    // Create NAN iface
+    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
+
+    // We should have 1 nan iface.
+    chip_->getNanIfaceNames([](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        ASSERT_EQ(iface_names.size(), 1u);
+        ASSERT_EQ(iface_names[0], "wlan0");
+    });
+    // Retrieve the exact iface object.
+    sp<android::hardware::wifi::V1_0::IWifiNanIface> nan_iface;
+    chip_->getNanIface("wlan0",
+                       [&nan_iface](const WifiStatus& status,
+                                    const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
+                           ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                           ASSERT_NE(iface.get(), nullptr);
+                           nan_iface = iface;
+                       });
+
+    // Remove the STA iface.
+    removeIface(IfaceType::STA, "wlan0");
+    // We should have 0 nan iface now.
+    chip_->getNanIfaceNames([](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        ASSERT_EQ(iface_names.size(), 0u);
+    });
+    // Any operation on the nan iface object should return error now.
+    nan_iface->getName([](const WifiStatus& status, const std::string& /* iface_name */) {
+        ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
+    });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveRttControllerOnStaRemove) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+    // Create RTT controller
+    sp<IWifiRttController> rtt_controller;
+    chip_->createRttController_1_6(
+            NULL, [&rtt_controller](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
+                if (WifiStatusCode::SUCCESS == status.code) {
+                    ASSERT_NE(rtt.get(), nullptr);
+                    rtt_controller = rtt;
+                }
+            });
+
+    // Remove the STA iface.
+    removeIface(IfaceType::STA, "wlan0");
+
+    // Any operation on the rtt controller object should return error now.
+    rtt_controller->getBoundIface([](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
+        ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, status.code);
+    });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) {
+    property_set("wifi.aware.interface", nullptr);
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
+    removeIface(IfaceType::NAN, "wlan0");
+    EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) {
+    property_set("wifi.aware.interface", "aware0");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*iface_util_, ifNameToIndex("aware0")).WillOnce(testing::Return(4));
+    EXPECT_CALL(*iface_util_, setUpState("aware0", true)).WillOnce(testing::Return(true));
+    ASSERT_EQ(createIface(IfaceType::NAN), "aware0");
+
+    EXPECT_CALL(*iface_util_, setUpState("aware0", false)).WillOnce(testing::Return(true));
+    removeIface(IfaceType::NAN, "aware0");
+}
+
+////////// V1 Iface Combinations when AP creation is disabled //////////
+class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV1_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// V2 Iface Combinations when AP creation is disabled //////////
+class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV2_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest, CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// Hypothetical Iface Combination with multiple ifaces //////////
+class WifiChip_MultiIfaceTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setup_MultiIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
+    property_set("wifi.interface.0", "");
+    property_set("wifi.interface.1", "");
+    property_set("wifi.interface.2", "");
+    property_set("wifi.interface", "");
+    property_set("wifi.concurrent.interface", "");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
+    property_set("wifi.interface.0", "test0");
+    property_set("wifi.interface.1", "test1");
+    property_set("wifi.interface.2", "test2");
+    property_set("wifi.interface", "bad0");
+    property_set("wifi.concurrent.interface", "bad1");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "bad0");
+    ASSERT_EQ(createIface(IfaceType::STA), "bad1");
+    ASSERT_EQ(createIface(IfaceType::STA), "test2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
+    property_set("wifi.interface.0", "");
+    property_set("wifi.interface.1", "");
+    property_set("wifi.interface.2", "");
+    property_set("wifi.interface", "testA0");
+    property_set("wifi.concurrent.interface", "testA1");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "testA0");
+    ASSERT_EQ(createIface(IfaceType::STA), "testA1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    // First AP will be slotted to wlan1.
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    // First STA will be slotted to wlan0.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    // All further STA will be slotted to the remaining free indices.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp
new file mode 100644
index 0000000..cc9a334
--- /dev/null
+++ b/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Test;
+
+namespace {
+constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
+constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
+constexpr char kIfaceName[] = "test-wlan0";
+
+bool isValidUnicastLocallyAssignedMacAddress(const std::array<uint8_t, 6>& mac_address) {
+    uint8_t first_byte = mac_address[0];
+    return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+class WifiIfaceUtilTest : public Test {
+  protected:
+    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+            new NiceMock<wifi_system::MockInterfaceTool>};
+    legacy_hal::wifi_hal_fn fake_func_table_;
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+    WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_, legacy_hal_);
+};
+
+TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
+    auto mac_address = iface_util_->getOrCreateRandomMacAddress();
+    ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
+
+    // All further calls should return the same MAC address.
+    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+}
+
+TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
+    std::array<uint8_t, 6> mac_address = {};
+    std::copy(std::begin(kMacAddress), std::end(kMacAddress), std::begin(mac_address));
+    EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
+            .WillRepeatedly(testing::Return(true));
+    EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
+            .WillRepeatedly(testing::Return(true));
+
+    // Register for iface state toggle events.
+    bool callback_invoked = false;
+    iface_util::IfaceEventHandlers event_handlers = {};
+    event_handlers.on_state_toggle_off_on =
+            [&callback_invoked](const std::string& /* iface_name */) { callback_invoked = true; };
+    iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
+    // Invoke setMacAddress and ensure that the cb is invoked.
+    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+    ASSERT_TRUE(callback_invoked);
+
+    // Unregister for iface state toggle events.
+    callback_invoked = false;
+    iface_util_->unregisterIfaceEventHandlers(kIfaceName);
+    // Invoke setMacAddress and ensure that the cb is not invoked.
+    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+    ASSERT_FALSE(callback_invoked);
+}
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
new file mode 100644
index 0000000..8a5ddcd
--- /dev/null
+++ b/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_nan_iface.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+constexpr char kIfaceName[] = "mockWlan0";
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+using android::hardware::wifi::V1_2::NanDataPathConfirmInd;
+
+bool CaptureIfaceEventHandlers(const std::string& /* iface_name*/,
+                               iface_util::IfaceEventHandlers in_iface_event_handlers,
+                               iface_util::IfaceEventHandlers* out_iface_event_handlers) {
+    *out_iface_event_handlers = in_iface_event_handlers;
+    return true;
+}
+
+class MockNanIfaceEventCallback : public V1_5::IWifiNanIfaceEventCallback {
+  public:
+    MockNanIfaceEventCallback() = default;
+
+    MOCK_METHOD3(notifyCapabilitiesResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&,
+                              const android::hardware::wifi::V1_0::NanCapabilities&));
+    MOCK_METHOD2(notifyEnableResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyConfigResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyDisableResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD3(notifyStartPublishResponse, Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+    MOCK_METHOD2(notifyStopPublishResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD3(notifyStartSubscribeResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+    MOCK_METHOD2(notifyStopSubscribeResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyTransmitFollowupResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyCreateDataInterfaceResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyDeleteDataInterfaceResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD3(notifyInitiateDataPathResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
+    MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyTerminateDataPathResponse, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
+    MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
+    MOCK_METHOD2(eventPublishTerminated, Return<void>(uint8_t, const WifiNanStatus&));
+    MOCK_METHOD2(eventSubscribeTerminated, Return<void>(uint8_t, const WifiNanStatus&));
+    MOCK_METHOD1(eventMatch, Return<void>(const V1_0::NanMatchInd&));
+    MOCK_METHOD1(eventMatch_1_6, Return<void>(const NanMatchInd&));
+    MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
+    MOCK_METHOD1(eventFollowupReceived, Return<void>(const NanFollowupReceivedInd&));
+    MOCK_METHOD2(eventTransmitFollowup, Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD1(eventDataPathRequest, Return<void>(const NanDataPathRequestInd&));
+    MOCK_METHOD1(eventDataPathConfirm,
+                 Return<void>(const android::hardware::wifi::V1_0::NanDataPathConfirmInd&));
+    MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
+    MOCK_METHOD1(eventDataPathConfirm_1_2,
+                 Return<void>(const android::hardware::wifi::V1_2::NanDataPathConfirmInd&));
+    MOCK_METHOD1(eventDataPathConfirm_1_6, Return<void>(const NanDataPathConfirmInd&));
+    MOCK_METHOD1(eventDataPathScheduleUpdate,
+                 Return<void>(const android::hardware::wifi::V1_2::NanDataPathScheduleUpdateInd&));
+    MOCK_METHOD1(eventDataPathScheduleUpdate_1_6,
+                 Return<void>(const NanDataPathScheduleUpdateInd&));
+    MOCK_METHOD3(notifyCapabilitiesResponse_1_5,
+                 Return<void>(uint16_t, const WifiNanStatus&, const V1_5::NanCapabilities&));
+};
+
+class WifiNanIfaceTest : public Test {
+  protected:
+    legacy_hal::wifi_hal_fn fake_func_table_;
+    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+            new NiceMock<wifi_system::MockInterfaceTool>};
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+            new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
+};
+
+TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
+    iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
+    EXPECT_CALL(*legacy_hal_, nanRegisterCallbackHandlers(testing::_, testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    EXPECT_CALL(*iface_util_, registerIfaceEventHandlers(testing::_, testing::_))
+            .WillOnce(testing::Invoke(bind(CaptureIfaceEventHandlers, std::placeholders::_1,
+                                           std::placeholders::_2, &captured_iface_event_handlers)));
+    sp<WifiNanIface> nan_iface = new WifiNanIface(kIfaceName, false, legacy_hal_, iface_util_);
+
+    // Register a mock nan event callback.
+    sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
+            new NiceMock<MockNanIfaceEventCallback>};
+    nan_iface->registerEventCallback(mock_event_callback, [](const WifiStatus& status) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+    });
+    // Ensure that the eventDisabled() function in mock callback will be
+    // invoked.
+    WifiNanStatus expected_nan_status = {NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+    EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status)).Times(1);
+
+    // Trigger the iface state toggle callback.
+    captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi.cpp b/wifi/1.6/default/wifi.cpp
new file mode 100644
index 0000000..c302ce2
--- /dev/null
+++ b/wifi/1.6/default/wifi.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi.h"
+#include "wifi_status_util.h"
+
+namespace {
+// Starting Chip ID, will be assigned to primary chip
+static constexpr android::hardware::wifi::V1_0::ChipId kPrimaryChipId = 0;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+Wifi::Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+           const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
+           const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+           const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    : iface_tool_(iface_tool),
+      legacy_hal_factory_(legacy_hal_factory),
+      mode_controller_(mode_controller),
+      feature_flags_(feature_flags),
+      run_state_(RunState::STOPPED) {}
+
+bool Wifi::isValid() {
+    // This object is always valid.
+    return true;
+}
+
+Return<void> Wifi::registerEventCallback(const sp<V1_0::IWifiEventCallback>& event_callback,
+                                         registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::registerEventCallbackInternal, hidl_status_cb, event_callback);
+}
+
+Return<void> Wifi::registerEventCallback_1_5(const sp<V1_5::IWifiEventCallback>& event_callback,
+                                             registerEventCallback_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::registerEventCallbackInternal_1_5, hidl_status_cb,
+                           event_callback);
+}
+
+Return<bool> Wifi::isStarted() {
+    return run_state_ != RunState::STOPPED;
+}
+
+Return<void> Wifi::start(start_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal,
+                           hidl_status_cb);
+}
+
+Return<void> Wifi::stop(stop_cb hidl_status_cb) {
+    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::stopInternal,
+                                   hidl_status_cb);
+}
+
+Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipIdsInternal,
+                           hidl_status_cb);
+}
+
+Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipInternal,
+                           hidl_status_cb, chip_id);
+}
+
+Return<void> Wifi::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+    LOG(INFO) << "-----------Debug is called----------------";
+    if (chips_.size() == 0) {
+        return Void();
+    }
+
+    for (sp<WifiChip> chip : chips_) {
+        if (!chip.get()) continue;
+
+        chip->debug(handle, {});
+    }
+    return Void();
+}
+
+WifiStatus Wifi::registerEventCallbackInternal(
+        const sp<V1_0::IWifiEventCallback>& event_callback __unused) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus Wifi::registerEventCallbackInternal_1_5(
+        const sp<V1_5::IWifiEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::startInternal() {
+    if (run_state_ == RunState::STARTED) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
+    }
+    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
+    if (wifi_status.code == WifiStatusCode::SUCCESS) {
+        // Register the callback for subsystem restart
+        const auto& on_subsystem_restart_callback = [this](const std::string& error) {
+            WifiStatus wifi_status = createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
+            for (const auto& callback : event_cb_handler_.getCallbacks()) {
+                LOG(INFO) << "Attempting to invoke onSubsystemRestart "
+                             "callback";
+                if (!callback->onSubsystemRestart(wifi_status).isOk()) {
+                    LOG(ERROR) << "Failed to invoke onSubsystemRestart callback";
+                } else {
+                    LOG(INFO) << "Succeeded to invoke onSubsystemRestart "
+                                 "callback";
+                }
+            }
+        };
+
+        // Create the chip instance once the HAL is started.
+        android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
+        for (auto& hal : legacy_hals_) {
+            chips_.push_back(
+                    new WifiChip(chipId, chipId == kPrimaryChipId, hal, mode_controller_,
+                                 std::make_shared<iface_util::WifiIfaceUtil>(iface_tool_, hal),
+                                 feature_flags_, on_subsystem_restart_callback));
+            chipId++;
+        }
+        run_state_ = RunState::STARTED;
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStart().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStart callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL started";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onFailure(wifi_status).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL start failed";
+        // Clear the event callback objects since the HAL start failed.
+        event_cb_handler_.invalidate();
+    }
+    return wifi_status;
+}
+
+WifiStatus Wifi::stopInternal(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    if (run_state_ == RunState::STOPPED) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
+    }
+    // Clear the chip object and its child objects since the HAL is now
+    // stopped.
+    for (auto& chip : chips_) {
+        if (chip.get()) {
+            chip->invalidate();
+            chip.clear();
+        }
+    }
+    chips_.clear();
+    WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
+    if (wifi_status.code == WifiStatusCode::SUCCESS) {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStop().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStop callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL stopped";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onFailure(wifi_status).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL stop failed";
+    }
+    // Clear the event callback objects since the HAL is now stopped.
+    event_cb_handler_.invalidate();
+    return wifi_status;
+}
+
+std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
+    std::vector<ChipId> chip_ids;
+
+    for (auto& chip : chips_) {
+        ChipId chip_id = getChipIdFromWifiChip(chip);
+        if (chip_id != UINT32_MAX) chip_ids.emplace_back(chip_id);
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
+    for (auto& chip : chips_) {
+        ChipId cand_id = getChipIdFromWifiChip(chip);
+        if ((cand_id != UINT32_MAX) && (cand_id == chip_id))
+            return {createWifiStatus(WifiStatusCode::SUCCESS), chip};
+    }
+
+    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+}
+
+WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
+    if (!mode_controller_->initialize()) {
+        LOG(ERROR) << "Failed to initialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+
+    legacy_hals_ = legacy_hal_factory_->getHals();
+    if (legacy_hals_.empty()) return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    int index = 0;  // for failure log
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error legacy_status = hal->initialize();
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            // Currently WifiLegacyHal::initialize does not allocate extra mem,
+            // only initializes the function table. If this changes, need to
+            // implement WifiLegacyHal::deinitialize and deinitalize the
+            // HALs already initialized
+            LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+        index++;
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
+    int index = 0;
+
+    run_state_ = RunState::STOPPING;
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
+        if (tmp != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            legacy_status = tmp;
+        }
+        index++;
+    }
+    run_state_ = RunState::STOPPED;
+
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "One or more legacy HALs failed to stop";
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    if (!mode_controller_->deinitialize()) {
+        LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+ChipId Wifi::getChipIdFromWifiChip(sp<WifiChip>& chip) {
+    ChipId chip_id = UINT32_MAX;
+    if (chip.get()) {
+        chip->getId([&](WifiStatus status, uint32_t id) {
+            if (status.code == WifiStatusCode::SUCCESS) {
+                chip_id = id;
+            }
+        });
+    }
+
+    return chip_id;
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi.h b/wifi/1.6/default/wifi.h
new file mode 100644
index 0000000..435358e
--- /dev/null
+++ b/wifi/1.6/default/wifi.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_H_
+#define WIFI_H_
+
+// HACK: NAN is a macro defined in math.h, which can be included in various
+// headers. This wifi HAL uses an enum called NAN, which does not compile when
+// the macro is defined. Undefine NAN to work around it.
+#undef NAN
+#include <android/hardware/wifi/1.6/IWifi.h>
+
+#include <android-base/macros.h>
+#include <utils/Looper.h>
+#include <functional>
+
+#include "hidl_callback_util.h"
+#include "wifi_chip.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+/**
+ * Root HIDL interface object used to control the Wifi HAL.
+ */
+class Wifi : public V1_6::IWifi {
+  public:
+    Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+         const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
+         const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+         const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+
+    bool isValid();
+
+    // HIDL methods exposed.
+    Return<void> registerEventCallback(const sp<V1_0::IWifiEventCallback>& event_callback,
+                                       registerEventCallback_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_5(const sp<V1_5::IWifiEventCallback>& event_callback,
+                                           registerEventCallback_1_5_cb hidl_status_cb) override;
+    Return<bool> isStarted() override;
+    Return<void> start(start_cb hidl_status_cb) override;
+    Return<void> stop(stop_cb hidl_status_cb) override;
+    Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
+    Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
+    Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
+
+  private:
+    enum class RunState { STOPPED, STARTED, STOPPING };
+
+    // Corresponding worker functions for the HIDL methods.
+    WifiStatus registerEventCallbackInternal(
+            const sp<V1_0::IWifiEventCallback>& event_callback __unused);
+    WifiStatus registerEventCallbackInternal_1_5(
+            const sp<V1_5::IWifiEventCallback>& event_callback);
+    WifiStatus startInternal();
+    WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
+    std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
+    std::pair<WifiStatus, sp<V1_4::IWifiChip>> getChipInternal(ChipId chip_id);
+
+    WifiStatus initializeModeControllerAndLegacyHal();
+    WifiStatus stopLegacyHalAndDeinitializeModeController(
+            std::unique_lock<std::recursive_mutex>* lock);
+    ChipId getChipIdFromWifiChip(sp<WifiChip>& chip);
+
+    // Instance is created in this root level |IWifi| HIDL interface object
+    // and shared with all the child HIDL interface objects.
+    std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
+    std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
+    std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
+    std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
+    RunState run_state_;
+    std::vector<sp<WifiChip>> chips_;
+    hidl_callback_util::HidlCallbackHandler<V1_5::IWifiEventCallback> event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(Wifi);
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_H_
diff --git a/wifi/1.6/default/wifi_ap_iface.cpp b/wifi/1.6/default/wifi_ap_iface.cpp
new file mode 100644
index 0000000..b2957db
--- /dev/null
+++ b/wifi/1.6/default/wifi_ap_iface.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_ap_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiApIface::WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+                         const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                         const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname),
+      instances_(instances),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true) {}
+
+void WifiApIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiApIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiApIface::getName() {
+    return ifname_;
+}
+
+void WifiApIface::removeInstance(std::string instance) {
+    instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end());
+}
+
+Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
+                                         setCountryCode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setCountryCodeInternal, hidl_status_cb, code);
+}
+
+Return<void> WifiApIface::getValidFrequenciesForBand(V1_0::WifiBand band,
+                                                     getValidFrequenciesForBand_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getValidFrequenciesForBandInternal, hidl_status_cb, band);
+}
+
+Return<void> WifiApIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                                        setMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setMacAddressInternal, hidl_status_cb, mac);
+}
+
+Return<void> WifiApIface::getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getFactoryMacAddressInternal, hidl_status_cb,
+                           instances_.size() > 0 ? instances_[0] : ifname_);
+}
+
+Return<void> WifiApIface::resetToFactoryMacAddress(resetToFactoryMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::resetToFactoryMacAddressInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::getBridgedInstances(getBridgedInstances_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getBridgedInstancesInternal, hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
+}
+
+WifiStatus WifiApIface::setCountryCodeInternal(const std::array<int8_t, 2>& code) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
+            instances_.size() > 0 ? instances_[0] : ifname_, code);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
+            instances_.size() > 0 ? instances_[0] : ifname_,
+            hidl_struct_util::convertHidlWifiBandToLegacy(band));
+    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiApIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
+    // Support random MAC up to 2 interfaces
+    if (instances_.size() == 2) {
+        int rbyte = 1;
+        for (auto const& intf : instances_) {
+            std::array<uint8_t, 6> rmac = mac;
+            // reverse the bits to avoid collision
+            rmac[rbyte] = 0xff - rmac[rbyte];
+            if (!iface_util_.lock()->setMacAddress(intf, rmac)) {
+                LOG(INFO) << "Failed to set random mac address on " << intf;
+                return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+            }
+            rbyte++;
+        }
+    }
+    // It also needs to set mac address for bridged interface, otherwise the mac
+    // address of bridged interface will be changed after one of instance
+    // down.
+    if (!iface_util_.lock()->setMacAddress(ifname_, mac)) {
+        LOG(ERROR) << "Fail to config MAC for interface " << ifname_;
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>> WifiApIface::getFactoryMacAddressInternal(
+        const std::string& ifaceName) {
+    std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifaceName);
+    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+
+WifiStatus WifiApIface::resetToFactoryMacAddressInternal() {
+    std::pair<WifiStatus, std::array<uint8_t, 6>> getMacResult;
+    if (instances_.size() == 2) {
+        for (auto const& intf : instances_) {
+            getMacResult = getFactoryMacAddressInternal(intf);
+            LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
+            if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
+                !iface_util_.lock()->setMacAddress(intf, getMacResult.second)) {
+                return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+            }
+        }
+        // It needs to set mac address for bridged interface, otherwise the mac
+        // address of the bridged interface will be changed after one of the
+        // instance down. Thus we are generating a random MAC address for the
+        // bridged interface even if we got the request to reset the Factory
+        // MAC. Since the bridged interface is an internal interface for the
+        // operation of bpf and others networking operation.
+        if (!iface_util_.lock()->setMacAddress(ifname_,
+                                               iface_util_.lock()->createRandomMacAddress())) {
+            LOG(ERROR) << "Fail to config MAC for bridged interface " << ifname_;
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+        }
+    } else {
+        getMacResult = getFactoryMacAddressInternal(ifname_);
+        LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_;
+        if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
+            !iface_util_.lock()->setMacAddress(ifname_, getMacResult.second)) {
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiApIface::getBridgedInstancesInternal() {
+    std::vector<hidl_string> instances;
+    for (const auto& instance_name : instances_) {
+        instances.push_back(instance_name);
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), instances};
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_ap_iface.h b/wifi/1.6/default/wifi_ap_iface.h
new file mode 100644
index 0000000..d1c0642
--- /dev/null
+++ b/wifi/1.6/default/wifi_ap_iface.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_AP_IFACE_H_
+#define WIFI_AP_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.5/IWifiApIface.h>
+
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a AP Iface instance.
+ */
+class WifiApIface : public V1_5::IWifiApIface {
+  public:
+    WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+    void removeInstance(std::string instance);
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
+                                setCountryCode_cb hidl_status_cb) override;
+    Return<void> getValidFrequenciesForBand(V1_0::WifiBand band,
+                                            getValidFrequenciesForBand_cb hidl_status_cb) override;
+    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                               setMacAddress_cb hidl_status_cb) override;
+    Return<void> getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) override;
+    Return<void> resetToFactoryMacAddress(resetToFactoryMacAddress_cb hidl_status_cb) override;
+
+    Return<void> getBridgedInstances(getBridgedInstances_cb hidl_status_cb) override;
+
+  private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
+    std::pair<WifiStatus, std::vector<WifiChannelInMhz>> getValidFrequenciesForBandInternal(
+            V1_0::WifiBand band);
+    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+    std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal(
+            const std::string& ifaceName);
+    WifiStatus resetToFactoryMacAddressInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getBridgedInstancesInternal();
+
+    std::string ifname_;
+    std::vector<std::string> instances_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiApIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
new file mode 100644
index 0000000..a185724
--- /dev/null
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -0,0 +1,1930 @@
+/*
+ * Copyright (C) 2016 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 <fcntl.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <net/if.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_chip.h"
+#include "wifi_status_util.h"
+
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
+namespace {
+using android::sp;
+using android::base::unique_fd;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::wifi::V1_0::ChipModeId;
+using android::hardware::wifi::V1_0::IfaceType;
+using android::hardware::wifi::V1_0::IWifiChip;
+
+constexpr char kCpioMagic[] = "070701";
+constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
+constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
+constexpr uint32_t kMaxRingBufferFileNum = 20;
+constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
+constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
+constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
+constexpr unsigned kMaxWlanIfaces = 5;
+constexpr char kApBridgeIfacePrefix[] = "ap_br_";
+
+template <typename Iface>
+void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
+    iface->invalidate();
+    ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), ifaces.end());
+}
+
+template <typename Iface>
+void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
+    for (const auto& iface : ifaces) {
+        iface->invalidate();
+    }
+    ifaces.clear();
+}
+
+template <typename Iface>
+std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
+    std::vector<hidl_string> names;
+    for (const auto& iface : ifaces) {
+        names.emplace_back(iface->getName());
+    }
+    return names;
+}
+
+template <typename Iface>
+sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces, const std::string& name) {
+    std::vector<hidl_string> names;
+    for (const auto& iface : ifaces) {
+        if (name == iface->getName()) {
+            return iface;
+        }
+    }
+    return nullptr;
+}
+
+std::string getWlanIfaceName(unsigned idx) {
+    if (idx >= kMaxWlanIfaces) {
+        CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
+        return {};
+    }
+
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    if (idx == 0 || idx == 1) {
+        const char* altPropName = (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
+        auto res = property_get(altPropName, buffer.data(), nullptr);
+        if (res > 0) return buffer.data();
+    }
+    std::string propName = "wifi.interface." + std::to_string(idx);
+    auto res = property_get(propName.c_str(), buffer.data(), nullptr);
+    if (res > 0) return buffer.data();
+
+    return "wlan" + std::to_string(idx);
+}
+
+// Returns the dedicated iface name if defined.
+// Returns two ifaces in bridged mode.
+std::vector<std::string> getPredefinedApIfaceNames(bool is_bridged) {
+    std::vector<std::string> ifnames;
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    buffer.fill(0);
+    if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) == 0) {
+        return ifnames;
+    }
+    ifnames.push_back(buffer.data());
+    if (is_bridged) {
+        buffer.fill(0);
+        if (property_get("ro.vendor.wifi.sap.concurrent.iface", buffer.data(), nullptr) == 0) {
+            return ifnames;
+        }
+        ifnames.push_back(buffer.data());
+    }
+    return ifnames;
+}
+
+std::string getPredefinedP2pIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> primaryIfaceName;
+    char p2pParentIfname[100];
+    std::string p2pDevIfName = "";
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.direct.interface", buffer.data(), "p2p0");
+    if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX, strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+        /* Get the p2p parent interface name from p2p device interface name set
+         * in property */
+        strncpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX),
+                strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX));
+        if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(), nullptr) == 0) {
+            return buffer.data();
+        }
+        /* Check if the parent interface derived from p2p device interface name
+         * is active */
+        if (strncmp(p2pParentIfname, primaryIfaceName.data(),
+                    strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) != 0) {
+            /*
+             * Update the predefined p2p device interface parent interface name
+             * with current active wlan interface
+             */
+            p2pDevIfName += P2P_MGMT_DEVICE_PREFIX;
+            p2pDevIfName += primaryIfaceName.data();
+            LOG(INFO) << "update the p2p device interface name to " << p2pDevIfName.c_str();
+            return p2pDevIfName;
+        }
+    }
+    return buffer.data();
+}
+
+// Returns the dedicated iface name if one is defined.
+std::string getPredefinedNanIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) {
+        return {};
+    }
+    return buffer.data();
+}
+
+void setActiveWlanIfaceNameProperty(const std::string& ifname) {
+    auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
+    if (res != 0) {
+        PLOG(ERROR) << "Failed to set active wlan iface name property";
+    }
+}
+
+// delete files that meet either conditions:
+// 1. older than a predefined time in the wifi tombstone dir.
+// 2. Files in excess to a predefined amount, starting from the oldest ones
+bool removeOldFilesInternal() {
+    time_t now = time(0);
+    const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(kTombstoneFolderPath), closedir);
+    if (!dir_dump) {
+        PLOG(ERROR) << "Failed to open directory";
+        return false;
+    }
+    struct dirent* dp;
+    bool success = true;
+    std::list<std::pair<const time_t, std::string>> valid_files;
+    while ((dp = readdir(dir_dump.get()))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        struct stat cur_file_stat;
+        std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+            success = false;
+            continue;
+        }
+        const time_t cur_file_time = cur_file_stat.st_mtime;
+        valid_files.push_back(std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
+    }
+    valid_files.sort();  // sort the list of files by last modified time from
+                         // small to big.
+    uint32_t cur_file_count = valid_files.size();
+    for (auto cur_file : valid_files) {
+        if (cur_file_count > kMaxRingBufferFileNum || cur_file.first < delete_files_before) {
+            if (unlink(cur_file.second.c_str()) != 0) {
+                PLOG(ERROR) << "Error deleting file";
+                success = false;
+            }
+            cur_file_count--;
+        } else {
+            break;
+        }
+    }
+    return success;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name, size_t file_name_len) {
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen =
+            sprintf(read_buf.data(), "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
+                    kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid, st.st_gid,
+                    static_cast<int>(st.st_nlink), static_cast<int>(st.st_mtime),
+                    static_cast<int>(st.st_size), major(st.st_dev), minor(st.st_dev),
+                    major(st.st_rdev), minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
+    if (write(out_fd, read_buf.data(), llen) == -1) {
+        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
+        return false;
+    }
+    if (write(out_fd, file_name, file_name_len) == -1) {
+        PLOG(ERROR) << "Error writing filename to file " << file_name;
+        return false;
+    }
+
+    // NUL Pad header up to 4 multiple bytes.
+    llen = (llen + file_name_len) % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file " << file_name;
+            return false;
+        }
+    }
+    return true;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
+    // writing content of file
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen = st.st_size;
+    size_t n_error = 0;
+    while (llen > 0) {
+        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
+        if (bytes_read == -1) {
+            PLOG(ERROR) << "Error reading file";
+            return ++n_error;
+        }
+        llen -= bytes_read;
+        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
+            PLOG(ERROR) << "Error writing data to file";
+            return ++n_error;
+        }
+        if (bytes_read == 0) {  // this should never happen, but just in case
+                                // to unstuck from while loop
+            PLOG(ERROR) << "Unexpected read result";
+            n_error++;
+            break;
+        }
+    }
+    llen = st.st_size % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file";
+            return ++n_error;
+        }
+    }
+    return n_error;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteFileTrailer(int out_fd) {
+    std::array<char, 4096> read_buf;
+    read_buf.fill(0);
+    if (write(out_fd, read_buf.data(),
+              sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0) + 4) == -1) {
+        PLOG(ERROR) << "Error writing trailing bytes";
+        return false;
+    }
+    return true;
+}
+
+// Archives all files in |input_dir| and writes result into |out_fd|
+// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
+// portion
+size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
+    struct dirent* dp;
+    size_t n_error = 0;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir), closedir);
+    if (!dir_dump) {
+        PLOG(ERROR) << "Failed to open directory";
+        return ++n_error;
+    }
+    while ((dp = readdir(dir_dump.get()))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        struct stat st;
+        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &st) == -1) {
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
+        if (fd_read == -1) {
+            PLOG(ERROR) << "Failed to open file " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        std::string file_name_with_last_modified_time =
+                cur_file_name + "-" + std::to_string(st.st_mtime);
+        // string.size() does not include the null terminator. The cpio FreeBSD
+        // file header expects the null character to be included in the length.
+        const size_t file_name_len = file_name_with_last_modified_time.size() + 1;
+        unique_fd file_auto_closer(fd_read);
+        if (!cpioWriteHeader(out_fd, st, file_name_with_last_modified_time.c_str(),
+                             file_name_len)) {
+            return ++n_error;
+        }
+        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
+        if (write_error) {
+            return n_error + write_error;
+        }
+    }
+    if (!cpioWriteFileTrailer(out_fd)) {
+        return ++n_error;
+    }
+    return n_error;
+}
+
+// Helper function to create a non-const char*.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+WifiChip::WifiChip(ChipId chip_id, bool is_primary,
+                   const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                   const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+                   const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+                   const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+                   const std::function<void(const std::string&)>& handler)
+    : chip_id_(chip_id),
+      legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      iface_util_(iface_util),
+      is_valid_(true),
+      current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
+      modes_(feature_flags.lock()->getChipModes(is_primary)),
+      debug_ring_buffer_cb_registered_(false),
+      subsystemCallbackHandler_(handler) {
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+}
+
+void WifiChip::invalidate() {
+    if (!writeRingbufferFilesInternal()) {
+        LOG(ERROR) << "Error writing files to flash";
+    }
+    invalidateAndRemoveAllIfaces();
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+bool WifiChip::isValid() {
+    return is_valid_;
+}
+
+std::set<sp<V1_4::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getIdInternal,
+                           hidl_status_cb);
+}
+
+// Deprecated support for this callback
+Return<void> WifiChip::registerEventCallback(const sp<V1_0::IWifiChipEventCallback>& event_callback,
+                                             registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal, hidl_status_cb,
+                           event_callback);
+}
+
+Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getAvailableModesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::configureChip(ChipModeId mode_id, configureChip_cb hidl_status_cb) {
+    return validateAndCallWithLock(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                                   &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
+}
+
+Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getModeInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestChipDebugInfo(requestChipDebugInfo_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestChipDebugInfoInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestDriverDebugDump(requestDriverDebugDump_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestDriverDebugDumpInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestFirmwareDebugDump(requestFirmwareDebugDump_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestFirmwareDebugDumpInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createApIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::createBridgedApIface(createBridgedApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createBridgedApIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIface(const hidl_string& ifname, getApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeApIface(const hidl_string& ifname, removeApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeApIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeIfaceInstanceFromBridgedApIface(
+        const hidl_string& ifname, const hidl_string& ifInstanceName,
+        removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal, hidl_status_cb,
+                           ifname, ifInstanceName);
+}
+
+Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createNanIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIface(const hidl_string& ifname, getNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeNanIface(const hidl_string& ifname, removeNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeNanIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createP2pIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIface(const hidl_string& ifname, getP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeP2pIface(const hidl_string& ifname, removeP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeP2pIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createStaIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIface(const hidl_string& ifname, getStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeStaIface(const hidl_string& ifname, removeStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeStaIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::createRttController(const sp<IWifiIface>& bound_iface,
+                                           createRttController_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createRttControllerInternal, hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getDebugRingBuffersStatus(getDebugRingBuffersStatus_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugRingBuffersStatusInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::startLoggingToDebugRingBuffer(
+        const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+        startLoggingToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::startLoggingToDebugRingBufferInternal, hidl_status_cb,
+                           ring_name, verbose_level, max_interval_in_sec, min_data_size_in_bytes);
+}
+
+Return<void> WifiChip::forceDumpToDebugRingBuffer(const hidl_string& ring_name,
+                                                  forceDumpToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::forceDumpToDebugRingBufferInternal, hidl_status_cb,
+                           ring_name);
+}
+
+Return<void> WifiChip::flushRingBufferToFile(flushRingBufferToFile_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::flushRingBufferToFileInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::stopLoggingToDebugRingBuffer(
+        stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::stopLoggingToDebugRingBufferInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getDebugHostWakeReasonStats(getDebugHostWakeReasonStats_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugHostWakeReasonStatsInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::enableDebugErrorAlerts(bool enable,
+                                              enableDebugErrorAlerts_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::enableDebugErrorAlertsInternal, hidl_status_cb, enable);
+}
+
+Return<void> WifiChip::selectTxPowerScenario(V1_1::IWifiChip::TxPowerScenario scenario,
+                                             selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::selectTxPowerScenarioInternal, hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::resetTxPowerScenario(resetTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::resetTxPowerScenarioInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::setLatencyMode(LatencyMode mode, setLatencyMode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setLatencyModeInternal, hidl_status_cb, mode);
+}
+
+Return<void> WifiChip::registerEventCallback_1_2(
+        const sp<V1_2::IWifiChipEventCallback>& event_callback,
+        registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal_1_2, hidl_status_cb,
+                           event_callback);
+}
+
+Return<void> WifiChip::selectTxPowerScenario_1_2(TxPowerScenario scenario,
+                                                 selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal_1_3, hidl_status_cb);
+}
+
+Return<void> WifiChip::getCapabilities_1_5(getCapabilities_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal_1_5, hidl_status_cb);
+}
+
+Return<void> WifiChip::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+    if (handle != nullptr && handle->numFds >= 1) {
+        {
+            std::unique_lock<std::mutex> lk(lock_t);
+            for (const auto& item : ringbuffer_map_) {
+                forceDumpToDebugRingBufferInternal(item.first);
+            }
+            // unique_lock unlocked here
+        }
+        usleep(100 * 1000);  // sleep for 100 milliseconds to wait for
+                             // ringbuffer updates.
+        int fd = handle->data[0];
+        if (!writeRingbufferFilesInternal()) {
+            LOG(ERROR) << "Error writing files to flash";
+        }
+        uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
+        if (n_error != 0) {
+            LOG(ERROR) << n_error << " errors occured in cpio function";
+        }
+        fsync(fd);
+    } else {
+        LOG(ERROR) << "File handle error";
+    }
+    return Void();
+}
+
+Return<void> WifiChip::createRttController_1_4(const sp<IWifiIface>& bound_iface,
+                                               createRttController_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createRttControllerInternal_1_4, hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::registerEventCallback_1_4(
+        const sp<V1_4::IWifiChipEventCallback>& event_callback,
+        registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal_1_4, hidl_status_cb,
+                           event_callback);
+}
+
+Return<void> WifiChip::setMultiStaPrimaryConnection(
+        const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setMultiStaPrimaryConnectionInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::setMultiStaUseCase(MultiStaUseCase use_case,
+                                          setMultiStaUseCase_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setMultiStaUseCaseInternal, hidl_status_cb, use_case);
+}
+
+Return<void> WifiChip::setCoexUnsafeChannels(const hidl_vec<CoexUnsafeChannel>& unsafeChannels,
+                                             hidl_bitfield<CoexRestriction> restrictions,
+                                             setCoexUnsafeChannels_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setCoexUnsafeChannelsInternal, hidl_status_cb, unsafeChannels,
+                           restrictions);
+}
+
+Return<void> WifiChip::setCountryCode(const hidl_array<int8_t, 2>& code,
+                                      setCountryCode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiChip::setCountryCodeInternal, hidl_status_cb, code);
+}
+
+Return<void> WifiChip::getUsableChannels(
+        WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+        hidl_bitfield<V1_5::IWifiChip::UsableChannelFilter> filterMask,
+        getUsableChannels_cb _hidl_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getUsableChannelsInternal, _hidl_cb, band, ifaceModeMask,
+                           filterMask);
+}
+
+Return<void> WifiChip::triggerSubsystemRestart(triggerSubsystemRestart_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::triggerSubsystemRestartInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::createRttController_1_6(const sp<IWifiIface>& bound_iface,
+                                               createRttController_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createRttControllerInternal_1_6, hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getUsableChannels_1_6(
+        WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+        hidl_bitfield<V1_6::IWifiChip::UsableChannelFilter> filterMask,
+        getUsableChannels_1_6_cb _hidl_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getUsableChannelsInternal_1_6, _hidl_cb, band, ifaceModeMask,
+                           filterMask);
+}
+
+void WifiChip::invalidateAndRemoveAllIfaces() {
+    invalidateAndClearBridgedApAll();
+    invalidateAndClearAll(ap_ifaces_);
+    invalidateAndClearAll(nan_ifaces_);
+    invalidateAndClearAll(p2p_ifaces_);
+    invalidateAndClearAll(sta_ifaces_);
+    // Since all the ifaces are invalid now, all RTT controller objects
+    // using those ifaces also need to be invalidated.
+    for (const auto& rtt : rtt_controllers_) {
+        rtt->invalidate();
+    }
+    rtt_controllers_.clear();
+}
+
+void WifiChip::invalidateAndRemoveDependencies(const std::string& removed_iface_name) {
+    for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
+        auto nan_iface = *it;
+        if (nan_iface->getName() == removed_iface_name) {
+            nan_iface->invalidate();
+            for (const auto& callback : event_cb_handler_.getCallbacks()) {
+                if (!callback->onIfaceRemoved(IfaceType::NAN, removed_iface_name).isOk()) {
+                    LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+                }
+            }
+            it = nan_ifaces_.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
+        auto rtt = *it;
+        if (rtt->getIfaceName() == removed_iface_name) {
+            rtt->invalidate();
+            it = rtt_controllers_.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
+std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal(
+        const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
+    // Deprecated support for this callback.
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, std::vector<V1_4::IWifiChip::ChipMode>>
+WifiChip::getAvailableModesInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
+}
+
+WifiStatus WifiChip::configureChipInternal(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id) {
+    if (!isValidModeId(mode_id)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    if (mode_id == current_mode_id_) {
+        LOG(DEBUG) << "Already in the specified mode " << mode_id;
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    }
+    WifiStatus status = handleChipConfiguration(lock, mode_id);
+    if (status.code != WifiStatusCode::SUCCESS) {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onChipReconfigureFailure(status).isOk()) {
+                LOG(ERROR) << "Failed to invoke onChipReconfigureFailure callback";
+            }
+        }
+        return status;
+    }
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onChipReconfigured(mode_id).isOk()) {
+            LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
+        }
+    }
+    current_mode_id_ = mode_id;
+    LOG(INFO) << "Configured chip in mode " << mode_id;
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+    legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(subsystemCallbackHandler_);
+
+    return status;
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
+    if (!isValidModeId(current_mode_id_)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), current_mode_id_};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
+}
+
+std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> WifiChip::requestChipDebugInfoInternal() {
+    V1_4::IWifiChip::ChipDebugInfo result;
+    legacy_hal::wifi_error legacy_status;
+    std::string driver_desc;
+    const auto ifname = getFirstActiveWlanIfaceName();
+    std::tie(legacy_status, driver_desc) = legacy_hal_.lock()->getDriverVersion(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver version: " << legacyErrorToString(legacy_status);
+        WifiStatus status =
+                createWifiStatusFromLegacyError(legacy_status, "failed to get driver version");
+        return {status, result};
+    }
+    result.driverDescription = driver_desc.c_str();
+
+    std::string firmware_desc;
+    std::tie(legacy_status, firmware_desc) = legacy_hal_.lock()->getFirmwareVersion(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware version: " << legacyErrorToString(legacy_status);
+        WifiStatus status =
+                createWifiStatusFromLegacyError(legacy_status, "failed to get firmware version");
+        return {status, result};
+    }
+    result.firmwareDescription = firmware_desc.c_str();
+
+    return {createWifiStatus(WifiStatusCode::SUCCESS), result};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>> WifiChip::requestDriverDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> driver_dump;
+    std::tie(legacy_status, driver_dump) =
+            legacy_hal_.lock()->requestDriverMemoryDump(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver debug dump: " << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), std::vector<uint8_t>()};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>> WifiChip::requestFirmwareDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> firmware_dump;
+    std::tie(legacy_status, firmware_dump) =
+            legacy_hal_.lock()->requestFirmwareMemoryDump(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware debug dump: " << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
+}
+
+WifiStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
+    legacy_hal::wifi_error legacy_status;
+    legacy_status = legacy_hal_.lock()->createVirtualInterface(
+            apVirtIf, hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+sp<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
+    std::vector<std::string> ap_instances;
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == ifname) {
+            ap_instances = it.second;
+        }
+    }
+    sp<WifiApIface> iface = new WifiApIface(ifname, ap_instances, legacy_hal_, iface_util_);
+    ap_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return iface;
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::createApIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = allocateApIfaceName();
+    WifiStatus status = createVirtualApInterface(ifname);
+    if (status.code != WifiStatusCode::SUCCESS) {
+        return {status, {}};
+    }
+    sp<WifiApIface> iface = newWifiApIface(ifname);
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::createBridgedApIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
+    if (ap_instances.size() < 2) {
+        LOG(ERROR) << "Fail to allocate two instances";
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
+    for (int i = 0; i < 2; i++) {
+        WifiStatus status = createVirtualApInterface(ap_instances[i]);
+        if (status.code != WifiStatusCode::SUCCESS) {
+            if (i != 0) {  // The failure happened when creating second virtual
+                           // iface.
+                legacy_hal_.lock()->deleteVirtualInterface(
+                        ap_instances.front());  // Remove the first virtual iface.
+            }
+            return {status, {}};
+        }
+    }
+    br_ifaces_ap_instances_[br_ifname] = ap_instances;
+    if (!iface_util_->createBridge(br_ifname)) {
+        LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
+        invalidateAndClearBridgedAp(br_ifname);
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    for (auto const& instance : ap_instances) {
+        // Bind ap instance interface to AP bridge
+        if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
+            LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
+            invalidateAndClearBridgedAp(br_ifname);
+            return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+        }
+    }
+    sp<WifiApIface> iface = newWifiApIface(br_ifname);
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getApIfaceNamesInternal() {
+    if (ap_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::getApIfaceInternal(
+        const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Invalidate & remove any dependent objects first.
+    // Note: This is probably not required because we never create
+    // nan/rtt objects over AP iface. But, there is no harm to do it
+    // here and not make that assumption all over the place.
+    invalidateAndRemoveDependencies(ifname);
+    // Clear the bridge interface and the iface instance.
+    invalidateAndClearBridgedAp(ifname);
+    invalidateAndClear(ap_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal(
+        const std::string& ifname, const std::string& ifInstanceName) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get() || ifInstanceName.empty()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Requires to remove one of the instance in bridge mode
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == ifname) {
+            std::vector<std::string> ap_instances = it.second;
+            for (auto const& iface : ap_instances) {
+                if (iface == ifInstanceName) {
+                    if (!iface_util_->removeIfaceFromBridge(it.first, iface)) {
+                        LOG(ERROR) << "Failed to remove interface: " << ifInstanceName << " from "
+                                   << ifname;
+                        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
+                    }
+                    legacy_hal::wifi_error legacy_status =
+                            legacy_hal_.lock()->deleteVirtualInterface(iface);
+                    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+                        LOG(ERROR) << "Failed to del interface: " << iface << " "
+                                   << legacyErrorToString(legacy_status);
+                        return createWifiStatusFromLegacyError(legacy_status);
+                    }
+                    ap_instances.erase(
+                            std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName),
+                            ap_instances.end());
+                    br_ifaces_ap_instances_[ifname] = ap_instances;
+                    break;
+                }
+            }
+            break;
+        }
+    }
+    iface->removeInstance(ifInstanceName);
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::createNanIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    bool is_dedicated_iface = true;
+    std::string ifname = getPredefinedNanIfaceName();
+    if (ifname.empty() || !iface_util_->ifNameToIndex(ifname)) {
+        // Use the first shared STA iface (wlan0) if a dedicated aware iface is
+        // not defined.
+        ifname = getFirstActiveWlanIfaceName();
+        is_dedicated_iface = false;
+    }
+    sp<WifiNanIface> iface = new WifiNanIface(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
+    nan_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getNanIfaceNamesInternal() {
+    if (nan_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::getNanIfaceInternal(
+        const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(nan_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = getPredefinedP2pIfaceName();
+    sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
+    p2p_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getP2pIfaceNamesInternal() {
+    if (p2p_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(p2p_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::createStaIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = allocateStaIfaceName();
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->createVirtualInterface(
+            ifname, hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
+    sta_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getStaIfaceNamesInternal() {
+    if (sta_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::getStaIfaceInternal(
+        const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Invalidate & remove any dependent objects first.
+    invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
+    invalidateAndClear(sta_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_0::IWifiRttController>> WifiChip::createRttControllerInternal(
+        const sp<IWifiIface>& /*bound_iface*/) {
+    LOG(ERROR) << "createRttController is not supported on this HAL";
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+WifiChip::getDebugRingBuffersStatusInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_ring_buffer_status> legacy_ring_buffer_status_vec;
+    std::tie(legacy_status, legacy_ring_buffer_status_vec) =
+            legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
+                legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_ring_buffer_status_vec};
+}
+
+WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
+        const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
+    WifiStatus status = registerDebugRingBufferCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRingBufferLogging(
+            getFirstActiveWlanIfaceName(), ring_name,
+            static_cast<std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(verbose_level),
+            max_interval_in_sec, min_data_size_in_bytes);
+    ringbuffer_map_.insert(
+            std::pair<std::string, Ringbuffer>(ring_name, Ringbuffer(kMaxBufferSizeBytes)));
+    // if verbose logging enabled, turn up HAL daemon logging as well.
+    if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) {
+        android::base::SetMinimumLogSeverity(android::base::DEBUG);
+    } else {
+        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(const hidl_string& ring_name) {
+    WifiStatus status = registerDebugRingBufferCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(), ring_name);
+
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::flushRingBufferToFileInternal() {
+    if (!writeRingbufferFilesInternal()) {
+        LOG(ERROR) << "Error writing files to flash";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->deregisterRingBufferCallbackHandler(getFirstActiveWlanIfaceName());
+    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+        debug_ring_buffer_cb_registered_ = false;
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+WifiChip::getDebugHostWakeReasonStatsInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::WakeReasonStats legacy_stats;
+    std::tie(legacy_status, legacy_stats) =
+            legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    WifiDebugHostWakeReasonStats hidl_stats;
+    if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats, &hidl_stats)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status;
+    if (enable) {
+        android::wp<WifiChip> weak_ptr_this(this);
+        const auto& on_alert_callback = [weak_ptr_this](int32_t error_code,
+                                                        std::vector<uint8_t> debug_data) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onDebugErrorAlert(error_code, debug_data).isOk()) {
+                    LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
+                }
+            }
+        };
+        legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
+                getFirstActiveWlanIfaceName(), on_alert_callback);
+    } else {
+        legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
+                getFirstActiveWlanIfaceName());
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+            getFirstActiveWlanIfaceName(),
+            hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::resetTxPowerScenarioInternal() {
+    auto legacy_status = legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
+    auto legacy_status = legacy_hal_.lock()->setLatencyMode(
+            getFirstActiveWlanIfaceName(), hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_2(
+        const sp<V1_2::IWifiChipEventCallback>& /* event_callback */) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+            getFirstActiveWlanIfaceName(),
+            hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
+    // Deprecated support for this callback.
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_5() {
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    uint32_t legacy_logger_feature_set;
+    const auto ifname = getFirstActiveWlanIfaceName();
+    std::tie(legacy_status, legacy_feature_set) =
+            legacy_hal_.lock()->getSupportedFeatureSet(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), 0};
+    }
+    std::tie(legacy_status, legacy_logger_feature_set) =
+            legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t hidl_caps;
+    if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+                legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiRttController>> WifiChip::createRttControllerInternal_1_4(
+        const sp<IWifiIface>& /*bound_iface*/) {
+    LOG(ERROR) << "createRttController_1_4 is not supported on this HAL";
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_4(
+        const sp<V1_4::IWifiChipEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::setMultiStaPrimaryConnectionInternal(const std::string& ifname) {
+    auto legacy_status = legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setMultiStaUseCaseInternal(MultiStaUseCase use_case) {
+    auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase(
+            hidl_struct_util::convertHidlMultiStaUseCaseToLegacy(use_case));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setCoexUnsafeChannelsInternal(std::vector<CoexUnsafeChannel> unsafe_channels,
+                                                   uint32_t restrictions) {
+    std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
+    if (!hidl_struct_util::convertHidlVectorOfCoexUnsafeChannelToLegacy(unsafe_channels,
+                                                                        &legacy_unsafe_channels)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    uint32_t legacy_restrictions = 0;
+    if (restrictions & CoexRestriction::WIFI_DIRECT) {
+        legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_DIRECT;
+    }
+    if (restrictions & CoexRestriction::SOFTAP) {
+        legacy_restrictions |= legacy_hal::wifi_coex_restriction::SOFTAP;
+    }
+    if (restrictions & CoexRestriction::WIFI_AWARE) {
+        legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_AWARE;
+    }
+    auto legacy_status =
+            legacy_hal_.lock()->setCoexUnsafeChannels(legacy_unsafe_channels, legacy_restrictions);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setCountryCodeInternal(const std::array<int8_t, 2>& code) {
+    auto legacy_status = legacy_hal_.lock()->setCountryCode(getFirstActiveWlanIfaceName(), code);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> WifiChip::getUsableChannelsInternal(
+        WifiBand /*band*/, uint32_t /*ifaceModeMask*/, uint32_t /*filterMask*/) {
+    LOG(ERROR) << "getUsableChannels is not supported on this HAL";
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiChip::triggerSubsystemRestartInternal() {
+    auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, sp<V1_6::IWifiRttController>> WifiChip::createRttControllerInternal_1_6(
+        const sp<IWifiIface>& bound_iface) {
+    if (sta_ifaces_.size() == 0 && !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+        LOG(ERROR) << "createRttControllerInternal_1_6: Chip cannot support STAs "
+                      "(and RTT by extension)";
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    sp<WifiRttController> rtt =
+            new WifiRttController(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
+    rtt_controllers_.emplace_back(rtt);
+    return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
+}
+
+std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> WifiChip::getUsableChannelsInternal_1_6(
+        WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask) {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_usable_channel> legacy_usable_channels;
+    std::tie(legacy_status, legacy_usable_channels) = legacy_hal_.lock()->getUsableChannels(
+            hidl_struct_util::convertHidlWifiBandToLegacyMacBand(band),
+            hidl_struct_util::convertHidlWifiIfaceModeToLegacy(ifaceModeMask),
+            hidl_struct_util::convertHidlUsableChannelFilterToLegacy(filterMask));
+
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<V1_6::WifiUsableChannel> hidl_usable_channels;
+    if (!hidl_struct_util::convertLegacyWifiUsableChannelsToHidl(legacy_usable_channels,
+                                                                 &hidl_usable_channels)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_usable_channels};
+}
+
+WifiStatus WifiChip::handleChipConfiguration(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id) {
+    // If the chip is already configured in a different mode, stop
+    // the legacy HAL and then start it after firmware mode change.
+    if (isValidModeId(current_mode_id_)) {
+        LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_ << " to mode " << mode_id;
+        invalidateAndRemoveAllIfaces();
+        legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stop(lock, []() {});
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL: " << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+    }
+    // Firmware mode change not needed for V2 devices.
+    bool success = true;
+    if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+    } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+    }
+    if (!success) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to start legacy HAL: " << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    // Every time the HAL is restarted, we need to register the
+    // radio mode change callback.
+    WifiStatus status = registerRadioModeChangeCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        // This probably is not a critical failure?
+        LOG(ERROR) << "Failed to register radio mode change callback";
+    }
+    // Extract and save the version information into property.
+    std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> version_info;
+    version_info = WifiChip::requestChipDebugInfoInternal();
+    if (WifiStatusCode::SUCCESS == version_info.first.code) {
+        property_set("vendor.wlan.firmware.version",
+                     version_info.second.firmwareDescription.c_str());
+        property_set("vendor.wlan.driver.version", version_info.second.driverDescription.c_str());
+    }
+
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::registerDebugRingBufferCallback() {
+    if (debug_ring_buffer_cb_registered_) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    }
+
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_ring_buffer_data_callback =
+            [weak_ptr_this](const std::string& name, const std::vector<uint8_t>& data,
+                            const legacy_hal::wifi_ring_buffer_status& status) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                WifiDebugRingBufferStatus hidl_status;
+                if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(status,
+                                                                                &hidl_status)) {
+                    LOG(ERROR) << "Error converting ring buffer status";
+                    return;
+                }
+                {
+                    std::unique_lock<std::mutex> lk(shared_ptr_this->lock_t);
+                    const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
+                    if (target != shared_ptr_this->ringbuffer_map_.end()) {
+                        Ringbuffer& cur_buffer = target->second;
+                        cur_buffer.append(data);
+                    } else {
+                        LOG(ERROR) << "Ringname " << name << " not found";
+                        return;
+                    }
+                    // unique_lock unlocked here
+                }
+            };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler(
+            getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
+
+    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+        debug_ring_buffer_cb_registered_ = true;
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerRadioModeChangeCallback() {
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_radio_mode_change_callback =
+            [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+                if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(mac_infos,
+                                                                       &hidl_radio_mode_infos)) {
+                    LOG(ERROR) << "Error converting wifi mac info";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4"
+                                   << " callback on: " << toString(callback);
+                    }
+                }
+            };
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
+                    getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::vector<V1_4::IWifiChip::ChipIfaceCombination> WifiChip::getCurrentModeIfaceCombinations() {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return {};
+    }
+    for (const auto& mode : modes_) {
+        if (mode.id == current_mode_id_) {
+            return mode.availableCombinations;
+        }
+    }
+    CHECK(0) << "Expected to find iface combinations for current mode!";
+    return {};
+}
+
+// Returns a map indexed by IfaceType with the number of ifaces currently
+// created of the corresponding type.
+std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
+    std::map<IfaceType, size_t> iface_counts;
+    iface_counts[IfaceType::AP] = ap_ifaces_.size();
+    iface_counts[IfaceType::NAN] = nan_ifaces_.size();
+    iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
+    iface_counts[IfaceType::STA] = sta_ifaces_.size();
+    return iface_counts;
+}
+
+// This expands the provided iface combinations to a more parseable
+// form. Returns a vector of available combinations possible with the number
+// of ifaces of each type in the combination.
+// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
+std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
+        const V1_4::IWifiChip::ChipIfaceCombination& combination) {
+    uint32_t num_expanded_combos = 1;
+    for (const auto& limit : combination.limits) {
+        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+            num_expanded_combos *= limit.types.size();
+        }
+    }
+
+    // Allocate the vector of expanded combos and reset all iface counts to 0
+    // in each combo.
+    std::vector<std::map<IfaceType, size_t>> expanded_combos;
+    expanded_combos.resize(num_expanded_combos);
+    for (auto& expanded_combo : expanded_combos) {
+        for (const auto type : {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+            expanded_combo[type] = 0;
+        }
+    }
+    uint32_t span = num_expanded_combos;
+    for (const auto& limit : combination.limits) {
+        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+            span /= limit.types.size();
+            for (uint32_t k = 0; k < num_expanded_combos; ++k) {
+                const auto iface_type = limit.types[(k / span) % limit.types.size()];
+                expanded_combos[k][iface_type]++;
+            }
+        }
+    }
+    return expanded_combos;
+}
+
+bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+        const std::map<IfaceType, size_t>& expanded_combo, IfaceType requested_type) {
+    const auto current_combo = getCurrentIfaceCombination();
+
+    // Check if we have space for 1 more iface of |type| in this combo
+    for (const auto type : {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+        size_t num_ifaces_needed = current_combo.at(type);
+        if (type == requested_type) {
+            num_ifaces_needed++;
+        }
+        size_t num_ifaces_allowed = expanded_combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode
+//    with the iface combination that is already active.
+bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType requested_type) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeIfaceCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandIfaceCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(expanded_combo,
+                                                                         requested_type)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// Note: This does not consider ifaces already active. It only checks if the
+// provided expanded iface combination can support the requested combo.
+bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
+        const std::map<IfaceType, size_t>& expanded_combo,
+        const std::map<IfaceType, size_t>& req_combo) {
+    // Check if we have space for 1 more iface of |type| in this combo
+    for (const auto type : {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+        if (req_combo.count(type) == 0) {
+            // Iface of "type" not in the req_combo.
+            continue;
+        }
+        size_t num_ifaces_needed = req_combo.at(type);
+        size_t num_ifaces_allowed = expanded_combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface combo can be added to the current mode.
+// Note: This does not consider ifaces already active. It only checks if the
+// current mode can support the requested combo.
+bool WifiChip::canCurrentModeSupportIfaceCombo(const std::map<IfaceType, size_t>& req_combo) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeIfaceCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandIfaceCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedIfaceComboSupportIfaceCombo(expanded_combo, req_combo)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
+    // Check if we can support at least 1 iface of type.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[requested_type] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+bool WifiChip::isValidModeId(ChipModeId mode_id) {
+    for (const auto& mode : modes_) {
+        if (mode.id == mode_id) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
+    // Check if we can support at least 1 STA & 1 AP concurrently.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[IfaceType::AP] = 1;
+    req_iface_combo[IfaceType::STA] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+bool WifiChip::isDualStaConcurrencyAllowedInCurrentMode() {
+    // Check if we can support at least 2 STA concurrently.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[IfaceType::STA] = 2;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+std::string WifiChip::getFirstActiveWlanIfaceName() {
+    if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
+    if (ap_ifaces_.size() > 0) {
+        // If the first active wlan iface is bridged iface.
+        // Return first instance name.
+        for (auto const& it : br_ifaces_ap_instances_) {
+            if (it.first == ap_ifaces_[0]->getName()) {
+                return it.second[0];
+            }
+        }
+        return ap_ifaces_[0]->getName();
+    }
+    // This could happen if the chip call is made before any STA/AP
+    // iface is created. Default to wlan0 for such cases.
+    LOG(WARNING) << "No active wlan interfaces in use! Using default";
+    return getWlanIfaceNameWithType(IfaceType::STA, 0);
+}
+
+// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
+// not already in use.
+// Note: This doesn't check the actual presence of these interfaces.
+std::string WifiChip::allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx) {
+    for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
+        const auto ifname = getWlanIfaceNameWithType(type, idx);
+        if (findUsingNameFromBridgedApInstances(ifname)) continue;
+        if (findUsingName(ap_ifaces_, ifname)) continue;
+        if (findUsingName(sta_ifaces_, ifname)) continue;
+        return ifname;
+    }
+    // This should never happen. We screwed up somewhere if it did.
+    CHECK(false) << "All wlan interfaces in use already!";
+    return {};
+}
+
+uint32_t WifiChip::startIdxOfApIface() {
+    if (isDualStaConcurrencyAllowedInCurrentMode()) {
+        // When the HAL support dual STAs, AP should start with idx 2.
+        return 2;
+    } else if (isStaApConcurrencyAllowedInCurrentMode()) {
+        //  When the HAL support STA + AP but it doesn't support dual STAs.
+        //  AP should start with idx 1.
+        return 1;
+    }
+    // No concurrency support.
+    return 0;
+}
+
+// AP iface names start with idx 1 for modes supporting
+// concurrent STA and not dual AP, else start with idx 0.
+std::string WifiChip::allocateApIfaceName() {
+    // Check if we have a dedicated iface for AP.
+    std::vector<std::string> ifnames = getPredefinedApIfaceNames(false);
+    if (!ifnames.empty()) {
+        return ifnames[0];
+    }
+    return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
+}
+
+std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
+    // Check if we have a dedicated iface for AP.
+    std::vector<std::string> instances = getPredefinedApIfaceNames(true);
+    if (instances.size() == 2) {
+        return instances;
+    } else {
+        int num_ifaces_need_to_allocate = 2 - instances.size();
+        for (int i = 0; i < num_ifaces_need_to_allocate; i++) {
+            std::string instance_name =
+                    allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface() + i);
+            if (!instance_name.empty()) {
+                instances.push_back(instance_name);
+            }
+        }
+    }
+    return instances;
+}
+
+// STA iface names start with idx 0.
+// Primary STA iface will always be 0.
+std::string WifiChip::allocateStaIfaceName() {
+    return allocateApOrStaIfaceName(IfaceType::STA, 0);
+}
+
+bool WifiChip::writeRingbufferFilesInternal() {
+    if (!removeOldFilesInternal()) {
+        LOG(ERROR) << "Error occurred while deleting old tombstone files";
+        return false;
+    }
+    // write ringbuffers to file
+    {
+        std::unique_lock<std::mutex> lk(lock_t);
+        for (auto& item : ringbuffer_map_) {
+            Ringbuffer& cur_buffer = item.second;
+            if (cur_buffer.getData().empty()) {
+                continue;
+            }
+            const std::string file_path_raw = kTombstoneFolderPath + item.first + "XXXXXXXXXX";
+            const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
+            if (dump_fd == -1) {
+                PLOG(ERROR) << "create file failed";
+                return false;
+            }
+            unique_fd file_auto_closer(dump_fd);
+            for (const auto& cur_block : cur_buffer.getData()) {
+                if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) ==
+                    -1) {
+                    PLOG(ERROR) << "Error writing to file";
+                }
+            }
+            cur_buffer.clear();
+        }
+        // unique_lock unlocked here
+    }
+    return true;
+}
+
+std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
+    std::string ifname;
+
+    // let the legacy hal override the interface name
+    legacy_hal::wifi_error err = legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
+    if (err == legacy_hal::WIFI_SUCCESS) return ifname;
+
+    return getWlanIfaceName(idx);
+}
+
+void WifiChip::invalidateAndClearBridgedApAll() {
+    for (auto const& it : br_ifaces_ap_instances_) {
+        for (auto const& iface : it.second) {
+            iface_util_->removeIfaceFromBridge(it.first, iface);
+            legacy_hal_.lock()->deleteVirtualInterface(iface);
+        }
+        iface_util_->deleteBridge(it.first);
+    }
+    br_ifaces_ap_instances_.clear();
+}
+
+void WifiChip::invalidateAndClearBridgedAp(const std::string& br_name) {
+    if (br_name.empty()) return;
+    // delete managed interfaces
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == br_name) {
+            for (auto const& iface : it.second) {
+                iface_util_->removeIfaceFromBridge(br_name, iface);
+                legacy_hal_.lock()->deleteVirtualInterface(iface);
+            }
+            iface_util_->deleteBridge(br_name);
+            br_ifaces_ap_instances_.erase(br_name);
+            break;
+        }
+    }
+    return;
+}
+
+bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == name) {
+            return true;
+        }
+        for (auto const& iface : it.second) {
+            if (iface == name) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_chip.h b/wifi/1.6/default/wifi_chip.h
new file mode 100644
index 0000000..61ac03d
--- /dev/null
+++ b/wifi/1.6/default/wifi_chip.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_CHIP_H_
+#define WIFI_CHIP_H_
+
+#include <list>
+#include <map>
+#include <mutex>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/IWifiRttController.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
+
+#include "hidl_callback_util.h"
+#include "ringbuffer.h"
+#include "wifi_ap_iface.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+#include "wifi_nan_iface.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_sta_iface.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using V1_5::WifiBand;
+
+/**
+ * HIDL interface object used to control a Wifi HAL chip instance.
+ * Since there is only a single chip instance used today, there is no
+ * identifying handle information stored here.
+ */
+class WifiChip : public V1_6::IWifiChip {
+  public:
+    WifiChip(ChipId chip_id, bool is_primary,
+             const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+             const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+             const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+             const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+             const std::function<void(const std::string&)>& subsystemCallbackHandler);
+    // HIDL does not provide a built-in mechanism to let the server invalidate
+    // a HIDL interface object after creation. If any client process holds onto
+    // a reference to the object in their context, any method calls on that
+    // reference will continue to be directed to the server.
+    //
+    // However Wifi HAL needs to control the lifetime of these objects. So, add
+    // a public |invalidate| method to |WifiChip| and it's child objects. This
+    // will be used to mark an object invalid when either:
+    // a) Wifi HAL is stopped, or
+    // b) Wifi Chip is reconfigured.
+    //
+    // All HIDL method implementations should check if the object is still
+    // marked valid before processing them.
+    void invalidate();
+    bool isValid();
+    std::set<sp<V1_4::IWifiChipEventCallback>> getEventCallbacks();
+
+    // HIDL methods exposed.
+    Return<void> getId(getId_cb hidl_status_cb) override;
+    // Deprecated support for this callback
+    Return<void> registerEventCallback(const sp<V1_0::IWifiChipEventCallback>& event_callback,
+                                       registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> getAvailableModes(getAvailableModes_cb hidl_status_cb) override;
+    Return<void> configureChip(ChipModeId mode_id, configureChip_cb hidl_status_cb) override;
+    Return<void> getMode(getMode_cb hidl_status_cb) override;
+    Return<void> requestChipDebugInfo(requestChipDebugInfo_cb hidl_status_cb) override;
+    Return<void> requestDriverDebugDump(requestDriverDebugDump_cb hidl_status_cb) override;
+    Return<void> requestFirmwareDebugDump(requestFirmwareDebugDump_cb hidl_status_cb) override;
+    Return<void> createApIface(createApIface_cb hidl_status_cb) override;
+    Return<void> createBridgedApIface(createBridgedApIface_cb hidl_status_cb) override;
+    Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
+    Return<void> getApIface(const hidl_string& ifname, getApIface_cb hidl_status_cb) override;
+    Return<void> removeApIface(const hidl_string& ifname, removeApIface_cb hidl_status_cb) override;
+    Return<void> removeIfaceInstanceFromBridgedApIface(
+            const hidl_string& brIfaceName, const hidl_string& ifaceInstanceName,
+            removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) override;
+    Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
+    Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
+    Return<void> getNanIface(const hidl_string& ifname, getNanIface_cb hidl_status_cb) override;
+    Return<void> removeNanIface(const hidl_string& ifname,
+                                removeNanIface_cb hidl_status_cb) override;
+    Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
+    Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
+    Return<void> getP2pIface(const hidl_string& ifname, getP2pIface_cb hidl_status_cb) override;
+    Return<void> removeP2pIface(const hidl_string& ifname,
+                                removeP2pIface_cb hidl_status_cb) override;
+    Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
+    Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
+    Return<void> getStaIface(const hidl_string& ifname, getStaIface_cb hidl_status_cb) override;
+    Return<void> removeStaIface(const hidl_string& ifname,
+                                removeStaIface_cb hidl_status_cb) override;
+    Return<void> createRttController(const sp<IWifiIface>& bound_iface,
+                                     createRttController_cb hidl_status_cb) override;
+    Return<void> getDebugRingBuffersStatus(getDebugRingBuffersStatus_cb hidl_status_cb) override;
+    Return<void> startLoggingToDebugRingBuffer(
+            const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+            uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+            startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> forceDumpToDebugRingBuffer(const hidl_string& ring_name,
+                                            forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> flushRingBufferToFile(flushRingBufferToFile_cb hidl_status_cb) override;
+    Return<void> stopLoggingToDebugRingBuffer(
+            stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> getDebugHostWakeReasonStats(
+            getDebugHostWakeReasonStats_cb hidl_status_cb) override;
+    Return<void> enableDebugErrorAlerts(bool enable,
+                                        enableDebugErrorAlerts_cb hidl_status_cb) override;
+    Return<void> selectTxPowerScenario(V1_1::IWifiChip::TxPowerScenario scenario,
+                                       selectTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> resetTxPowerScenario(resetTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> setLatencyMode(LatencyMode mode, setLatencyMode_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_2(const sp<V1_2::IWifiChipEventCallback>& event_callback,
+                                           registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> selectTxPowerScenario_1_2(TxPowerScenario scenario,
+                                           selectTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_3(getCapabilities_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_5(getCapabilities_1_5_cb hidl_status_cb) override;
+    Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
+    Return<void> createRttController_1_4(const sp<IWifiIface>& bound_iface,
+                                         createRttController_1_4_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_4(const sp<V1_4::IWifiChipEventCallback>& event_callback,
+                                           registerEventCallback_1_4_cb hidl_status_cb) override;
+    Return<void> setMultiStaPrimaryConnection(
+            const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) override;
+    Return<void> setMultiStaUseCase(MultiStaUseCase use_case,
+                                    setMultiStaUseCase_cb hidl_status_cb) override;
+    Return<void> setCoexUnsafeChannels(const hidl_vec<CoexUnsafeChannel>& unsafe_channels,
+                                       hidl_bitfield<IfaceType> restrictions,
+                                       setCoexUnsafeChannels_cb hidl_status_cb) override;
+    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
+                                setCountryCode_cb _hidl_cb) override;
+    Return<void> getUsableChannels(WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+                                   hidl_bitfield<V1_5::IWifiChip::UsableChannelFilter> filterMask,
+                                   getUsableChannels_cb _hidl_cb) override;
+    Return<void> triggerSubsystemRestart(triggerSubsystemRestart_cb hidl_status_cb) override;
+    Return<void> createRttController_1_6(const sp<IWifiIface>& bound_iface,
+                                         createRttController_1_6_cb hidl_status_cb) override;
+    Return<void> getUsableChannels_1_6(WifiBand band,
+                                       hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+                                       hidl_bitfield<UsableChannelFilter> filterMask,
+                                       getUsableChannels_1_6_cb _hidl_cb) override;
+
+  private:
+    void invalidateAndRemoveAllIfaces();
+    // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
+    // invalidated & removed.
+    void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
+
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, ChipId> getIdInternal();
+    // Deprecated support for this callback
+    WifiStatus registerEventCallbackInternal(
+            const sp<V1_0::IWifiChipEventCallback>& event_callback);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+    std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
+    WifiStatus configureChipInternal(std::unique_lock<std::recursive_mutex>* lock,
+                                     ChipModeId mode_id);
+    std::pair<WifiStatus, uint32_t> getModeInternal();
+    std::pair<WifiStatus, IWifiChip::ChipDebugInfo> requestChipDebugInfoInternal();
+    std::pair<WifiStatus, std::vector<uint8_t>> requestDriverDebugDumpInternal();
+    std::pair<WifiStatus, std::vector<uint8_t>> requestFirmwareDebugDumpInternal();
+    sp<WifiApIface> newWifiApIface(std::string& ifname);
+    WifiStatus createVirtualApInterface(const std::string& apVirtIf);
+    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createApIfaceInternal();
+    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createBridgedApIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
+    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> getApIfaceInternal(const std::string& ifname);
+    WifiStatus removeApIfaceInternal(const std::string& ifname);
+    WifiStatus removeIfaceInstanceFromBridgedApIfaceInternal(const std::string& brIfaceName,
+                                                             const std::string& ifInstanceName);
+    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
+    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(const std::string& ifname);
+    WifiStatus removeNanIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(const std::string& ifname);
+    WifiStatus removeP2pIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> createStaIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
+    std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> getStaIfaceInternal(const std::string& ifname);
+    WifiStatus removeStaIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<V1_0::IWifiRttController>> createRttControllerInternal(
+            const sp<IWifiIface>& bound_iface);
+    std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+    getDebugRingBuffersStatusInternal();
+    WifiStatus startLoggingToDebugRingBufferInternal(const hidl_string& ring_name,
+                                                     WifiDebugRingBufferVerboseLevel verbose_level,
+                                                     uint32_t max_interval_in_sec,
+                                                     uint32_t min_data_size_in_bytes);
+    WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
+    WifiStatus flushRingBufferToFileInternal();
+    WifiStatus stopLoggingToDebugRingBufferInternal();
+    std::pair<WifiStatus, WifiDebugHostWakeReasonStats> getDebugHostWakeReasonStatsInternal();
+    WifiStatus enableDebugErrorAlertsInternal(bool enable);
+    WifiStatus selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario);
+    WifiStatus resetTxPowerScenarioInternal();
+    WifiStatus setLatencyModeInternal(LatencyMode mode);
+    WifiStatus registerEventCallbackInternal_1_2(
+            const sp<V1_2::IWifiChipEventCallback>& event_callback);
+    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_5();
+    std::pair<WifiStatus, sp<V1_4::IWifiRttController>> createRttControllerInternal_1_4(
+            const sp<IWifiIface>& bound_iface);
+    WifiStatus registerEventCallbackInternal_1_4(
+            const sp<V1_4::IWifiChipEventCallback>& event_callback);
+    WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
+    WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case);
+    WifiStatus setCoexUnsafeChannelsInternal(std::vector<CoexUnsafeChannel> unsafe_channels,
+                                             uint32_t restrictions);
+    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
+    std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> getUsableChannelsInternal(
+            WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
+    WifiStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
+                                       ChipModeId mode_id);
+    WifiStatus registerDebugRingBufferCallback();
+    WifiStatus registerRadioModeChangeCallback();
+    std::vector<V1_4::IWifiChip::ChipIfaceCombination> getCurrentModeIfaceCombinations();
+    std::map<IfaceType, size_t> getCurrentIfaceCombination();
+    std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
+            const V1_4::IWifiChip::ChipIfaceCombination& combination);
+    bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+            const std::map<IfaceType, size_t>& expanded_combo, IfaceType requested_type);
+    bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType requested_type);
+    bool canExpandedIfaceComboSupportIfaceCombo(const std::map<IfaceType, size_t>& expanded_combo,
+                                                const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceCombo(const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
+    bool isValidModeId(ChipModeId mode_id);
+    bool isStaApConcurrencyAllowedInCurrentMode();
+    bool isDualStaConcurrencyAllowedInCurrentMode();
+    uint32_t startIdxOfApIface();
+    std::string getFirstActiveWlanIfaceName();
+    std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
+    std::string allocateApIfaceName();
+    std::vector<std::string> allocateBridgedApInstanceNames();
+    std::string allocateStaIfaceName();
+    bool writeRingbufferFilesInternal();
+    std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
+    void invalidateAndClearBridgedApAll();
+    void invalidateAndClearBridgedAp(const std::string& br_name);
+    bool findUsingNameFromBridgedApInstances(const std::string& name);
+    WifiStatus triggerSubsystemRestartInternal();
+    std::pair<WifiStatus, sp<V1_6::IWifiRttController>> createRttControllerInternal_1_6(
+            const sp<IWifiIface>& bound_iface);
+    std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> getUsableChannelsInternal_1_6(
+            WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
+
+    ChipId chip_id_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    std::vector<sp<WifiApIface>> ap_ifaces_;
+    std::vector<sp<WifiNanIface>> nan_ifaces_;
+    std::vector<sp<WifiP2pIface>> p2p_ifaces_;
+    std::vector<sp<WifiStaIface>> sta_ifaces_;
+    std::vector<sp<WifiRttController>> rtt_controllers_;
+    std::map<std::string, Ringbuffer> ringbuffer_map_;
+    bool is_valid_;
+    // Members pertaining to chip configuration.
+    uint32_t current_mode_id_;
+    std::mutex lock_t;
+    std::vector<V1_4::IWifiChip::ChipMode> modes_;
+    // The legacy ring buffer callback API has only a global callback
+    // registration mechanism. Use this to check if we have already
+    // registered a callback.
+    bool debug_ring_buffer_cb_registered_;
+    hidl_callback_util::HidlCallbackHandler<V1_4::IWifiChipEventCallback> event_cb_handler_;
+
+    const std::function<void(const std::string&)> subsystemCallbackHandler_;
+    std::map<std::string, std::vector<std::string>> br_ifaces_ap_instances_;
+    DISALLOW_COPY_AND_ASSIGN(WifiChip);
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_CHIP_H_
diff --git a/wifi/1.6/default/wifi_feature_flags.cpp b/wifi/1.6/default/wifi_feature_flags.cpp
new file mode 100644
index 0000000..71319e1
--- /dev/null
+++ b/wifi/1.6/default/wifi_feature_flags.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2016 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 <string>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+using V1_0::ChipModeId;
+using V1_0::IfaceType;
+using V1_0::IWifiChip;
+
+/* The chip may either have a single mode supporting any number of combinations,
+ * or a fixed dual-mode (so it involves firmware loading to switch between
+ * modes) setting. If there is a need to support more modes, it needs to be
+ * implemented manually in WiFi HAL (see changeFirmwareMode in
+ * WifiChip::handleChipConfiguration).
+ *
+ * Supported combinations are defined in device's makefile, for example:
+ *    WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
+ *    WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
+ * What means:
+ *    Interface combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
+ *                             operations.
+ *    Interface combination 2: 1 STA and 2 AP concurrent iface operations.
+ *
+ * For backward compatibility, the following makefile flags can be used to
+ * generate combinations list:
+ *  - WIFI_HIDL_FEATURE_DUAL_INTERFACE
+ *  - WIFI_HIDL_FEATURE_DISABLE_AP
+ *  - WIFI_HIDL_FEATURE_AWARE
+ * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
+ * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
+ * two interface combinations:
+ *    Interface Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
+ *                             concurrent iface operations.
+ *    Interface Combination 2: Will support 1 STA and 1 AP concurrent
+ *                             iface operations.
+ *
+ * The only dual-mode configuration supported is for alternating STA and AP
+ * mode, that may involve firmware reloading. In such case, there are 2 separate
+ * modes of operation with 1 interface combination each:
+ *    Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
+ *                       concurrent iface operations.
+ *    Mode 2 (AP mode): Will support 1 AP iface operation.
+ *
+ * If Aware is enabled, the iface combination will be modified to support either
+ * P2P or NAN in place of just P2P.
+ */
+// clang-format off
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
+// former V2 (fixed dual interface) setup expressed as V3
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+#  ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+#    ifdef WIFI_HIDL_FEATURE_AWARE
+//     1 STA + 1 of (P2P or NAN)
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+#    else
+//     1 STA + 1 P2P
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+#    endif
+#  else
+#    ifdef WIFI_HIDL_FEATURE_AWARE
+//     (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+                                              {{{STA}, 1}, {{P2P, NAN}, 1}}
+#    else
+//     (1 STA + 1 AP) or (1 STA + 1 P2P)
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+                                              {{{STA}, 1}, {{P2P}, 1}}
+#    endif
+#  endif
+#else
+// V1 (fixed single interface, dual-mode chip)
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV1Sta;
+#  ifdef WIFI_HIDL_FEATURE_AWARE
+//   1 STA + 1 of (P2P or NAN)
+#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+#  else
+//   1 STA + 1 P2P
+#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+#  endif
+
+#  ifndef WIFI_HIDL_FEATURE_DISABLE_AP
+#    define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
+#  endif
+#endif
+// clang-format on
+
+/**
+ * Helper class to convert a collection of combination limits to a combination.
+ *
+ * The main point here is to simplify the syntax required by
+ * WIFI_HAL_INTERFACE_COMBINATIONS.
+ */
+struct ChipIfaceCombination : public hidl_vec<IWifiChip::ChipIfaceCombinationLimit> {
+    ChipIfaceCombination(const std::initializer_list<IWifiChip::ChipIfaceCombinationLimit> list)
+        : hidl_vec(list) {}
+
+    operator IWifiChip::ChipIfaceCombination() const { return {*this}; }
+
+    static hidl_vec<IWifiChip::ChipIfaceCombination> make_vec(
+            const std::initializer_list<ChipIfaceCombination> list) {
+        return hidl_vec<IWifiChip::ChipIfaceCombination>(  //
+                std::begin(list), std::end(list));
+    }
+};
+
+#define STA IfaceType::STA
+#define AP IfaceType::AP
+#define P2P IfaceType::P2P
+#define NAN IfaceType::NAN
+static const std::vector<IWifiChip::ChipMode> kChipModesPrimary{
+        {kMainModeId, ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
+        {chip_mode_ids::kV1Ap,
+         ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
+#endif
+};
+
+static const std::vector<IWifiChip::ChipMode> kChipModesSecondary{
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
+        {chip_mode_ids::kV3,
+         ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
+#endif
+};
+
+constexpr char kDebugPresetInterfaceCombinationIdxProperty[] =
+        "persist.vendor.debug.wifi.hal.preset_interface_combination_idx";
+// List of pre-defined interface combinations that can be enabled at runtime via
+// setting the property: "kDebugPresetInterfaceCombinationIdxProperty" to the
+// corresponding index value.
+static const std::vector<std::pair<std::string, std::vector<IWifiChip::ChipMode>>> kDebugChipModes{
+        // Legacy combination - No STA/AP concurrencies.
+        // 0 - (1 AP) or (1 STA + 1 of (P2P or NAN))
+        {"No STA/AP Concurrency",
+         {{kMainModeId,
+           ChipIfaceCombination::make_vec({{{{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + AP concurrency
+        // 1 - (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+        {"STA + AP Concurrency",
+         {{kMainModeId, ChipIfaceCombination::make_vec(
+                                {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + STA concurrency
+        // 2 - (1 STA + 1 AP) or (2 STA + 1 of (P2P or NAN))
+        {"Dual STA Concurrency",
+         {{kMainModeId, ChipIfaceCombination::make_vec(
+                                {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
+
+        // AP + AP + STA concurrency
+        // 3 - (1 STA + 2 AP) or (1 STA + 1 of (P2P or NAN))
+        {"Dual AP Concurrency",
+         {{kMainModeId, ChipIfaceCombination::make_vec(
+                                {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + STA concurrency and AP + AP + STA concurrency
+        // 4 - (1 STA + 2 AP) or (2 STA + 1 of (P2P or NAN))
+        {"Dual STA & Dual AP Concurrency",
+         {{kMainModeId, ChipIfaceCombination::make_vec(
+                                {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + STA concurrency
+        // 5 - (1 STA + 1 AP (bridged or single) | P2P | NAN), or (2 STA))
+        {"Dual STA or STA plus single other interface",
+         {{kMainModeId,
+           ChipIfaceCombination::make_vec({{{{STA}, 1}, {{P2P, NAN, AP}, 1}}, {{{STA}, 2}}})}}}};
+
+#undef STA
+#undef AP
+#undef P2P
+#undef NAN
+
+#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+#pragma message                                                                   \
+        "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
+        "'config_wifi_ap_randomization_supported' in "                            \
+        "frameworks/base/core/res/res/values/config.xml in the device overlay "   \
+        "instead"
+#endif  // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+
+WifiFeatureFlags::WifiFeatureFlags() {}
+
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModesForPrimary() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    auto res = property_get(kDebugPresetInterfaceCombinationIdxProperty, buffer.data(), nullptr);
+    // Debug propety not set, use the device preset interface combination.
+    if (res <= 0) return kChipModesPrimary;
+
+    // Debug propety set, use one of the debug preset interface combination.
+    unsigned long idx = std::stoul(buffer.data());
+    if (idx >= kDebugChipModes.size()) {
+        LOG(ERROR) << "Invalid index set in property: "
+                   << kDebugPresetInterfaceCombinationIdxProperty;
+        return kChipModesPrimary;
+    }
+    std::string name;
+    std::vector<IWifiChip::ChipMode> chip_modes;
+    std::tie(name, chip_modes) = kDebugChipModes[idx];
+    LOG(INFO) << "Using debug chip mode: <" << name
+              << "> set via property: " << kDebugPresetInterfaceCombinationIdxProperty;
+    return chip_modes;
+}
+
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(bool is_primary) {
+    return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary;
+}
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_feature_flags.h b/wifi/1.6/default/wifi_feature_flags.h
new file mode 100644
index 0000000..d5844d9
--- /dev/null
+++ b/wifi/1.6/default/wifi_feature_flags.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_FEATURE_FLAGS_H_
+#define WIFI_FEATURE_FLAGS_H_
+
+#include <android/hardware/wifi/1.2/IWifiChip.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+namespace chip_mode_ids {
+// These mode ID's should be unique (even across combo versions). Refer to
+// handleChipConfiguration() for it's usage.
+constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
+// Mode ID's for V1
+constexpr V1_0::ChipModeId kV1Sta = 0;
+constexpr V1_0::ChipModeId kV1Ap = 1;
+// Mode ID for V3
+constexpr V1_0::ChipModeId kV3 = 3;
+}  // namespace chip_mode_ids
+
+class WifiFeatureFlags {
+  public:
+    WifiFeatureFlags();
+    virtual ~WifiFeatureFlags() = default;
+
+    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes(bool is_primary);
+
+  private:
+    std::vector<V1_0::IWifiChip::ChipMode> getChipModesForPrimary();
+};
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.6/default/wifi_iface_util.cpp b/wifi/1.6/default/wifi_iface_util.cpp
new file mode 100644
index 0000000..d55e4f8
--- /dev/null
+++ b/wifi/1.6/default/wifi_iface_util.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <net/if.h>
+#include <cstddef>
+#include <iostream>
+#include <limits>
+#include <random>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+namespace {
+// Constants to set the local bit & clear the multicast bit.
+constexpr uint8_t kMacAddressMulticastMask = 0x01;
+constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+WifiIfaceUtil::WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                             const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : iface_tool_(iface_tool),
+      legacy_hal_(legacy_hal),
+      random_mac_address_(nullptr),
+      event_handlers_map_() {}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(const std::string& iface_name) {
+    return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
+                                  const std::array<uint8_t, 6>& mac) {
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+            legacy_hal_.lock()->getSupportedFeatureSet(iface_name);
+
+    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+        !iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
+        LOG(ERROR) << "SetUpState(false) failed.";
+        return false;
+    }
+#endif
+    bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac);
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+        !iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+        LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready.";
+        // Wait for driver ready and try to set iface UP again
+        if (legacy_hal_.lock()->waitForDriverReady() != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "SetUpState(true) wait for driver ready failed.";
+            return false;
+        }
+        if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+            LOG(ERROR) << "SetUpState(true) failed after retry.";
+            return false;
+        }
+    }
+#endif
+    IfaceEventHandlers event_handlers = {};
+    const auto it = event_handlers_map_.find(iface_name);
+    if (it != event_handlers_map_.end()) {
+        event_handlers = it->second;
+    }
+    if (event_handlers.on_state_toggle_off_on != nullptr) {
+        event_handlers.on_state_toggle_off_on(iface_name);
+    }
+    if (!success) {
+        LOG(ERROR) << "SetMacAddress failed on " << iface_name;
+    } else {
+        LOG(DEBUG) << "SetMacAddress succeeded on " << iface_name;
+    }
+    return success;
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
+    if (random_mac_address_) {
+        return *random_mac_address_.get();
+    }
+    random_mac_address_ = std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
+    return *random_mac_address_.get();
+}
+
+void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
+                                               IfaceEventHandlers handlers) {
+    event_handlers_map_[iface_name] = handlers;
+}
+
+void WifiIfaceUtil::unregisterIfaceEventHandlers(const std::string& iface_name) {
+    event_handlers_map_.erase(iface_name);
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
+    std::array<uint8_t, 6> address = {};
+    std::random_device rd;
+    std::default_random_engine engine(rd());
+    std::uniform_int_distribution<uint8_t> dist(std::numeric_limits<uint8_t>::min(),
+                                                std::numeric_limits<uint8_t>::max());
+    for (size_t i = 0; i < address.size(); i++) {
+        address[i] = dist(engine);
+    }
+    // Set the local bit and clear the multicast bit.
+    address[0] |= kMacAddressLocallyAssignedMask;
+    address[0] &= ~kMacAddressMulticastMask;
+    return address;
+}
+
+bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) {
+    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) {
+        LOG(ERROR) << "SetUpState to " << request_up << " failed";
+        return false;
+    }
+    return true;
+}
+
+unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) {
+    return if_nametoindex(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::createBridge(const std::string& br_name) {
+    if (!iface_tool_.lock()->createBridge(br_name)) {
+        return false;
+    }
+
+    if (!iface_tool_.lock()->SetUpState(br_name.c_str(), true)) {
+        LOG(ERROR) << "bridge SetUpState(true) failed.";
+    }
+    return true;
+}
+
+bool WifiIfaceUtil::deleteBridge(const std::string& br_name) {
+    if (!iface_tool_.lock()->SetUpState(br_name.c_str(), false)) {
+        LOG(INFO) << "SetUpState(false) failed for bridge=" << br_name.c_str();
+    }
+
+    return iface_tool_.lock()->deleteBridge(br_name);
+}
+
+bool WifiIfaceUtil::addIfaceToBridge(const std::string& br_name, const std::string& if_name) {
+    return iface_tool_.lock()->addIfaceToBridge(br_name, if_name);
+}
+
+bool WifiIfaceUtil::removeIfaceFromBridge(const std::string& br_name, const std::string& if_name) {
+    return iface_tool_.lock()->removeIfaceFromBridge(br_name, if_name);
+}
+
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_iface_util.h b/wifi/1.6/default/wifi_iface_util.h
new file mode 100644
index 0000000..c5db5de
--- /dev/null
+++ b/wifi/1.6/default/wifi_iface_util.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_IFACE_UTIL_H_
+#define WIFI_IFACE_UTIL_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+// Iface event handlers.
+struct IfaceEventHandlers {
+    // Callback to be invoked when the iface is set down & up for MAC address
+    // change.
+    std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
+};
+
+/**
+ * Util class for common iface operations.
+ */
+class WifiIfaceUtil {
+  public:
+    WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    virtual ~WifiIfaceUtil() = default;
+
+    virtual std::array<uint8_t, 6> getFactoryMacAddress(const std::string& iface_name);
+    virtual bool setMacAddress(const std::string& iface_name, const std::array<uint8_t, 6>& mac);
+    // Get or create a random MAC address. The MAC address returned from
+    // this method will remain the same throughout the lifetime of the HAL
+    // daemon. (So, changes on every reboot)
+    virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
+
+    // Register for any iface event callbacks for the provided interface.
+    virtual void registerIfaceEventHandlers(const std::string& iface_name,
+                                            IfaceEventHandlers handlers);
+    virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
+    virtual bool setUpState(const std::string& iface_name, bool request_up);
+    virtual unsigned ifNameToIndex(const std::string& iface_name);
+
+    virtual bool createBridge(const std::string& br_name);
+
+    virtual bool deleteBridge(const std::string& br_name);
+
+    virtual bool addIfaceToBridge(const std::string& br_name, const std::string& if_name);
+
+    virtual bool removeIfaceFromBridge(const std::string& br_name, const std::string& if_name);
+    // Get a random MAC address.
+    virtual std::array<uint8_t, 6> createRandomMacAddress();
+
+  private:
+    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
+    std::map<std::string, IfaceEventHandlers> event_handlers_map_;
+};
+
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal.cpp b/wifi/1.6/default/wifi_legacy_hal.cpp
new file mode 100644
index 0000000..64dde95
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1582 @@
+/*
+ * Copyright (C) 2016 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 <array>
+#include <chrono>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+#include <net/if.h>
+
+#include "hidl_sync_util.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+// Constants ported over from the legacy HAL calling code
+// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
+// away when this shim layer is replaced by the real vendor
+// implementation.
+static constexpr uint32_t kMaxVersionStringLength = 256;
+static constexpr uint32_t kMaxCachedGscanResults = 64;
+static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
+static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
+static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
+static constexpr uint32_t kMaxRingBuffers = 10;
+static constexpr uint32_t kMaxWifiUsableChannels = 256;
+// need a long timeout (1000ms) for chips that unload their driver.
+static constexpr uint32_t kMaxStopCompleteWaitMs = 1000;
+static constexpr char kDriverPropName[] = "wlan.driver.status";
+
+// Helper function to create a non-const char* for legacy Hal API's.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+// Legacy HAL functions accept "C" style function pointers, so use global
+// functions to pass to the legacy HAL function and store the corresponding
+// std::function methods to be invoked.
+//
+// Callback to be invoked once |stop| is complete
+std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
+void onAsyncStopComplete(wifi_handle handle) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_stop_complete_internal_callback) {
+        on_stop_complete_internal_callback(handle);
+        // Invalidate this callback since we don't want this firing again.
+        on_stop_complete_internal_callback = nullptr;
+    }
+}
+
+// Callback to be invoked for driver dump.
+std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
+void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
+    if (on_driver_memory_dump_internal_callback) {
+        on_driver_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for firmware dump.
+std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
+void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
+    if (on_firmware_memory_dump_internal_callback) {
+        on_firmware_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for Gscan events.
+std::function<void(wifi_request_id, wifi_scan_event)> on_gscan_event_internal_callback;
+void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_gscan_event_internal_callback) {
+        on_gscan_event_internal_callback(id, event);
+    }
+}
+
+// Callback to be invoked for Gscan full results.
+std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
+        on_gscan_full_result_internal_callback;
+void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
+                            uint32_t buckets_scanned) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_gscan_full_result_internal_callback) {
+        on_gscan_full_result_internal_callback(id, result, buckets_scanned);
+    }
+}
+
+// Callback to be invoked for link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
+        on_link_layer_stats_result_internal_callback;
+void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat, int num_radios,
+                                wifi_radio_stat* radio_stat) {
+    if (on_link_layer_stats_result_internal_callback) {
+        on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios, radio_stat);
+    }
+}
+
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+        on_rssi_threshold_breached_internal_callback;
+void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid, int8_t rssi) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_rssi_threshold_breached_internal_callback) {
+        on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+    }
+}
+
+// Callback to be invoked for ring buffer data indication.
+std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
+        on_ring_buffer_data_internal_callback;
+void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
+                           wifi_ring_buffer_status* status) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_ring_buffer_data_internal_callback) {
+        on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size, status);
+    }
+}
+
+// Callback to be invoked for error alert indication.
+std::function<void(wifi_request_id, char*, int, int)> on_error_alert_internal_callback;
+void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size, int err_code) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_error_alert_internal_callback) {
+        on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
+    }
+}
+
+// Callback to be invoked for radio mode change indication.
+std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
+        on_radio_mode_change_internal_callback;
+void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs, wifi_mac_info* mac_infos) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_radio_mode_change_internal_callback) {
+        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
+    }
+}
+
+// Callback to be invoked to report subsystem restart
+std::function<void(const char*)> on_subsystem_restart_internal_callback;
+void onAsyncSubsystemRestart(const char* error) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_subsystem_restart_internal_callback) {
+        on_subsystem_restart_internal_callback(error);
+    }
+}
+
+// Callback to be invoked for rtt results results.
+std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result* rtt_results[])>
+        on_rtt_results_internal_callback;
+void onAsyncRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_results[]) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_rtt_results_internal_callback) {
+        on_rtt_results_internal_callback(id, num_results, rtt_results);
+        on_rtt_results_internal_callback = nullptr;
+    }
+}
+
+// Callbacks for the various NAN operations.
+// NOTE: These have very little conversions to perform before invoking the user
+// callbacks.
+// So, handle all of them here directly to avoid adding an unnecessary layer.
+std::function<void(transaction_id, const NanResponseMsg&)> on_nan_notify_response_user_callback;
+void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_notify_response_user_callback && msg) {
+        on_nan_notify_response_user_callback(id, *msg);
+    }
+}
+
+std::function<void(const NanPublishRepliedInd&)> on_nan_event_publish_replied_user_callback;
+void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
+    LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
+}
+
+std::function<void(const NanPublishTerminatedInd&)> on_nan_event_publish_terminated_user_callback;
+void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_publish_terminated_user_callback && event) {
+        on_nan_event_publish_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
+void onAysncNanEventMatch(NanMatchInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_user_callback && event) {
+        on_nan_event_match_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchExpiredInd&)> on_nan_event_match_expired_user_callback;
+void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_expired_user_callback && event) {
+        on_nan_event_match_expired_user_callback(*event);
+    }
+}
+
+std::function<void(const NanSubscribeTerminatedInd&)>
+        on_nan_event_subscribe_terminated_user_callback;
+void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_subscribe_terminated_user_callback && event) {
+        on_nan_event_subscribe_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
+void onAysncNanEventFollowup(NanFollowupInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_followup_user_callback && event) {
+        on_nan_event_followup_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDiscEngEventInd&)> on_nan_event_disc_eng_event_user_callback;
+void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disc_eng_event_user_callback && event) {
+        on_nan_event_disc_eng_event_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
+void onAysncNanEventDisabled(NanDisabledInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disabled_user_callback && event) {
+        on_nan_event_disabled_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
+void onAysncNanEventTca(NanTCAInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_tca_user_callback && event) {
+        on_nan_event_tca_user_callback(*event);
+    }
+}
+
+std::function<void(const NanBeaconSdfPayloadInd&)> on_nan_event_beacon_sdf_payload_user_callback;
+void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_beacon_sdf_payload_user_callback && event) {
+        on_nan_event_beacon_sdf_payload_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathRequestInd&)> on_nan_event_data_path_request_user_callback;
+void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_request_user_callback && event) {
+        on_nan_event_data_path_request_user_callback(*event);
+    }
+}
+std::function<void(const NanDataPathConfirmInd&)> on_nan_event_data_path_confirm_user_callback;
+void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_confirm_user_callback && event) {
+        on_nan_event_data_path_confirm_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathEndInd&)> on_nan_event_data_path_end_user_callback;
+void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_end_user_callback && event) {
+        on_nan_event_data_path_end_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTransmitFollowupInd&)> on_nan_event_transmit_follow_up_user_callback;
+void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_transmit_follow_up_user_callback && event) {
+        on_nan_event_transmit_follow_up_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeRequestInd&)> on_nan_event_range_request_user_callback;
+void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_request_user_callback && event) {
+        on_nan_event_range_request_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeReportInd&)> on_nan_event_range_report_user_callback;
+void onAysncNanEventRangeReport(NanRangeReportInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_report_user_callback && event) {
+        on_nan_event_range_report_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathScheduleUpdateInd&)> on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_schedule_update_user_callback && event) {
+        on_nan_event_schedule_update_user_callback(*event);
+    }
+}
+
+// Callbacks for the various TWT operations.
+std::function<void(const TwtSetupResponse&)> on_twt_event_setup_response_callback;
+void onAsyncTwtEventSetupResponse(TwtSetupResponse* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_setup_response_callback && event) {
+        on_twt_event_setup_response_callback(*event);
+    }
+}
+
+std::function<void(const TwtTeardownCompletion&)> on_twt_event_teardown_completion_callback;
+void onAsyncTwtEventTeardownCompletion(TwtTeardownCompletion* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_teardown_completion_callback && event) {
+        on_twt_event_teardown_completion_callback(*event);
+    }
+}
+
+std::function<void(const TwtInfoFrameReceived&)> on_twt_event_info_frame_received_callback;
+void onAsyncTwtEventInfoFrameReceived(TwtInfoFrameReceived* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_info_frame_received_callback && event) {
+        on_twt_event_info_frame_received_callback(*event);
+    }
+}
+
+std::function<void(const TwtDeviceNotify&)> on_twt_event_device_notify_callback;
+void onAsyncTwtEventDeviceNotify(TwtDeviceNotify* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_device_notify_callback && event) {
+        on_twt_event_device_notify_callback(*event);
+    }
+}
+
+// End of the free-standing "C" style callbacks.
+
+WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                             const wifi_hal_fn& fn, bool is_primary)
+    : global_func_table_(fn),
+      global_handle_(nullptr),
+      awaiting_event_loop_termination_(false),
+      is_started_(false),
+      iface_tool_(iface_tool),
+      is_primary_(is_primary) {}
+
+wifi_error WifiLegacyHal::initialize() {
+    LOG(DEBUG) << "Initialize legacy HAL";
+    // this now does nothing, since HAL function table is provided
+    // to the constructor
+    return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::start() {
+    // Ensure that we're starting in a good state.
+    CHECK(global_func_table_.wifi_initialize && !global_handle_ && iface_name_to_handle_.empty() &&
+          !awaiting_event_loop_termination_);
+    if (is_started_) {
+        LOG(DEBUG) << "Legacy HAL already started";
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Waiting for the driver ready";
+    wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
+    if (status == WIFI_ERROR_TIMED_OUT || status == WIFI_ERROR_UNKNOWN) {
+        LOG(ERROR) << "Failed or timed out awaiting driver ready";
+        return status;
+    }
+
+    if (is_primary_) {
+        property_set(kDriverPropName, "ok");
+
+        if (!iface_tool_.lock()->SetWifiUpState(true)) {
+            LOG(ERROR) << "Failed to set WiFi interface up";
+            return WIFI_ERROR_UNKNOWN;
+        }
+    }
+
+    LOG(DEBUG) << "Starting legacy HAL";
+    status = global_func_table_.wifi_initialize(&global_handle_);
+    if (status != WIFI_SUCCESS || !global_handle_) {
+        LOG(ERROR) << "Failed to retrieve global handle";
+        return status;
+    }
+    std::thread(&WifiLegacyHal::runEventLoop, this).detach();
+    status = retrieveIfaceHandles();
+    if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
+        LOG(ERROR) << "Failed to retrieve wlan interface handle";
+        return status;
+    }
+    LOG(DEBUG) << "Legacy HAL start complete";
+    is_started_ = true;
+    return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::stop(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+        const std::function<void()>& on_stop_complete_user_callback) {
+    if (!is_started_) {
+        LOG(DEBUG) << "Legacy HAL already stopped";
+        on_stop_complete_user_callback();
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Stopping legacy HAL";
+    on_stop_complete_internal_callback = [on_stop_complete_user_callback,
+                                          this](wifi_handle handle) {
+        CHECK_EQ(global_handle_, handle) << "Handle mismatch";
+        LOG(INFO) << "Legacy HAL stop complete callback received";
+        // Invalidate all the internal pointers now that the HAL is
+        // stopped.
+        invalidate();
+        if (is_primary_) iface_tool_.lock()->SetWifiUpState(false);
+        on_stop_complete_user_callback();
+        is_started_ = false;
+    };
+    awaiting_event_loop_termination_ = true;
+    global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
+    const auto status =
+            stop_wait_cv_.wait_for(*lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
+                                   [this] { return !awaiting_event_loop_termination_; });
+    if (!status) {
+        LOG(ERROR) << "Legacy HAL stop failed or timed out";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    LOG(DEBUG) << "Legacy HAL stop complete";
+    return WIFI_SUCCESS;
+}
+
+bool WifiLegacyHal::isStarted() {
+    return is_started_;
+}
+
+wifi_error WifiLegacyHal::waitForDriverReady() {
+    return global_func_table_.wifi_wait_for_driver_ready();
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_driver_version(getIfaceHandle(iface_name),
+                                                                   buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
+        const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_firmware_version(getIfaceHandle(iface_name),
+                                                                     buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::requestDriverMemoryDump(
+        const std::string& iface_name) {
+    std::vector<uint8_t> driver_dump;
+    on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer, int buffer_size) {
+        driver_dump.insert(driver_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+                           reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+    };
+    wifi_error status = global_func_table_.wifi_get_driver_memory_dump(getIfaceHandle(iface_name),
+                                                                       {onSyncDriverMemoryDump});
+    on_driver_memory_dump_internal_callback = nullptr;
+    return {status, std::move(driver_dump)};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::requestFirmwareMemoryDump(
+        const std::string& iface_name) {
+    std::vector<uint8_t> firmware_dump;
+    on_firmware_memory_dump_internal_callback = [&firmware_dump](char* buffer, int buffer_size) {
+        firmware_dump.insert(firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+                             reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+    };
+    wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
+            getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
+    on_firmware_memory_dump_internal_callback = nullptr;
+    return {status, std::move(firmware_dump)};
+}
+
+std::pair<wifi_error, uint64_t> WifiLegacyHal::getSupportedFeatureSet(
+        const std::string& iface_name) {
+    feature_set set = 0, chip_set = 0;
+    wifi_error status = WIFI_SUCCESS;
+
+    static_assert(sizeof(set) == sizeof(uint64_t),
+                  "Some feature_flags can not be represented in output");
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    global_func_table_.wifi_get_chip_feature_set(
+            global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_supported_feature_set(iface_handle, &set);
+    }
+    return {status, static_cast<uint64_t>(set | chip_set)};
+}
+
+std::pair<wifi_error, PacketFilterCapabilities> WifiLegacyHal::getPacketFilterCapabilities(
+        const std::string& iface_name) {
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+            getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
+                                          const std::vector<uint8_t>& program) {
+    return global_func_table_.wifi_set_packet_filter(getIfaceHandle(iface_name), program.data(),
+                                                     program.size());
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::readApfPacketFilterData(
+        const std::string& iface_name) {
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+            getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    if (status != WIFI_SUCCESS) {
+        return {status, {}};
+    }
+
+    // Size the buffer to read the entire program & work memory.
+    std::vector<uint8_t> buffer(caps.max_len);
+
+    status = global_func_table_.wifi_read_packet_filter(
+            getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(), buffer.size());
+    return {status, move(buffer)};
+}
+
+std::pair<wifi_error, wifi_gscan_capabilities> WifiLegacyHal::getGscanCapabilities(
+        const std::string& iface_name) {
+    wifi_gscan_capabilities caps;
+    wifi_error status =
+            global_func_table_.wifi_get_gscan_capabilities(getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::startGscan(
+        const std::string& iface_name, wifi_request_id id, const wifi_scan_cmd_params& params,
+        const std::function<void(wifi_request_id)>& on_failure_user_callback,
+        const on_gscan_results_callback& on_results_user_callback,
+        const on_gscan_full_result_callback& on_full_result_user_callback) {
+    // If there is already an ongoing background scan, reject new scan requests.
+    if (on_gscan_event_internal_callback || on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    // This callback will be used to either trigger |on_results_user_callback|
+    // or |on_failure_user_callback|.
+    on_gscan_event_internal_callback = [iface_name, on_failure_user_callback,
+                                        on_results_user_callback,
+                                        this](wifi_request_id id, wifi_scan_event event) {
+        switch (event) {
+            case WIFI_SCAN_RESULTS_AVAILABLE:
+            case WIFI_SCAN_THRESHOLD_NUM_SCANS:
+            case WIFI_SCAN_THRESHOLD_PERCENT: {
+                wifi_error status;
+                std::vector<wifi_cached_scan_results> cached_scan_results;
+                std::tie(status, cached_scan_results) = getGscanCachedResults(iface_name);
+                if (status == WIFI_SUCCESS) {
+                    on_results_user_callback(id, cached_scan_results);
+                    return;
+                }
+                FALLTHROUGH_INTENDED;
+            }
+            // Fall through if failed. Failure to retrieve cached scan
+            // results should trigger a background scan failure.
+            case WIFI_SCAN_FAILED:
+                on_failure_user_callback(id);
+                on_gscan_event_internal_callback = nullptr;
+                on_gscan_full_result_internal_callback = nullptr;
+                return;
+        }
+        LOG(FATAL) << "Unexpected gscan event received: " << event;
+    };
+
+    on_gscan_full_result_internal_callback = [on_full_result_user_callback](
+                                                     wifi_request_id id, wifi_scan_result* result,
+                                                     uint32_t buckets_scanned) {
+        if (result) {
+            on_full_result_user_callback(id, result, buckets_scanned);
+        }
+    };
+
+    wifi_scan_result_handler handler = {onAsyncGscanFullResult, onAsyncGscanEvent};
+    wifi_error status =
+            global_func_table_.wifi_start_gscan(id, getIfaceHandle(iface_name), params, handler);
+    if (status != WIFI_SUCCESS) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name, wifi_request_id id) {
+    // If there is no an ongoing background scan, reject stop requests.
+    // TODO(b/32337212): This needs to be handled by the HIDL object because we
+    // need to return the NOT_STARTED error code.
+    if (!on_gscan_event_internal_callback && !on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status = global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing background scan. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, std::vector<uint32_t>> WifiLegacyHal::getValidFrequenciesForBand(
+        const std::string& iface_name, wifi_band band) {
+    static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
+                  "Wifi Channel cannot be represented in output");
+    std::vector<uint32_t> freqs;
+    freqs.resize(kMaxGscanFrequenciesForBand);
+    int32_t num_freqs = 0;
+    wifi_error status = global_func_table_.wifi_get_valid_channels(
+            getIfaceHandle(iface_name), band, freqs.size(),
+            reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
+    CHECK(num_freqs >= 0 && static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
+    freqs.resize(num_freqs);
+    return {status, std::move(freqs)};
+}
+
+wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name, bool dfs_on) {
+    return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name), dfs_on ? 0 : 1);
+}
+
+wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name, bool debug) {
+    wifi_link_layer_params params;
+    params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
+    params.aggressive_statistics_gathering = debug;
+    return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name), params);
+}
+
+wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
+    // TODO: Do we care about these responses?
+    uint32_t clear_mask_rsp;
+    uint8_t stop_rsp;
+    return global_func_table_.wifi_clear_link_stats(getIfaceHandle(iface_name), 0xFFFFFFFF,
+                                                    &clear_mask_rsp, 1, &stop_rsp);
+}
+
+std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
+        const std::string& iface_name) {
+    LinkLayerStats link_stats{};
+    LinkLayerStats* link_stats_ptr = &link_stats;
+
+    on_link_layer_stats_result_internal_callback = [&link_stats_ptr](
+                                                           wifi_request_id /* id */,
+                                                           wifi_iface_stat* iface_stats_ptr,
+                                                           int num_radios,
+                                                           wifi_radio_stat* radio_stats_ptr) {
+        wifi_radio_stat* l_radio_stats_ptr;
+        wifi_peer_info* l_peer_info_stats_ptr;
+
+        if (iface_stats_ptr != nullptr) {
+            link_stats_ptr->iface = *iface_stats_ptr;
+            l_peer_info_stats_ptr = iface_stats_ptr->peer_info;
+            for (uint32_t i = 0; i < iface_stats_ptr->num_peers; i++) {
+                WifiPeerInfo peer;
+                peer.peer_info = *l_peer_info_stats_ptr;
+                if (l_peer_info_stats_ptr->num_rate > 0) {
+                    /* Copy the rate stats */
+                    peer.rate_stats.assign(
+                            l_peer_info_stats_ptr->rate_stats,
+                            l_peer_info_stats_ptr->rate_stats + l_peer_info_stats_ptr->num_rate);
+                }
+                peer.peer_info.num_rate = 0;
+                link_stats_ptr->peers.push_back(peer);
+                l_peer_info_stats_ptr =
+                        (wifi_peer_info*)((u8*)l_peer_info_stats_ptr + sizeof(wifi_peer_info) +
+                                          (sizeof(wifi_rate_stat) *
+                                           l_peer_info_stats_ptr->num_rate));
+            }
+            link_stats_ptr->iface.num_peers = 0;
+        } else {
+            LOG(ERROR) << "Invalid iface stats in link layer stats";
+        }
+        if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+            LOG(ERROR) << "Invalid radio stats in link layer stats";
+            return;
+        }
+        l_radio_stats_ptr = radio_stats_ptr;
+        for (int i = 0; i < num_radios; i++) {
+            LinkLayerRadioStats radio;
+
+            radio.stats = *l_radio_stats_ptr;
+            // Copy over the tx level array to the separate vector.
+            if (l_radio_stats_ptr->num_tx_levels > 0 &&
+                l_radio_stats_ptr->tx_time_per_levels != nullptr) {
+                radio.tx_time_per_levels.assign(
+                        l_radio_stats_ptr->tx_time_per_levels,
+                        l_radio_stats_ptr->tx_time_per_levels + l_radio_stats_ptr->num_tx_levels);
+            }
+            radio.stats.num_tx_levels = 0;
+            radio.stats.tx_time_per_levels = nullptr;
+            /* Copy over the channel stat to separate vector */
+            if (l_radio_stats_ptr->num_channels > 0) {
+                /* Copy the channel stats */
+                radio.channel_stats.assign(
+                        l_radio_stats_ptr->channels,
+                        l_radio_stats_ptr->channels + l_radio_stats_ptr->num_channels);
+            }
+            link_stats_ptr->radios.push_back(radio);
+            l_radio_stats_ptr =
+                    (wifi_radio_stat*)((u8*)l_radio_stats_ptr + sizeof(wifi_radio_stat) +
+                                       (sizeof(wifi_channel_stat) *
+                                        l_radio_stats_ptr->num_channels));
+        }
+    };
+
+    wifi_error status = global_func_table_.wifi_get_link_stats(0, getIfaceHandle(iface_name),
+                                                               {onSyncLinkLayerStatsResult});
+    on_link_layer_stats_result_internal_callback = nullptr;
+    return {status, link_stats};
+}
+
+wifi_error WifiLegacyHal::startRssiMonitoring(
+        const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
+        const on_rssi_threshold_breached_callback& on_threshold_breached_user_callback) {
+    if (on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_rssi_threshold_breached_internal_callback = [on_threshold_breached_user_callback](
+                                                           wifi_request_id id, uint8_t* bssid_ptr,
+                                                           int8_t rssi) {
+        if (!bssid_ptr) {
+            return;
+        }
+        std::array<uint8_t, 6> bssid_arr;
+        // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
+        // address.
+        std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+        on_threshold_breached_user_callback(id, bssid_arr, rssi);
+    };
+    wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
+            id, getIfaceHandle(iface_name), max_rssi, min_rssi, {onAsyncRssiThresholdBreached});
+    if (status != WIFI_SUCCESS) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name, wifi_request_id id) {
+    if (!on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status =
+            global_func_table_.wifi_stop_rssi_monitoring(id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_roaming_capabilities> WifiLegacyHal::getRoamingCapabilities(
+        const std::string& iface_name) {
+    wifi_roaming_capabilities caps;
+    wifi_error status =
+            global_func_table_.wifi_get_roaming_capabilities(getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
+                                           const wifi_roaming_config& config) {
+    wifi_roaming_config config_internal = config;
+    return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name), &config_internal);
+}
+
+wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
+                                                fw_roaming_state_t state) {
+    return global_func_table_.wifi_enable_firmware_roaming(getIfaceHandle(iface_name), state);
+}
+
+wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name, bool enable) {
+    return global_func_table_.wifi_configure_nd_offload(getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::startSendingOffloadedPacket(const std::string& iface_name,
+                                                      uint32_t cmd_id, uint16_t ether_type,
+                                                      const std::vector<uint8_t>& ip_packet_data,
+                                                      const std::array<uint8_t, 6>& src_address,
+                                                      const std::array<uint8_t, 6>& dst_address,
+                                                      uint32_t period_in_ms) {
+    std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
+    std::vector<uint8_t> src_address_internal(src_address.data(),
+                                              src_address.data() + src_address.size());
+    std::vector<uint8_t> dst_address_internal(dst_address.data(),
+                                              dst_address.data() + dst_address.size());
+    return global_func_table_.wifi_start_sending_offloaded_packet(
+            cmd_id, getIfaceHandle(iface_name), ether_type, ip_packet_data_internal.data(),
+            ip_packet_data_internal.size(), src_address_internal.data(),
+            dst_address_internal.data(), period_in_ms);
+}
+
+wifi_error WifiLegacyHal::stopSendingOffloadedPacket(const std::string& iface_name,
+                                                     uint32_t cmd_id) {
+    return global_func_table_.wifi_stop_sending_offloaded_packet(cmd_id,
+                                                                 getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
+                                                wifi_power_scenario scenario) {
+    return global_func_table_.wifi_select_tx_power_scenario(getIfaceHandle(iface_name), scenario);
+}
+
+wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
+    return global_func_table_.wifi_reset_tx_power_scenario(getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name, wifi_latency_mode mode) {
+    return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name), mode);
+}
+
+wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode,
+                                                   uint32_t completion_window) {
+    return global_func_table_.wifi_set_thermal_mitigation_mode(global_handle_, mode,
+                                                               completion_window);
+}
+
+wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+                                                         uint32_t access_category) {
+    return global_func_table_.wifi_map_dscp_access_category(global_handle_, start, end,
+                                                            access_category);
+}
+
+wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() {
+    return global_func_table_.wifi_reset_dscp_mapping(global_handle_);
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
+        const std::string& iface_name) {
+    uint32_t supported_feature_flags = 0;
+    wifi_error status = WIFI_SUCCESS;
+
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_logger_supported_feature_set(iface_handle,
+                                                                          &supported_feature_flags);
+    }
+    return {status, supported_feature_flags};
+}
+
+wifi_error WifiLegacyHal::startPktFateMonitoring(const std::string& iface_name) {
+    return global_func_table_.wifi_start_pkt_fate_monitoring(getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
+        const std::string& iface_name) {
+    std::vector<wifi_tx_report> tx_pkt_fates;
+    tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
+            getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(), &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    tx_pkt_fates.resize(num_fates);
+    return {status, std::move(tx_pkt_fates)};
+}
+
+std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
+        const std::string& iface_name) {
+    std::vector<wifi_rx_report> rx_pkt_fates;
+    rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
+            getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(), &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    rx_pkt_fates.resize(num_fates);
+    return {status, std::move(rx_pkt_fates)};
+}
+
+std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
+        const std::string& iface_name) {
+    WakeReasonStats stats;
+    stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+
+    // This legacy struct needs separate memory to store the variable sized wake
+    // reason types.
+    stats.wake_reason_cnt.cmd_event_wake_cnt =
+            reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
+    stats.wake_reason_cnt.cmd_event_wake_cnt_sz = stats.cmd_event_wake_cnt.size();
+    stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt =
+            reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz = stats.driver_fw_local_wake_cnt.size();
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
+
+    wifi_error status = global_func_table_.wifi_get_wake_reason_stats(getIfaceHandle(iface_name),
+                                                                      &stats.wake_reason_cnt);
+
+    CHECK(stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
+          static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
+                  kMaxWakeReasonStatsArraySize);
+    stats.cmd_event_wake_cnt.resize(stats.wake_reason_cnt.cmd_event_wake_cnt_used);
+    stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
+
+    CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
+          static_cast<uint32_t>(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
+                  kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
+
+    return {status, stats};
+}
+
+wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
+        const std::string& iface_name, const on_ring_buffer_data_callback& on_user_data_callback) {
+    if (on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback = [on_user_data_callback](
+                                                    char* ring_name, char* buffer, int buffer_size,
+                                                    wifi_ring_buffer_status* status) {
+        if (status && buffer) {
+            std::vector<uint8_t> buffer_vector(reinterpret_cast<uint8_t*>(buffer),
+                                               reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+            on_user_data_callback(ring_name, buffer_vector, *status);
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_log_handler(0, getIfaceHandle(iface_name),
+                                                                {onAsyncRingBufferData});
+    if (status != WIFI_SUCCESS) {
+        on_ring_buffer_data_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(const std::string& iface_name) {
+    if (!on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_log_handler(0, getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> WifiLegacyHal::getRingBuffersStatus(
+        const std::string& iface_name) {
+    std::vector<wifi_ring_buffer_status> ring_buffers_status;
+    ring_buffers_status.resize(kMaxRingBuffers);
+    uint32_t num_rings = kMaxRingBuffers;
+    wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
+            getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
+    CHECK(num_rings <= kMaxRingBuffers);
+    ring_buffers_status.resize(num_rings);
+    return {status, std::move(ring_buffers_status)};
+}
+
+wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
+                                                 const std::string& ring_name,
+                                                 uint32_t verbose_level, uint32_t max_interval_sec,
+                                                 uint32_t min_data_size) {
+    return global_func_table_.wifi_start_logging(getIfaceHandle(iface_name), verbose_level, 0,
+                                                 max_interval_sec, min_data_size,
+                                                 makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
+                                            const std::string& ring_name) {
+    return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
+                                                 makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
+        const std::string& iface_name, const on_error_alert_callback& on_user_alert_callback) {
+    if (on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = [on_user_alert_callback](wifi_request_id id, char* buffer,
+                                                                int buffer_size, int err_code) {
+        if (buffer) {
+            CHECK(id == 0);
+            on_user_alert_callback(
+                    err_code,
+                    std::vector<uint8_t>(reinterpret_cast<uint8_t*>(buffer),
+                                         reinterpret_cast<uint8_t*>(buffer) + buffer_size));
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_alert_handler(0, getIfaceHandle(iface_name),
+                                                                  {onAsyncErrorAlert});
+    if (status != WIFI_SUCCESS) {
+        on_error_alert_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(const std::string& iface_name) {
+    if (!on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_alert_handler(0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
+        const std::string& iface_name,
+        const on_radio_mode_change_callback& on_user_change_callback) {
+    if (on_radio_mode_change_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_radio_mode_change_internal_callback = [on_user_change_callback](
+                                                     wifi_request_id /* id */, uint32_t num_macs,
+                                                     wifi_mac_info* mac_infos_arr) {
+        if (num_macs > 0 && mac_infos_arr) {
+            std::vector<WifiMacInfo> mac_infos_vec;
+            for (uint32_t i = 0; i < num_macs; i++) {
+                WifiMacInfo mac_info;
+                mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
+                mac_info.mac_band = mac_infos_arr[i].mac_band;
+                for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
+                    WifiIfaceInfo iface_info;
+                    iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
+                    iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
+                    mac_info.iface_infos.push_back(iface_info);
+                }
+                mac_infos_vec.push_back(mac_info);
+            }
+            on_user_change_callback(mac_infos_vec);
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
+            0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
+    if (status != WIFI_SUCCESS) {
+        on_radio_mode_change_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::registerSubsystemRestartCallbackHandler(
+        const on_subsystem_restart_callback& on_restart_callback) {
+    if (on_subsystem_restart_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_subsystem_restart_internal_callback = [on_restart_callback](const char* error) {
+        on_restart_callback(error);
+    };
+    wifi_error status = global_func_table_.wifi_set_subsystem_restart_handler(
+            global_handle_, {onAsyncSubsystemRestart});
+    if (status != WIFI_SUCCESS) {
+        on_subsystem_restart_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::startRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<wifi_rtt_config>& rtt_configs,
+        const on_rtt_results_callback& on_results_user_callback) {
+    if (on_rtt_results_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_rtt_results_internal_callback = [on_results_user_callback](wifi_request_id id,
+                                                                  unsigned num_results,
+                                                                  wifi_rtt_result* rtt_results[]) {
+        if (num_results > 0 && !rtt_results) {
+            LOG(ERROR) << "Unexpected nullptr in RTT results";
+            return;
+        }
+        std::vector<const wifi_rtt_result*> rtt_results_vec;
+        std::copy_if(rtt_results, rtt_results + num_results, back_inserter(rtt_results_vec),
+                     [](wifi_rtt_result* rtt_result) { return rtt_result != nullptr; });
+        on_results_user_callback(id, rtt_results_vec);
+    };
+
+    std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
+    wifi_error status = global_func_table_.wifi_rtt_range_request(
+            id, getIfaceHandle(iface_name), rtt_configs.size(), rtt_configs_internal.data(),
+            {onAsyncRttResults});
+    if (status != WIFI_SUCCESS) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::cancelRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
+    if (!on_rtt_results_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>), "MAC address size mismatch");
+    // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
+    // addressed are cancelled).
+    std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
+    wifi_error status = global_func_table_.wifi_rtt_range_cancel(
+            id, getIfaceHandle(iface_name), mac_addrs.size(),
+            reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
+    // If the request Id is wrong, don't stop the ongoing range request. Any
+    // other error should be treated as the end of rtt ranging.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
+        const std::string& iface_name) {
+    wifi_rtt_capabilities rtt_caps;
+    wifi_error status =
+            global_func_table_.wifi_get_rtt_capabilities(getIfaceHandle(iface_name), &rtt_caps);
+    return {status, rtt_caps};
+}
+
+std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
+        const std::string& iface_name) {
+    wifi_rtt_responder rtt_responder;
+    wifi_error status = global_func_table_.wifi_rtt_get_responder_info(getIfaceHandle(iface_name),
+                                                                       &rtt_responder);
+    return {status, rtt_responder};
+}
+
+wifi_error WifiLegacyHal::enableRttResponder(const std::string& iface_name, wifi_request_id id,
+                                             const wifi_channel_info& channel_hint,
+                                             uint32_t max_duration_secs,
+                                             const wifi_rtt_responder& info) {
+    wifi_rtt_responder info_internal(info);
+    return global_func_table_.wifi_enable_responder(id, getIfaceHandle(iface_name), channel_hint,
+                                                    max_duration_secs, &info_internal);
+}
+
+wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name, wifi_request_id id) {
+    return global_func_table_.wifi_disable_responder(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name, wifi_request_id id,
+                                    const wifi_lci_information& info) {
+    wifi_lci_information info_internal(info);
+    return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name), &info_internal);
+}
+
+wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name, wifi_request_id id,
+                                    const wifi_lcr_information& info) {
+    wifi_lcr_information info_internal(info);
+    return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name), &info_internal);
+}
+
+wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(const std::string& iface_name,
+                                                      const NanCallbackHandlers& user_callbacks) {
+    on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
+    on_nan_event_publish_terminated_user_callback = user_callbacks.on_event_publish_terminated;
+    on_nan_event_match_user_callback = user_callbacks.on_event_match;
+    on_nan_event_match_expired_user_callback = user_callbacks.on_event_match_expired;
+    on_nan_event_subscribe_terminated_user_callback = user_callbacks.on_event_subscribe_terminated;
+    on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
+    on_nan_event_disc_eng_event_user_callback = user_callbacks.on_event_disc_eng_event;
+    on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
+    on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
+    on_nan_event_beacon_sdf_payload_user_callback = user_callbacks.on_event_beacon_sdf_payload;
+    on_nan_event_data_path_request_user_callback = user_callbacks.on_event_data_path_request;
+    on_nan_event_data_path_confirm_user_callback = user_callbacks.on_event_data_path_confirm;
+    on_nan_event_data_path_end_user_callback = user_callbacks.on_event_data_path_end;
+    on_nan_event_transmit_follow_up_user_callback = user_callbacks.on_event_transmit_follow_up;
+    on_nan_event_range_request_user_callback = user_callbacks.on_event_range_request;
+    on_nan_event_range_report_user_callback = user_callbacks.on_event_range_report;
+    on_nan_event_schedule_update_user_callback = user_callbacks.on_event_schedule_update;
+
+    return global_func_table_.wifi_nan_register_handler(
+            getIfaceHandle(iface_name),
+            {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
+             onAysncNanEventPublishTerminated, onAysncNanEventMatch, onAysncNanEventMatchExpired,
+             onAysncNanEventSubscribeTerminated, onAysncNanEventFollowup,
+             onAysncNanEventDiscEngEvent, onAysncNanEventDisabled, onAysncNanEventTca,
+             onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
+             onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
+             onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
+             onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
+}
+
+wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name, transaction_id id,
+                                           const NanEnableRequest& msg) {
+    NanEnableRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_enable_request(id, getIfaceHandle(iface_name),
+                                                      &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name, transaction_id id) {
+    return global_func_table_.wifi_nan_disable_request(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name, transaction_id id,
+                                            const NanPublishRequest& msg) {
+    NanPublishRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_request(id, getIfaceHandle(iface_name),
+                                                       &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPublishCancelRequest(const std::string& iface_name, transaction_id id,
+                                                  const NanPublishCancelRequest& msg) {
+    NanPublishCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_cancel_request(id, getIfaceHandle(iface_name),
+                                                              &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name, transaction_id id,
+                                              const NanSubscribeRequest& msg) {
+    NanSubscribeRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_request(id, getIfaceHandle(iface_name),
+                                                         &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeCancelRequest(const std::string& iface_name,
+                                                    transaction_id id,
+                                                    const NanSubscribeCancelRequest& msg) {
+    NanSubscribeCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_cancel_request(id, getIfaceHandle(iface_name),
+                                                                &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTransmitFollowupRequest(const std::string& iface_name,
+                                                     transaction_id id,
+                                                     const NanTransmitFollowupRequest& msg) {
+    NanTransmitFollowupRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_transmit_followup_request(id, getIfaceHandle(iface_name),
+                                                                 &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name, transaction_id id,
+                                          const NanStatsRequest& msg) {
+    NanStatsRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_stats_request(id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name, transaction_id id,
+                                           const NanConfigRequest& msg) {
+    NanConfigRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_config_request(id, getIfaceHandle(iface_name),
+                                                      &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name, transaction_id id,
+                                        const NanTCARequest& msg) {
+    NanTCARequest msg_internal(msg);
+    return global_func_table_.wifi_nan_tca_request(id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(const std::string& iface_name,
+                                                     transaction_id id,
+                                                     const NanBeaconSdfPayloadRequest& msg) {
+    NanBeaconSdfPayloadRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_beacon_sdf_payload_request(id, getIfaceHandle(iface_name),
+                                                                  &msg_internal);
+}
+
+std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
+    NanVersion version;
+    wifi_error status = global_func_table_.wifi_nan_get_version(global_handle_, &version);
+    return {status, version};
+}
+
+wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name, transaction_id id) {
+    return global_func_table_.wifi_nan_get_capabilities(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceCreate(const std::string& iface_name, transaction_id id,
+                                                 const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_create(id, getIfaceHandle(iface_name),
+                                                             makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceDelete(const std::string& iface_name, transaction_id id,
+                                                 const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_delete(id, getIfaceHandle(iface_name),
+                                                             makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataRequestInitiator(const std::string& iface_name, transaction_id id,
+                                                  const NanDataPathInitiatorRequest& msg) {
+    NanDataPathInitiatorRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_data_request_initiator(id, getIfaceHandle(iface_name),
+                                                              &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDataIndicationResponse(const std::string& iface_name,
+                                                    transaction_id id,
+                                                    const NanDataPathIndicationResponse& msg) {
+    NanDataPathIndicationResponse msg_internal(msg);
+    return global_func_table_.wifi_nan_data_indication_response(id, getIfaceHandle(iface_name),
+                                                                &msg_internal);
+}
+
+typedef struct {
+    u8 num_ndp_instances;
+    NanDataPathId ndp_instance_id;
+} NanDataPathEndSingleNdpIdRequest;
+
+wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name, transaction_id id,
+                                     uint32_t ndpInstanceId) {
+    NanDataPathEndSingleNdpIdRequest msg;
+    msg.num_ndp_instances = 1;
+    msg.ndp_instance_id = ndpInstanceId;
+    wifi_error status = global_func_table_.wifi_nan_data_end(id, getIfaceHandle(iface_name),
+                                                             (NanDataPathEndRequest*)&msg);
+    return status;
+}
+
+wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
+                                         std::array<int8_t, 2> code) {
+    std::string code_str(code.data(), code.data() + code.size());
+    return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name), code_str.c_str());
+}
+
+wifi_error WifiLegacyHal::retrieveIfaceHandles() {
+    wifi_interface_handle* iface_handles = nullptr;
+    int num_iface_handles = 0;
+    wifi_error status =
+            global_func_table_.wifi_get_ifaces(global_handle_, &num_iface_handles, &iface_handles);
+    if (status != WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to enumerate interface handles";
+        return status;
+    }
+    iface_name_to_handle_.clear();
+    for (int i = 0; i < num_iface_handles; ++i) {
+        std::array<char, IFNAMSIZ> iface_name_arr = {};
+        status = global_func_table_.wifi_get_iface_name(iface_handles[i], iface_name_arr.data(),
+                                                        iface_name_arr.size());
+        if (status != WIFI_SUCCESS) {
+            LOG(WARNING) << "Failed to get interface handle name";
+            continue;
+        }
+        // Assuming the interface name is null terminated since the legacy HAL
+        // API does not return a size.
+        std::string iface_name(iface_name_arr.data());
+        LOG(INFO) << "Adding interface handle for " << iface_name;
+        iface_name_to_handle_[iface_name] = iface_handles[i];
+    }
+    return WIFI_SUCCESS;
+}
+
+wifi_interface_handle WifiLegacyHal::getIfaceHandle(const std::string& iface_name) {
+    const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
+    if (iface_handle_iter == iface_name_to_handle_.end()) {
+        LOG(ERROR) << "Unknown iface name: " << iface_name;
+        return nullptr;
+    }
+    return iface_handle_iter->second;
+}
+
+void WifiLegacyHal::runEventLoop() {
+    LOG(DEBUG) << "Starting legacy HAL event loop";
+    global_func_table_.wifi_event_loop(global_handle_);
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (!awaiting_event_loop_termination_) {
+        LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping";
+    }
+    LOG(DEBUG) << "Legacy HAL event loop terminated";
+    awaiting_event_loop_termination_ = false;
+    stop_wait_cv_.notify_one();
+}
+
+std::pair<wifi_error, std::vector<wifi_cached_scan_results>> WifiLegacyHal::getGscanCachedResults(
+        const std::string& iface_name) {
+    std::vector<wifi_cached_scan_results> cached_scan_results;
+    cached_scan_results.resize(kMaxCachedGscanResults);
+    int32_t num_results = 0;
+    wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
+            getIfaceHandle(iface_name), true /* always flush */, cached_scan_results.size(),
+            cached_scan_results.data(), &num_results);
+    CHECK(num_results >= 0 && static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
+    cached_scan_results.resize(num_results);
+    // Check for invalid IE lengths in these cached scan results and correct it.
+    for (auto& cached_scan_result : cached_scan_results) {
+        int num_scan_results = cached_scan_result.num_results;
+        for (int i = 0; i < num_scan_results; i++) {
+            auto& scan_result = cached_scan_result.results[i];
+            if (scan_result.ie_length > 0) {
+                LOG(DEBUG) << "Cached scan result has non-zero IE length " << scan_result.ie_length;
+                scan_result.ie_length = 0;
+            }
+        }
+    }
+    return {status, std::move(cached_scan_results)};
+}
+
+wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
+                                                 wifi_interface_type iftype) {
+    // Create the interface if it doesn't exist. If interface already exist,
+    // Vendor Hal should return WIFI_SUCCESS.
+    wifi_error status = global_func_table_.wifi_virtual_interface_create(global_handle_,
+                                                                         ifname.c_str(), iftype);
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
+    // Delete the interface if it was created dynamically.
+    wifi_error status =
+            global_func_table_.wifi_virtual_interface_delete(global_handle_, ifname.c_str());
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
+                                                                     wifi_error status) {
+    if (status == WIFI_SUCCESS) {
+        // refresh list of handlers now.
+        status = retrieveIfaceHandles();
+    } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
+        // Vendor hal does not implement this API. Such vendor implementations
+        // are expected to create / delete interface by other means.
+
+        // check if interface exists.
+        if (if_nametoindex(ifname.c_str())) {
+            status = retrieveIfaceHandles();
+        }
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type, std::string& ifname) {
+    std::array<char, IFNAMSIZ> buffer;
+
+    wifi_error res = global_func_table_.wifi_get_supported_iface_name(
+            global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size());
+    if (res == WIFI_SUCCESS) ifname = buffer.data();
+
+    return res;
+}
+
+wifi_error WifiLegacyHal::multiStaSetPrimaryConnection(const std::string& ifname) {
+    return global_func_table_.wifi_multi_sta_set_primary_connection(global_handle_,
+                                                                    getIfaceHandle(ifname));
+}
+
+wifi_error WifiLegacyHal::multiStaSetUseCase(wifi_multi_sta_use_case use_case) {
+    return global_func_table_.wifi_multi_sta_set_use_case(global_handle_, use_case);
+}
+
+wifi_error WifiLegacyHal::setCoexUnsafeChannels(
+        std::vector<wifi_coex_unsafe_channel> unsafe_channels, uint32_t restrictions) {
+    return global_func_table_.wifi_set_coex_unsafe_channels(global_handle_, unsafe_channels.size(),
+                                                            unsafe_channels.data(), restrictions);
+}
+
+wifi_error WifiLegacyHal::setVoipMode(const std::string& iface_name, wifi_voip_mode mode) {
+    return global_func_table_.wifi_set_voip_mode(getIfaceHandle(iface_name), mode);
+}
+
+wifi_error WifiLegacyHal::twtRegisterHandler(const std::string& iface_name,
+                                             const TwtCallbackHandlers& user_callbacks) {
+    on_twt_event_setup_response_callback = user_callbacks.on_setup_response;
+    on_twt_event_teardown_completion_callback = user_callbacks.on_teardown_completion;
+    on_twt_event_info_frame_received_callback = user_callbacks.on_info_frame_received;
+    on_twt_event_device_notify_callback = user_callbacks.on_device_notify;
+
+    return global_func_table_.wifi_twt_register_handler(
+            getIfaceHandle(iface_name),
+            {onAsyncTwtEventSetupResponse, onAsyncTwtEventTeardownCompletion,
+             onAsyncTwtEventInfoFrameReceived, onAsyncTwtEventDeviceNotify});
+}
+
+std::pair<wifi_error, TwtCapabilitySet> WifiLegacyHal::twtGetCapability(
+        const std::string& iface_name) {
+    TwtCapabilitySet capSet;
+    wifi_error status =
+            global_func_table_.wifi_twt_get_capability(getIfaceHandle(iface_name), &capSet);
+    return {status, capSet};
+}
+
+wifi_error WifiLegacyHal::twtSetupRequest(const std::string& iface_name,
+                                          const TwtSetupRequest& msg) {
+    TwtSetupRequest msgInternal(msg);
+    return global_func_table_.wifi_twt_setup_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+wifi_error WifiLegacyHal::twtTearDownRequest(const std::string& iface_name,
+                                             const TwtTeardownRequest& msg) {
+    TwtTeardownRequest msgInternal(msg);
+    return global_func_table_.wifi_twt_teardown_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+wifi_error WifiLegacyHal::twtInfoFrameRequest(const std::string& iface_name,
+                                              const TwtInfoFrameRequest& msg) {
+    TwtInfoFrameRequest msgInternal(msg);
+    return global_func_table_.wifi_twt_info_frame_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+std::pair<wifi_error, TwtStats> WifiLegacyHal::twtGetStats(const std::string& iface_name,
+                                                           uint8_t configId) {
+    TwtStats stats;
+    wifi_error status =
+            global_func_table_.wifi_twt_get_stats(getIfaceHandle(iface_name), configId, &stats);
+    return {status, stats};
+}
+
+wifi_error WifiLegacyHal::twtClearStats(const std::string& iface_name, uint8_t configId) {
+    return global_func_table_.wifi_twt_clear_stats(getIfaceHandle(iface_name), configId);
+}
+
+wifi_error WifiLegacyHal::setDtimConfig(const std::string& iface_name, uint32_t multiplier) {
+    return global_func_table_.wifi_set_dtim_config(getIfaceHandle(iface_name), multiplier);
+}
+
+std::pair<wifi_error, std::vector<wifi_usable_channel>> WifiLegacyHal::getUsableChannels(
+        uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask) {
+    std::vector<wifi_usable_channel> channels;
+    channels.resize(kMaxWifiUsableChannels);
+    uint32_t size = 0;
+    wifi_error status = global_func_table_.wifi_get_usable_channels(
+            global_handle_, band_mask, iface_mode_mask, filter_mask, channels.size(), &size,
+            reinterpret_cast<wifi_usable_channel*>(channels.data()));
+    CHECK(size >= 0 && size <= kMaxWifiUsableChannels);
+    channels.resize(size);
+    return {status, std::move(channels)};
+}
+
+wifi_error WifiLegacyHal::triggerSubsystemRestart() {
+    return global_func_table_.wifi_trigger_subsystem_restart(global_handle_);
+}
+
+wifi_error WifiLegacyHal::setIndoorState(bool isIndoor) {
+    return global_func_table_.wifi_set_indoor_state(global_handle_, isIndoor);
+}
+
+void WifiLegacyHal::invalidate() {
+    global_handle_ = nullptr;
+    iface_name_to_handle_.clear();
+    on_driver_memory_dump_internal_callback = nullptr;
+    on_firmware_memory_dump_internal_callback = nullptr;
+    on_gscan_event_internal_callback = nullptr;
+    on_gscan_full_result_internal_callback = nullptr;
+    on_link_layer_stats_result_internal_callback = nullptr;
+    on_rssi_threshold_breached_internal_callback = nullptr;
+    on_ring_buffer_data_internal_callback = nullptr;
+    on_error_alert_internal_callback = nullptr;
+    on_radio_mode_change_internal_callback = nullptr;
+    on_subsystem_restart_internal_callback = nullptr;
+    on_rtt_results_internal_callback = nullptr;
+    on_nan_notify_response_user_callback = nullptr;
+    on_nan_event_publish_terminated_user_callback = nullptr;
+    on_nan_event_match_user_callback = nullptr;
+    on_nan_event_match_expired_user_callback = nullptr;
+    on_nan_event_subscribe_terminated_user_callback = nullptr;
+    on_nan_event_followup_user_callback = nullptr;
+    on_nan_event_disc_eng_event_user_callback = nullptr;
+    on_nan_event_disabled_user_callback = nullptr;
+    on_nan_event_tca_user_callback = nullptr;
+    on_nan_event_beacon_sdf_payload_user_callback = nullptr;
+    on_nan_event_data_path_request_user_callback = nullptr;
+    on_nan_event_data_path_confirm_user_callback = nullptr;
+    on_nan_event_data_path_end_user_callback = nullptr;
+    on_nan_event_transmit_follow_up_user_callback = nullptr;
+    on_nan_event_range_request_user_callback = nullptr;
+    on_nan_event_range_report_user_callback = nullptr;
+    on_nan_event_schedule_update_user_callback = nullptr;
+    on_twt_event_setup_response_callback = nullptr;
+    on_twt_event_teardown_completion_callback = nullptr;
+    on_twt_event_info_frame_received_callback = nullptr;
+    on_twt_event_device_notify_callback = nullptr;
+}
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal.h b/wifi/1.6/default/wifi_legacy_hal.h
new file mode 100644
index 0000000..1d85d2e
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal.h
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_H_
+#define WIFI_LEGACY_HAL_H_
+
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <thread>
+#include <vector>
+
+#include <hardware_legacy/wifi_hal.h>
+#include <wifi_system/interface_tool.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+// Import all the types defined inside the legacy HAL header files into this
+// namespace.
+using ::frame_info;
+using ::frame_type;
+using ::FRAME_TYPE_80211_MGMT;
+using ::FRAME_TYPE_ETHERNET_II;
+using ::FRAME_TYPE_UNKNOWN;
+using ::fw_roaming_state_t;
+using ::mac_addr;
+using ::NAN_CHANNEL_24G_BAND;
+using ::NAN_CHANNEL_5G_BAND_HIGH;
+using ::NAN_CHANNEL_5G_BAND_LOW;
+using ::NAN_DISABLE_RANGE_REPORT;
+using ::NAN_DO_NOT_USE_SRF;
+using ::NAN_DP_CHANNEL_NOT_REQUESTED;
+using ::NAN_DP_CONFIG_NO_SECURITY;
+using ::NAN_DP_CONFIG_SECURITY;
+using ::NAN_DP_END;
+using ::NAN_DP_FORCE_CHANNEL_SETUP;
+using ::NAN_DP_INITIATOR_RESPONSE;
+using ::NAN_DP_INTERFACE_CREATE;
+using ::NAN_DP_INTERFACE_DELETE;
+using ::NAN_DP_REQUEST_ACCEPT;
+using ::NAN_DP_REQUEST_CHANNEL_SETUP;
+using ::NAN_DP_REQUEST_REJECT;
+using ::NAN_DP_RESPONDER_RESPONSE;
+using ::NAN_GET_CAPABILITIES;
+using ::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+using ::NAN_MATCH_ALG_MATCH_NEVER;
+using ::NAN_MATCH_ALG_MATCH_ONCE;
+using ::NAN_PUBLISH_TYPE_SOLICITED;
+using ::NAN_PUBLISH_TYPE_UNSOLICITED;
+using ::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+using ::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+using ::NAN_RANGING_AUTO_RESPONSE_ENABLE;
+using ::NAN_RANGING_DISABLE;
+using ::NAN_RANGING_ENABLE;
+using ::NAN_RESPONSE_BEACON_SDF_PAYLOAD;
+using ::NAN_RESPONSE_CONFIG;
+using ::NAN_RESPONSE_DISABLED;
+using ::NAN_RESPONSE_ENABLED;
+using ::NAN_RESPONSE_ERROR;
+using ::NAN_RESPONSE_PUBLISH;
+using ::NAN_RESPONSE_PUBLISH_CANCEL;
+using ::NAN_RESPONSE_STATS;
+using ::NAN_RESPONSE_SUBSCRIBE;
+using ::NAN_RESPONSE_SUBSCRIBE_CANCEL;
+using ::NAN_RESPONSE_TCA;
+using ::NAN_RESPONSE_TRANSMIT_FOLLOWUP;
+using ::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+using ::NAN_SECURITY_KEY_INPUT_PMK;
+using ::NAN_SERVICE_ACCEPT_POLICY_ALL;
+using ::NAN_SERVICE_ACCEPT_POLICY_NONE;
+using ::NAN_SRF_ATTR_BLOOM_FILTER;
+using ::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+using ::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+using ::NAN_SRF_INCLUDE_RESPOND;
+using ::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+using ::NAN_SSI_REQUIRED_IN_MATCH_IND;
+using ::NAN_STATUS_ALREADY_ENABLED;
+using ::NAN_STATUS_FOLLOWUP_QUEUE_FULL;
+using ::NAN_STATUS_INTERNAL_FAILURE;
+using ::NAN_STATUS_INVALID_NDP_ID;
+using ::NAN_STATUS_INVALID_PARAM;
+using ::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
+using ::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID;
+using ::NAN_STATUS_NAN_NOT_ALLOWED;
+using ::NAN_STATUS_NO_OTA_ACK;
+using ::NAN_STATUS_NO_RESOURCE_AVAILABLE;
+using ::NAN_STATUS_PROTOCOL_FAILURE;
+using ::NAN_STATUS_SUCCESS;
+using ::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+using ::NAN_SUBSCRIBE_TYPE_ACTIVE;
+using ::NAN_SUBSCRIBE_TYPE_PASSIVE;
+using ::NAN_TRANSMIT_IN_DW;
+using ::NAN_TRANSMIT_IN_FAW;
+using ::NAN_TX_PRIORITY_HIGH;
+using ::NAN_TX_PRIORITY_NORMAL;
+using ::NAN_TX_TYPE_BROADCAST;
+using ::NAN_TX_TYPE_UNICAST;
+using ::NAN_USE_SRF;
+using ::NanBeaconSdfPayloadInd;
+using ::NanCapabilities;
+using ::NanChannelInfo;
+using ::NanConfigRequest;
+using ::NanDataPathChannelCfg;
+using ::NanDataPathConfirmInd;
+using ::NanDataPathEndInd;
+using ::NanDataPathIndicationResponse;
+using ::NanDataPathInitiatorRequest;
+using ::NanDataPathRequestInd;
+using ::NanDataPathScheduleUpdateInd;
+using ::NanDisabledInd;
+using ::NanDiscEngEventInd;
+using ::NanEnableRequest;
+using ::NanFollowupInd;
+using ::NanMatchAlg;
+using ::NanMatchExpiredInd;
+using ::NanMatchInd;
+using ::NanPublishCancelRequest;
+using ::NanPublishRequest;
+using ::NanPublishTerminatedInd;
+using ::NanPublishType;
+using ::NanRangeReportInd;
+using ::NanRangeRequestInd;
+using ::NanResponseMsg;
+using ::NanSRFType;
+using ::NanStatusType;
+using ::NanSubscribeCancelRequest;
+using ::NanSubscribeRequest;
+using ::NanSubscribeTerminatedInd;
+using ::NanSubscribeType;
+using ::NanTransmitFollowupInd;
+using ::NanTransmitFollowupRequest;
+using ::NanTxType;
+using ::ROAMING_DISABLE;
+using ::ROAMING_ENABLE;
+using ::RTT_PEER_AP;
+using ::RTT_PEER_NAN;
+using ::RTT_PEER_P2P_CLIENT;
+using ::RTT_PEER_P2P_GO;
+using ::RTT_PEER_STA;
+using ::rtt_peer_type;
+using ::RTT_STATUS_ABORTED;
+using ::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL;
+using ::RTT_STATUS_FAIL_BUSY_TRY_LATER;
+using ::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE;
+using ::RTT_STATUS_FAIL_INVALID_TS;
+using ::RTT_STATUS_FAIL_NO_CAPABILITY;
+using ::RTT_STATUS_FAIL_NO_RSP;
+using ::RTT_STATUS_FAIL_NOT_SCHEDULED_YET;
+using ::RTT_STATUS_FAIL_PROTOCOL;
+using ::RTT_STATUS_FAIL_REJECTED;
+using ::RTT_STATUS_FAIL_SCHEDULE;
+using ::RTT_STATUS_FAIL_TM_TIMEOUT;
+using ::RTT_STATUS_FAILURE;
+using ::RTT_STATUS_INVALID_REQ;
+using ::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
+using ::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE;
+using ::RTT_STATUS_NO_WIFI;
+using ::RTT_STATUS_SUCCESS;
+using ::RTT_TYPE_1_SIDED;
+using ::RTT_TYPE_2_SIDED;
+using ::RX_PKT_FATE_DRV_DROP_FILTER;
+using ::RX_PKT_FATE_DRV_DROP_INVALID;
+using ::RX_PKT_FATE_DRV_DROP_NOBUFS;
+using ::RX_PKT_FATE_DRV_DROP_OTHER;
+using ::RX_PKT_FATE_DRV_QUEUED;
+using ::RX_PKT_FATE_FW_DROP_FILTER;
+using ::RX_PKT_FATE_FW_DROP_INVALID;
+using ::RX_PKT_FATE_FW_DROP_NOBUFS;
+using ::RX_PKT_FATE_FW_DROP_OTHER;
+using ::RX_PKT_FATE_FW_QUEUED;
+using ::RX_PKT_FATE_SUCCESS;
+using ::ssid_t;
+using ::transaction_id;
+using ::TX_PKT_FATE_ACKED;
+using ::TX_PKT_FATE_DRV_DROP_INVALID;
+using ::TX_PKT_FATE_DRV_DROP_NOBUFS;
+using ::TX_PKT_FATE_DRV_DROP_OTHER;
+using ::TX_PKT_FATE_DRV_QUEUED;
+using ::TX_PKT_FATE_FW_DROP_INVALID;
+using ::TX_PKT_FATE_FW_DROP_NOBUFS;
+using ::TX_PKT_FATE_FW_DROP_OTHER;
+using ::TX_PKT_FATE_FW_QUEUED;
+using ::TX_PKT_FATE_SENT;
+using ::WIFI_AC_BE;
+using ::WIFI_AC_BK;
+using ::WIFI_AC_VI;
+using ::WIFI_AC_VO;
+using ::wifi_band;
+using ::WIFI_BAND_A;
+using ::WIFI_BAND_A_DFS;
+using ::WIFI_BAND_A_WITH_DFS;
+using ::WIFI_BAND_ABG;
+using ::WIFI_BAND_ABG_WITH_DFS;
+using ::WIFI_BAND_BG;
+using ::WIFI_BAND_UNSPECIFIED;
+using ::wifi_cached_scan_results;
+using ::WIFI_CHAN_WIDTH_10;
+using ::WIFI_CHAN_WIDTH_160;
+using ::WIFI_CHAN_WIDTH_20;
+using ::WIFI_CHAN_WIDTH_320;
+using ::WIFI_CHAN_WIDTH_40;
+using ::WIFI_CHAN_WIDTH_5;
+using ::WIFI_CHAN_WIDTH_80;
+using ::WIFI_CHAN_WIDTH_80P80;
+using ::WIFI_CHAN_WIDTH_INVALID;
+using ::wifi_channel_info;
+using ::wifi_channel_stat;
+using ::wifi_channel_width;
+using ::wifi_coex_restriction;
+using ::wifi_coex_unsafe_channel;
+using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
+using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
+using ::wifi_error;
+using ::WIFI_ERROR_BUSY;
+using ::WIFI_ERROR_INVALID_ARGS;
+using ::WIFI_ERROR_INVALID_REQUEST_ID;
+using ::WIFI_ERROR_NONE;
+using ::WIFI_ERROR_NOT_AVAILABLE;
+using ::WIFI_ERROR_NOT_SUPPORTED;
+using ::WIFI_ERROR_OUT_OF_MEMORY;
+using ::WIFI_ERROR_TIMED_OUT;
+using ::WIFI_ERROR_TOO_MANY_REQUESTS;
+using ::WIFI_ERROR_UNINITIALIZED;
+using ::WIFI_ERROR_UNKNOWN;
+using ::wifi_gscan_capabilities;
+using ::wifi_hal_fn;
+using ::wifi_information_element;
+using ::WIFI_INTERFACE_IBSS;
+using ::WIFI_INTERFACE_MESH;
+using ::wifi_interface_mode;
+using ::WIFI_INTERFACE_NAN;
+using ::WIFI_INTERFACE_P2P_CLIENT;
+using ::WIFI_INTERFACE_P2P_GO;
+using ::WIFI_INTERFACE_SOFTAP;
+using ::WIFI_INTERFACE_STA;
+using ::WIFI_INTERFACE_TDLS;
+using ::wifi_interface_type;
+using ::WIFI_INTERFACE_TYPE_AP;
+using ::WIFI_INTERFACE_TYPE_NAN;
+using ::WIFI_INTERFACE_TYPE_P2P;
+using ::WIFI_INTERFACE_TYPE_STA;
+using ::WIFI_INTERFACE_UNKNOWN;
+using ::wifi_latency_mode;
+using ::WIFI_LATENCY_MODE_LOW;
+using ::WIFI_LATENCY_MODE_NORMAL;
+using ::wifi_lci_information;
+using ::wifi_lcr_information;
+using ::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
+using ::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+using ::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
+using ::WIFI_LOGGER_PACKET_FATE_SUPPORTED;
+using ::WIFI_LOGGER_POWER_EVENT_SUPPORTED;
+using ::WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
+using ::WIFI_MOTION_EXPECTED;
+using ::WIFI_MOTION_NOT_EXPECTED;
+using ::wifi_motion_pattern;
+using ::WIFI_MOTION_UNKNOWN;
+using ::wifi_multi_sta_use_case;
+using ::wifi_power_scenario;
+using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+using ::WIFI_POWER_SCENARIO_VOICE_CALL;
+using ::wifi_rate;
+using ::wifi_request_id;
+using ::wifi_ring_buffer_status;
+using ::wifi_roaming_capabilities;
+using ::wifi_roaming_config;
+using ::wifi_rtt_bw;
+using ::WIFI_RTT_BW_10;
+using ::WIFI_RTT_BW_160;
+using ::WIFI_RTT_BW_20;
+using ::WIFI_RTT_BW_320;
+using ::WIFI_RTT_BW_40;
+using ::WIFI_RTT_BW_5;
+using ::WIFI_RTT_BW_80;
+using ::wifi_rtt_capabilities;
+using ::wifi_rtt_config;
+using ::wifi_rtt_preamble;
+using ::WIFI_RTT_PREAMBLE_EHT;
+using ::WIFI_RTT_PREAMBLE_HE;
+using ::WIFI_RTT_PREAMBLE_HT;
+using ::WIFI_RTT_PREAMBLE_LEGACY;
+using ::WIFI_RTT_PREAMBLE_VHT;
+using ::wifi_rtt_responder;
+using ::wifi_rtt_result;
+using ::wifi_rtt_status;
+using ::wifi_rtt_type;
+using ::wifi_rx_packet_fate;
+using ::wifi_rx_report;
+using ::wifi_scan_bucket_spec;
+using ::wifi_scan_cmd_params;
+using ::WIFI_SCAN_FLAG_INTERRUPTED;
+using ::wifi_scan_result;
+using ::WIFI_SUCCESS;
+using ::wifi_tx_packet_fate;
+using ::wifi_tx_report;
+using ::wifi_usable_channel;
+using ::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+using ::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
+using ::WLAN_MAC_2_4_BAND;
+using ::WLAN_MAC_5_0_BAND;
+using ::WLAN_MAC_60_0_BAND;
+using ::WLAN_MAC_6_0_BAND;
+
+// APF capabilities supported by the iface.
+struct PacketFilterCapabilities {
+    uint32_t version;
+    uint32_t max_len;
+};
+
+// WARNING: We don't care about the variable sized members of either
+// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
+// to escape the compiler warnings regarding this.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
+// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
+// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+    wifi_radio_stat stats;
+    std::vector<uint32_t> tx_time_per_levels;
+    std::vector<wifi_channel_stat> channel_stats;
+};
+
+struct WifiPeerInfo {
+    wifi_peer_info peer_info;
+    std::vector<wifi_rate_stat> rate_stats;
+};
+
+struct LinkLayerStats {
+    wifi_iface_stat iface;
+    std::vector<LinkLayerRadioStats> radios;
+    std::vector<WifiPeerInfo> peers;
+};
+#pragma GCC diagnostic pop
+
+// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
+// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
+// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
+// API. Separate that out into a separate return elements to avoid passing
+// pointers around.
+struct WakeReasonStats {
+    WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
+    std::vector<uint32_t> cmd_event_wake_cnt;
+    std::vector<uint32_t> driver_fw_local_wake_cnt;
+};
+
+// NAN response and event callbacks struct.
+struct NanCallbackHandlers {
+    // NotifyResponse invoked to notify the status of the Request.
+    std::function<void(transaction_id, const NanResponseMsg&)> on_notify_response;
+    // Various event callbacks.
+    std::function<void(const NanPublishTerminatedInd&)> on_event_publish_terminated;
+    std::function<void(const NanMatchInd&)> on_event_match;
+    std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
+    std::function<void(const NanSubscribeTerminatedInd&)> on_event_subscribe_terminated;
+    std::function<void(const NanFollowupInd&)> on_event_followup;
+    std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
+    std::function<void(const NanDisabledInd&)> on_event_disabled;
+    std::function<void(const NanTCAInd&)> on_event_tca;
+    std::function<void(const NanBeaconSdfPayloadInd&)> on_event_beacon_sdf_payload;
+    std::function<void(const NanDataPathRequestInd&)> on_event_data_path_request;
+    std::function<void(const NanDataPathConfirmInd&)> on_event_data_path_confirm;
+    std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
+    std::function<void(const NanTransmitFollowupInd&)> on_event_transmit_follow_up;
+    std::function<void(const NanRangeRequestInd&)> on_event_range_request;
+    std::function<void(const NanRangeReportInd&)> on_event_range_report;
+    std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
+};
+
+// Full scan results contain IE info and are hence passed by reference, to
+// preserve the variable length array member |ie_data|. Callee must not retain
+// the pointer.
+using on_gscan_full_result_callback =
+        std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
+// These scan results don't contain any IE info, so no need to pass by
+// reference.
+using on_gscan_results_callback =
+        std::function<void(wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
+
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+        std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
+
+// Callback for RTT range request results.
+// Rtt results contain IE info and are hence passed by reference, to
+// preserve the |LCI| and |LCR| pointers. Callee must not retain
+// the pointer.
+using on_rtt_results_callback =
+        std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
+
+// Callback for ring buffer data.
+using on_ring_buffer_data_callback = std::function<void(
+        const std::string&, const std::vector<uint8_t>&, const wifi_ring_buffer_status&)>;
+
+// Callback for alerts.
+using on_error_alert_callback = std::function<void(int32_t, const std::vector<uint8_t>&)>;
+
+// Callback for subsystem restart
+using on_subsystem_restart_callback = std::function<void(const std::string&)>;
+
+// Struct for the mac info from the legacy HAL. This is a cleaner version
+// of the |wifi_mac_info| & |wifi_iface_info|.
+typedef struct {
+    std::string name;
+    wifi_channel channel;
+} WifiIfaceInfo;
+
+typedef struct {
+    uint32_t wlan_mac_id;
+    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+    uint32_t mac_band;
+    /* Represents the connected Wi-Fi interfaces associated with each MAC */
+    std::vector<WifiIfaceInfo> iface_infos;
+} WifiMacInfo;
+
+// Callback for radio mode change
+using on_radio_mode_change_callback = std::function<void(const std::vector<WifiMacInfo>&)>;
+
+// TWT response and event callbacks struct.
+struct TwtCallbackHandlers {
+    // Callback for TWT setup response
+    std::function<void(const TwtSetupResponse&)> on_setup_response;
+    // Callback for TWT teardown completion
+    std::function<void(const TwtTeardownCompletion&)> on_teardown_completion;
+    // Callback for TWT info frame received event
+    std::function<void(const TwtInfoFrameReceived&)> on_info_frame_received;
+    // Callback for TWT notification from the device
+    std::function<void(const TwtDeviceNotify&)> on_device_notify;
+};
+
+/**
+ * Class that encapsulates all legacy HAL interactions.
+ * This class manages the lifetime of the event loop thread used by legacy HAL.
+ *
+ * Note: There will only be a single instance of this class created in the Wifi
+ * object and will be valid for the lifetime of the process.
+ */
+class WifiLegacyHal {
+  public:
+    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool, const wifi_hal_fn& fn,
+                  bool is_primary);
+    virtual ~WifiLegacyHal() = default;
+
+    // Initialize the legacy HAL function table.
+    virtual wifi_error initialize();
+    // Start the legacy HAL and the event looper thread.
+    virtual wifi_error start();
+    // Deinitialize the legacy HAL and wait for the event loop thread to exit
+    // using a predefined timeout.
+    virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
+                            const std::function<void()>& on_complete_callback);
+    virtual wifi_error waitForDriverReady();
+    // Checks if legacy HAL has successfully started
+    bool isStarted();
+    // Wrappers for all the functions in the legacy HAL function table.
+    virtual std::pair<wifi_error, std::string> getDriverVersion(const std::string& iface_name);
+    virtual std::pair<wifi_error, std::string> getFirmwareVersion(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
+            const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
+            const std::string& iface_name);
+    std::pair<wifi_error, uint64_t> getSupportedFeatureSet(const std::string& iface_name);
+    // APF functions.
+    std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
+            const std::string& iface_name);
+    wifi_error setPacketFilter(const std::string& iface_name, const std::vector<uint8_t>& program);
+    std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
+            const std::string& iface_name);
+    // Gscan functions.
+    std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
+            const std::string& iface_name);
+    // These API's provides a simplified interface over the legacy Gscan API's:
+    // a) All scan events from the legacy HAL API other than the
+    //    |WIFI_SCAN_FAILED| are treated as notification of results.
+    //    This method then retrieves the cached scan results from the legacy
+    //    HAL API and triggers the externally provided
+    //    |on_results_user_callback| on success.
+    // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
+    // results
+    //    triggers the externally provided |on_failure_user_callback|.
+    // c) Full scan result event triggers the externally provided
+    //    |on_full_result_user_callback|.
+    wifi_error startGscan(const std::string& iface_name, wifi_request_id id,
+                          const wifi_scan_cmd_params& params,
+                          const std::function<void(wifi_request_id)>& on_failure_callback,
+                          const on_gscan_results_callback& on_results_callback,
+                          const on_gscan_full_result_callback& on_full_result_callback);
+    wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
+    std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
+            const std::string& iface_name, wifi_band band);
+    virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
+    // Link layer stats functions.
+    wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
+    wifi_error disableLinkLayerStats(const std::string& iface_name);
+    std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(const std::string& iface_name);
+    // RSSI monitor functions.
+    wifi_error startRssiMonitoring(
+            const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
+            const on_rssi_threshold_breached_callback& on_threshold_breached_callback);
+    wifi_error stopRssiMonitoring(const std::string& iface_name, wifi_request_id id);
+    std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
+            const std::string& iface_name);
+    wifi_error configureRoaming(const std::string& iface_name, const wifi_roaming_config& config);
+    wifi_error enableFirmwareRoaming(const std::string& iface_name, fw_roaming_state_t state);
+    wifi_error configureNdOffload(const std::string& iface_name, bool enable);
+    wifi_error startSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id,
+                                           uint16_t ether_type,
+                                           const std::vector<uint8_t>& ip_packet_data,
+                                           const std::array<uint8_t, 6>& src_address,
+                                           const std::array<uint8_t, 6>& dst_address,
+                                           uint32_t period_in_ms);
+    wifi_error stopSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id);
+    virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
+                                             wifi_power_scenario scenario);
+    virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
+    wifi_error setLatencyMode(const std::string& iface_name, wifi_latency_mode mode);
+    wifi_error setThermalMitigationMode(wifi_thermal_mode mode, uint32_t completion_window);
+    wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+                                              uint32_t access_category);
+    wifi_error resetDscpToAccessCategoryMapping();
+    // Logger/debug functions.
+    std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(const std::string& iface_name);
+    wifi_error startPktFateMonitoring(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(const std::string& iface_name);
+    std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(const std::string& iface_name);
+    wifi_error registerRingBufferCallbackHandler(
+            const std::string& iface_name, const on_ring_buffer_data_callback& on_data_callback);
+    wifi_error deregisterRingBufferCallbackHandler(const std::string& iface_name);
+    wifi_error registerSubsystemRestartCallbackHandler(
+            const on_subsystem_restart_callback& on_restart_callback);
+    std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> getRingBuffersStatus(
+            const std::string& iface_name);
+    wifi_error startRingBufferLogging(const std::string& iface_name, const std::string& ring_name,
+                                      uint32_t verbose_level, uint32_t max_interval_sec,
+                                      uint32_t min_data_size);
+    wifi_error getRingBufferData(const std::string& iface_name, const std::string& ring_name);
+    wifi_error registerErrorAlertCallbackHandler(const std::string& iface_name,
+                                                 const on_error_alert_callback& on_alert_callback);
+    wifi_error deregisterErrorAlertCallbackHandler(const std::string& iface_name);
+    // Radio mode functions.
+    virtual wifi_error registerRadioModeChangeCallbackHandler(
+            const std::string& iface_name,
+            const on_radio_mode_change_callback& on_user_change_callback);
+    // RTT functions.
+    wifi_error startRttRangeRequest(const std::string& iface_name, wifi_request_id id,
+                                    const std::vector<wifi_rtt_config>& rtt_configs,
+                                    const on_rtt_results_callback& on_results_callback);
+    wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id,
+                                     const std::vector<std::array<uint8_t, 6>>& mac_addrs);
+    std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(const std::string& iface_name);
+    std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(const std::string& iface_name);
+    wifi_error enableRttResponder(const std::string& iface_name, wifi_request_id id,
+                                  const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
+                                  const wifi_rtt_responder& info);
+    wifi_error disableRttResponder(const std::string& iface_name, wifi_request_id id);
+    wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lci_information& info);
+    wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lcr_information& info);
+    // NAN functions.
+    virtual wifi_error nanRegisterCallbackHandlers(const std::string& iface_name,
+                                                   const NanCallbackHandlers& callbacks);
+    wifi_error nanEnableRequest(const std::string& iface_name, transaction_id id,
+                                const NanEnableRequest& msg);
+    virtual wifi_error nanDisableRequest(const std::string& iface_name, transaction_id id);
+    wifi_error nanPublishRequest(const std::string& iface_name, transaction_id id,
+                                 const NanPublishRequest& msg);
+    wifi_error nanPublishCancelRequest(const std::string& iface_name, transaction_id id,
+                                       const NanPublishCancelRequest& msg);
+    wifi_error nanSubscribeRequest(const std::string& iface_name, transaction_id id,
+                                   const NanSubscribeRequest& msg);
+    wifi_error nanSubscribeCancelRequest(const std::string& iface_name, transaction_id id,
+                                         const NanSubscribeCancelRequest& msg);
+    wifi_error nanTransmitFollowupRequest(const std::string& iface_name, transaction_id id,
+                                          const NanTransmitFollowupRequest& msg);
+    wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
+                               const NanStatsRequest& msg);
+    wifi_error nanConfigRequest(const std::string& iface_name, transaction_id id,
+                                const NanConfigRequest& msg);
+    wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
+                             const NanTCARequest& msg);
+    wifi_error nanBeaconSdfPayloadRequest(const std::string& iface_name, transaction_id id,
+                                          const NanBeaconSdfPayloadRequest& msg);
+    std::pair<wifi_error, NanVersion> nanGetVersion();
+    wifi_error nanGetCapabilities(const std::string& iface_name, transaction_id id);
+    wifi_error nanDataInterfaceCreate(const std::string& iface_name, transaction_id id,
+                                      const std::string& data_iface_name);
+    virtual wifi_error nanDataInterfaceDelete(const std::string& iface_name, transaction_id id,
+                                              const std::string& data_iface_name);
+    wifi_error nanDataRequestInitiator(const std::string& iface_name, transaction_id id,
+                                       const NanDataPathInitiatorRequest& msg);
+    wifi_error nanDataIndicationResponse(const std::string& iface_name, transaction_id id,
+                                         const NanDataPathIndicationResponse& msg);
+    wifi_error nanDataEnd(const std::string& iface_name, transaction_id id, uint32_t ndpInstanceId);
+    // AP functions.
+    wifi_error setCountryCode(const std::string& iface_name, std::array<int8_t, 2> code);
+
+    // interface functions.
+    virtual wifi_error createVirtualInterface(const std::string& ifname,
+                                              wifi_interface_type iftype);
+    virtual wifi_error deleteVirtualInterface(const std::string& ifname);
+    wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
+
+    // STA + STA functions
+    virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
+    virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
+
+    // Coex functions.
+    virtual wifi_error setCoexUnsafeChannels(std::vector<wifi_coex_unsafe_channel> unsafe_channels,
+                                             uint32_t restrictions);
+
+    wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode);
+
+    wifi_error twtRegisterHandler(const std::string& iface_name,
+                                  const TwtCallbackHandlers& handler);
+
+    std::pair<wifi_error, TwtCapabilitySet> twtGetCapability(const std::string& iface_name);
+
+    wifi_error twtSetupRequest(const std::string& iface_name, const TwtSetupRequest& msg);
+
+    wifi_error twtTearDownRequest(const std::string& iface_name, const TwtTeardownRequest& msg);
+
+    wifi_error twtInfoFrameRequest(const std::string& iface_name, const TwtInfoFrameRequest& msg);
+
+    std::pair<wifi_error, TwtStats> twtGetStats(const std::string& iface_name, uint8_t configId);
+
+    wifi_error twtClearStats(const std::string& iface_name, uint8_t configId);
+
+    wifi_error setDtimConfig(const std::string& iface_name, uint32_t multiplier);
+
+    // Retrieve the list of usable channels in the requested bands
+    // for the requested modes
+    std::pair<wifi_error, std::vector<wifi_usable_channel>> getUsableChannels(
+            uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask);
+
+    wifi_error triggerSubsystemRestart();
+
+    wifi_error setIndoorState(bool isIndoor);
+
+  private:
+    // Retrieve interface handles for all the available interfaces.
+    wifi_error retrieveIfaceHandles();
+    wifi_interface_handle getIfaceHandle(const std::string& iface_name);
+    // Run the legacy HAL event loop thread.
+    void runEventLoop();
+    // Retrieve the cached gscan results to pass the results back to the
+    // external callbacks.
+    std::pair<wifi_error, std::vector<wifi_cached_scan_results>> getGscanCachedResults(
+            const std::string& iface_name);
+    void invalidate();
+    // Handles wifi (error) status of Virtual interface create/delete
+    wifi_error handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
+                                                          wifi_error status);
+
+    // Global function table of legacy HAL.
+    wifi_hal_fn global_func_table_;
+    // Opaque handle to be used for all global operations.
+    wifi_handle global_handle_;
+    // Map of interface name to handle that is to be used for all interface
+    // specific operations.
+    std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
+    // Flag to indicate if we have initiated the cleanup of legacy HAL.
+    std::atomic<bool> awaiting_event_loop_termination_;
+    std::condition_variable_any stop_wait_cv_;
+    // Flag to indicate if the legacy HAL has been started.
+    bool is_started_;
+    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    // flag to indicate if this HAL is for the primary chip. This is used
+    // in order to avoid some hard-coded behavior used with older HALs,
+    // such as bring wlan0 interface up/down on start/stop HAL.
+    // it may be removed once vendor HALs are updated.
+    bool is_primary_;
+};
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal_factory.cpp b/wifi/1.6/default/wifi_legacy_hal_factory.cpp
new file mode 100644
index 0000000..147bf4d
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_factory.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <dlfcn.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
+static constexpr char kVendorHalsDescExt[] = ".xml";
+static constexpr uint32_t kVendorHalsDescVersion = 1;
+
+bool isDirectory(struct dirent* entryPtr) {
+    bool isDir = false;
+    if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
+        isDir = (entryPtr->d_type == DT_DIR);
+    } else {
+        struct stat entryStat;
+        stat(entryPtr->d_name, &entryStat);
+        isDir = S_ISDIR(entryStat.st_mode);
+    }
+    return isDir;
+}
+
+bool isFileExtension(const char* name, const char* ext) {
+    if (name == NULL) return false;
+    if (ext == NULL) return false;
+
+    size_t extLen = strlen(ext);
+    size_t nameLen = strlen(name);
+
+    if (extLen > nameLen) return false;
+
+    if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
+
+    return true;
+}
+};  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+WifiLegacyHalFactory::WifiLegacyHalFactory(
+        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+    : iface_tool_(iface_tool) {}
+
+std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
+    if (legacy_hals_.empty()) {
+        if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList();
+        for (auto& desc : descs_) {
+            std::shared_ptr<WifiLegacyHal> hal =
+                    std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn, desc.primary);
+            legacy_hals_.push_back(hal);
+        }
+    }
+
+    return legacy_hals_;
+}
+
+bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
+    wifi_hal_lib_desc desc;
+
+    if (!initLinkedHalFunctionTable(&desc.fn)) return false;
+
+    desc.primary = true;
+    desc.handle = NULL;
+    descs_.push_back(desc);
+    return true;
+}
+
+bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
+    init_wifi_vendor_hal_func_table_t initfn;
+
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(RTLD_DEFAULT,
+                                                      "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
+        return false;
+    }
+
+    if (!initHalFuncTableWithStubs(hal_fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        return false;
+    }
+
+    if (initfn(hal_fn) != WIFI_SUCCESS) {
+        LOG(ERROR) << "Can not initialize the vendor function pointer table";
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Overall structure of the HAL descriptor XML schema
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <WifiVendorHal version="1">
+ * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
+ * <primary>1</primary>
+ * </WifiVendorHal>
+ */
+void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
+    xmlDocPtr xml;
+    xmlNodePtr node, cnode;
+    char* version;
+    std::string path;
+    xmlChar* value;
+    wifi_hal_lib_desc desc;
+
+    LOG(INFO) << "processing vendor HALs descriptions in " << kVendorHalsDescPath;
+    DIR* dirPtr = ::opendir(kVendorHalsDescPath);
+    if (dirPtr == NULL) {
+        LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
+        return;
+    }
+    for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
+         entryPtr = ::readdir(dirPtr)) {
+        if (isDirectory(entryPtr)) continue;
+
+        if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
+            continue;  // only process .xml files
+
+        LOG(INFO) << "processing config file: " << entryPtr->d_name;
+
+        std::string fullPath(kVendorHalsDescPath);
+        fullPath.append("/");
+        fullPath.append(entryPtr->d_name);
+        xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
+        if (!xml) {
+            LOG(ERROR) << "failed to parse: " << entryPtr->d_name << " skipping...";
+            continue;
+        }
+        node = xmlDocGetRootElement(xml);
+        if (!node) {
+            LOG(ERROR) << "empty config file: " << entryPtr->d_name << " skipping...";
+            goto skip;
+        }
+        if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
+            LOG(ERROR) << "bad config, root element not WifiVendorHal: " << entryPtr->d_name
+                       << " skipping...";
+            goto skip;
+        }
+        version = (char*)xmlGetProp(node, BAD_CAST "version");
+        if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
+            LOG(ERROR) << "conf file: " << entryPtr->d_name
+                       << "must have version: " << kVendorHalsDescVersion << ", skipping...";
+            goto skip;
+        }
+        cnode = node->children;
+        path.clear();
+        desc.primary = false;
+        while (cnode) {
+            if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                if (value) path = (char*)value;
+                xmlFree(value);
+            } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                desc.primary = !xmlStrcmp(value, BAD_CAST "1");
+                xmlFree(value);
+            }
+            cnode = cnode->next;
+        }
+        if (path.empty()) {
+            LOG(ERROR) << "hal library path not provided in: " << entryPtr->d_name
+                       << ", skipping...";
+            goto skip;
+        }
+        if (loadVendorHalLib(path, desc)) {
+            if (desc.primary)
+                descs_.insert(descs_.begin(), desc);
+            else
+                descs_.push_back(desc);
+        }
+    skip:
+        xmlFreeDoc(xml);
+    }
+    ::closedir(dirPtr);
+}
+
+bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc) {
+    void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
+    init_wifi_vendor_hal_func_table_t initfn;
+    wifi_error res;
+
+    if (!h) {
+        LOG(ERROR) << "failed to open vendor hal library: " << path;
+        return false;
+    }
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(h, "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
+        goto out_err;
+    }
+
+    if (!initHalFuncTableWithStubs(&desc.fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        goto out_err;
+    }
+    res = initfn(&desc.fn);
+    if (res != WIFI_SUCCESS) {
+        LOG(ERROR) << "failed to initialize the vendor func table in: " << path
+                   << " error: " << res;
+        goto out_err;
+    }
+
+    res = desc.fn.wifi_early_initialize();
+    // vendor HALs which do not implement early_initialize will return
+    // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
+    if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
+        LOG(ERROR) << "early initialization failed in: " << path << " error: " << res;
+        goto out_err;
+    }
+
+    desc.handle = h;
+    return true;
+out_err:
+    dlclose(h);
+    return false;
+}
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal_factory.h b/wifi/1.6/default/wifi_legacy_hal_factory.h
new file mode 100644
index 0000000..9f4423e
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_factory.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_FACTORY_H_
+#define WIFI_LEGACY_HAL_FACTORY_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+/**
+ * Class that creates WifiLegacyHal objects for vendor HALs in the system.
+ */
+class WifiLegacyHalFactory {
+  public:
+    WifiLegacyHalFactory(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    virtual ~WifiLegacyHalFactory() = default;
+
+    std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
+
+  private:
+    typedef struct {
+        wifi_hal_fn fn;
+        bool primary;
+        void* handle;
+    } wifi_hal_lib_desc;
+
+    bool initVendorHalDescriptorFromLinked();
+    void initVendorHalsDescriptorList();
+    bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
+    bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
+
+    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    std::vector<wifi_hal_lib_desc> descs_;
+    std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
+};
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.cpp b/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
new file mode 100644
index 0000000..7e66fab
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2016 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 "wifi_legacy_hal_stubs.h"
+
+// TODO: Remove these stubs from HalTool in libwifi-system.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+template <typename>
+struct stubFunction;
+
+template <typename R, typename... Args>
+struct stubFunction<R (*)(Args...)> {
+    static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
+};
+template <typename... Args>
+struct stubFunction<void (*)(Args...)> {
+    static constexpr void invoke(Args...) {}
+};
+
+template <typename T>
+void populateStubFor(T* val) {
+    *val = &stubFunction<T>::invoke;
+}
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
+    if (hal_fn == nullptr) {
+        return false;
+    }
+    populateStubFor(&hal_fn->wifi_initialize);
+    populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
+    populateStubFor(&hal_fn->wifi_cleanup);
+    populateStubFor(&hal_fn->wifi_event_loop);
+    populateStubFor(&hal_fn->wifi_get_error_info);
+    populateStubFor(&hal_fn->wifi_get_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
+    populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
+    populateStubFor(&hal_fn->wifi_get_supported_channels);
+    populateStubFor(&hal_fn->wifi_is_epr_supported);
+    populateStubFor(&hal_fn->wifi_get_ifaces);
+    populateStubFor(&hal_fn->wifi_get_iface_name);
+    populateStubFor(&hal_fn->wifi_set_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_start_gscan);
+    populateStubFor(&hal_fn->wifi_stop_gscan);
+    populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
+    populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_set_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
+    populateStubFor(&hal_fn->wifi_set_link_stats);
+    populateStubFor(&hal_fn->wifi_get_link_stats);
+    populateStubFor(&hal_fn->wifi_clear_link_stats);
+    populateStubFor(&hal_fn->wifi_get_valid_channels);
+    populateStubFor(&hal_fn->wifi_rtt_range_request);
+    populateStubFor(&hal_fn->wifi_rtt_range_cancel);
+    populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
+    populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
+    populateStubFor(&hal_fn->wifi_enable_responder);
+    populateStubFor(&hal_fn->wifi_disable_responder);
+    populateStubFor(&hal_fn->wifi_set_nodfs_flag);
+    populateStubFor(&hal_fn->wifi_start_logging);
+    populateStubFor(&hal_fn->wifi_set_epno_list);
+    populateStubFor(&hal_fn->wifi_reset_epno_list);
+    populateStubFor(&hal_fn->wifi_set_country_code);
+    populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
+    populateStubFor(&hal_fn->wifi_set_log_handler);
+    populateStubFor(&hal_fn->wifi_reset_log_handler);
+    populateStubFor(&hal_fn->wifi_set_alert_handler);
+    populateStubFor(&hal_fn->wifi_reset_alert_handler);
+    populateStubFor(&hal_fn->wifi_get_firmware_version);
+    populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
+    populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_ring_data);
+    populateStubFor(&hal_fn->wifi_enable_tdls);
+    populateStubFor(&hal_fn->wifi_disable_tdls);
+    populateStubFor(&hal_fn->wifi_get_tdls_status);
+    populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
+    populateStubFor(&hal_fn->wifi_get_driver_version);
+    populateStubFor(&hal_fn->wifi_set_passpoint_list);
+    populateStubFor(&hal_fn->wifi_reset_passpoint_list);
+    populateStubFor(&hal_fn->wifi_set_lci);
+    populateStubFor(&hal_fn->wifi_set_lcr);
+    populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
+    populateStubFor(&hal_fn->wifi_configure_nd_offload);
+    populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
+    populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
+    populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_nan_enable_request);
+    populateStubFor(&hal_fn->wifi_nan_disable_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
+    populateStubFor(&hal_fn->wifi_nan_stats_request);
+    populateStubFor(&hal_fn->wifi_nan_config_request);
+    populateStubFor(&hal_fn->wifi_nan_tca_request);
+    populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
+    populateStubFor(&hal_fn->wifi_nan_register_handler);
+    populateStubFor(&hal_fn->wifi_nan_get_version);
+    populateStubFor(&hal_fn->wifi_nan_get_capabilities);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_create);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
+    populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
+    populateStubFor(&hal_fn->wifi_nan_data_indication_response);
+    populateStubFor(&hal_fn->wifi_nan_data_end);
+    populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
+    populateStubFor(&hal_fn->wifi_set_packet_filter);
+    populateStubFor(&hal_fn->wifi_read_packet_filter);
+    populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
+    populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
+    populateStubFor(&hal_fn->wifi_configure_roaming);
+    populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
+    populateStubFor(&hal_fn->wifi_set_latency_mode);
+    populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+    populateStubFor(&hal_fn->wifi_virtual_interface_create);
+    populateStubFor(&hal_fn->wifi_virtual_interface_delete);
+    populateStubFor(&hal_fn->wifi_map_dscp_access_category);
+    populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
+    populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
+    populateStubFor(&hal_fn->wifi_get_supported_iface_name);
+    populateStubFor(&hal_fn->wifi_early_initialize);
+    populateStubFor(&hal_fn->wifi_get_chip_feature_set);
+    populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
+    populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
+    populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels);
+    populateStubFor(&hal_fn->wifi_set_voip_mode);
+    populateStubFor(&hal_fn->wifi_twt_register_handler);
+    populateStubFor(&hal_fn->wifi_twt_get_capability);
+    populateStubFor(&hal_fn->wifi_twt_setup_request);
+    populateStubFor(&hal_fn->wifi_twt_teardown_request);
+    populateStubFor(&hal_fn->wifi_twt_info_frame_request);
+    populateStubFor(&hal_fn->wifi_twt_get_stats);
+    populateStubFor(&hal_fn->wifi_twt_clear_stats);
+    populateStubFor(&hal_fn->wifi_set_dtim_config);
+    populateStubFor(&hal_fn->wifi_get_usable_channels);
+    populateStubFor(&hal_fn->wifi_trigger_subsystem_restart);
+    populateStubFor(&hal_fn->wifi_set_indoor_state);
+    return true;
+}
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.h b/wifi/1.6/default/wifi_legacy_hal_stubs.h
new file mode 100644
index 0000000..c9a03bf
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_stubs.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_STUBS_H_
+#define WIFI_LEGACY_HAL_STUBS_H_
+
+#include <hardware_legacy/wifi_hal.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.6/default/wifi_mode_controller.cpp b/wifi/1.6/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..4b8ac7d
--- /dev/null
+++ b/wifi/1.6/default/wifi_mode_controller.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_mode_controller.h"
+
+using android::hardware::wifi::V1_0::IfaceType;
+using android::wifi_hal::DriverTool;
+
+namespace {
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+    int mode;
+    switch (type) {
+        case IfaceType::AP:
+            mode = DriverTool::kFirmwareModeAp;
+            break;
+        case IfaceType::P2P:
+            mode = DriverTool::kFirmwareModeP2p;
+            break;
+        case IfaceType::NAN:
+            // NAN is exposed in STA mode currently.
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+        case IfaceType::STA:
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+    }
+    return mode;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+    return driver_tool_->IsFirmwareModeChangeNeeded(convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::initialize() {
+    if (!driver_tool_->LoadDriver()) {
+        LOG(ERROR) << "Failed to load WiFi driver";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+    if (!driver_tool_->ChangeFirmwareMode(convertIfaceTypeToFirmwareMode(type))) {
+        LOG(ERROR) << "Failed to change firmware mode";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::deinitialize() {
+    if (!driver_tool_->UnloadDriver()) {
+        LOG(ERROR) << "Failed to unload WiFi driver";
+        return false;
+    }
+    return true;
+}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_mode_controller.h b/wifi/1.6/default/wifi_mode_controller.h
new file mode 100644
index 0000000..fee2b66
--- /dev/null
+++ b/wifi/1.6/default/wifi_mode_controller.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <wifi_hal/driver_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+  public:
+    WifiModeController();
+    virtual ~WifiModeController() = default;
+
+    // Checks if a firmware mode change is necessary to support the specified
+    // iface type operations.
+    virtual bool isFirmwareModeChangeNeeded(IfaceType type);
+    virtual bool initialize();
+    // Change the firmware mode to support the specified iface type operations.
+    virtual bool changeFirmwareMode(IfaceType type);
+    // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+    // invoked.
+    virtual bool deinitialize();
+
+  private:
+    std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
+};
+
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.6/default/wifi_nan_iface.cpp b/wifi/1.6/default/wifi_nan_iface.cpp
new file mode 100644
index 0000000..ac2ebc9
--- /dev/null
+++ b/wifi/1.6/default/wifi_nan_iface.cpp
@@ -0,0 +1,1016 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_nan_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiNanIface::WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
+                           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                           const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname),
+      is_dedicated_iface_(is_dedicated_iface),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true) {
+    if (is_dedicated_iface_) {
+        // If using a dedicated iface, set the iface up first.
+        if (!iface_util_.lock()->setUpState(ifname_, true)) {
+            // Fatal failure, invalidate the iface object.
+            invalidate();
+            return;
+        }
+    }
+    // Register all the callbacks here. these should be valid for the lifetime
+    // of the object. Whenever the mode changes legacy HAL will remove
+    // all of these callbacks.
+    legacy_hal::NanCallbackHandlers callback_handlers;
+    android::wp<WifiNanIface> weak_ptr_this(this);
+
+    // Callback for response.
+    callback_handlers.on_notify_response = [weak_ptr_this](legacy_hal::transaction_id id,
+                                                           const legacy_hal::NanResponseMsg& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        WifiNanStatus wifiNanStatus;
+        if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(msg, &wifiNanStatus)) {
+            LOG(ERROR) << "Failed to convert nan response header";
+            return;
+        }
+
+        switch (msg.response_type) {
+            case legacy_hal::NAN_RESPONSE_ENABLED: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyEnableResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_DISABLED: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyDisableResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStartPublishResponse(id, wifiNanStatus,
+                                                              msg.body.publish_response.publish_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStopPublishResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyTransmitFollowupResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStartSubscribeResponse(
+                                         id, wifiNanStatus,
+                                         msg.body.subscribe_response.subscribe_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStopSubscribeResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_CONFIG: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyConfigResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_GET_CAPABILITIES: {
+                V1_6::NanCapabilities hidl_struct;
+                if (!hidl_struct_util::convertLegacyNanCapabilitiesResponseToHidl(
+                            msg.body.nan_capabilities, &hidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+                    if (!callback->notifyCapabilitiesResponse_1_6(id, wifiNanStatus, hidl_struct)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_CREATE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyCreateDataInterfaceResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_DELETE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyDeleteDataInterfaceResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyInitiateDataPathResponse(
+                                         id, wifiNanStatus,
+                                         msg.body.data_request_response.ndp_instance_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyRespondToDataPathIndicationResponse(id, wifiNanStatus)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_END: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyTerminateDataPathResponse(id, wifiNanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_TCA:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_STATS:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_ERROR:
+            /* fall through */
+            default:
+                LOG(ERROR) << "Unknown or unhandled response type: " << msg.response_type;
+                return;
+        }
+    };
+
+    callback_handlers.on_event_disc_eng_event =
+            [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanClusterEventInd hidl_struct;
+                // event types defined identically - hence can be cast
+                hidl_struct.eventType = (NanClusterEventType)msg.event_type;
+                hidl_struct.addr = msg.data.mac_addr.addr;
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventClusterEvent(hidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_disabled = [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        WifiNanStatus status;
+        hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
+                                                 &status);
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventDisabled(status).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_publish_terminated =
+            [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                WifiNanStatus status;
+                hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason,
+                                                         sizeof(msg.nan_reason), &status);
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventPublishTerminated(msg.publish_id, status).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_subscribe_terminated =
+            [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                WifiNanStatus status;
+                hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason,
+                                                         sizeof(msg.nan_reason), &status);
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventSubscribeTerminated(msg.subscribe_id, status).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_match = [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        V1_6::NanMatchInd hidl_struct;
+        if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(msg, &hidl_struct)) {
+            LOG(ERROR) << "Failed to convert nan capabilities response";
+            return;
+        }
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+            if (!callback->eventMatch_1_6(hidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_match_expired = [weak_ptr_this](
+                                                       const legacy_hal::NanMatchExpiredInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventMatchExpired(msg.publish_subscribe_id, msg.requestor_instance_id)
+                         .isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_followup = [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanFollowupReceivedInd hidl_struct;
+        if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(msg, &hidl_struct)) {
+            LOG(ERROR) << "Failed to convert nan capabilities response";
+            return;
+        }
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_transmit_follow_up =
+            [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                WifiNanStatus status;
+                hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason,
+                                                         sizeof(msg.nan_reason), &status);
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_data_path_request =
+            [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanDataPathRequestInd hidl_struct;
+                if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(msg,
+                                                                                &hidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_data_path_confirm =
+            [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                V1_6::NanDataPathConfirmInd hidl_struct;
+                if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(msg,
+                                                                                &hidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+                    if (!callback->eventDataPathConfirm_1_6(hidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_data_path_end =
+            [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    for (int i = 0; i < msg.num_ndp_instances; ++i) {
+                        if (!callback->eventDataPathTerminated(msg.ndp_instance_id[i]).isOk()) {
+                            LOG(ERROR) << "Failed to invoke the callback";
+                        }
+                    }
+                }
+            };
+
+    callback_handlers.on_event_beacon_sdf_payload =
+            [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
+                LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
+            };
+
+    callback_handlers.on_event_range_request =
+            [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
+                LOG(ERROR) << "on_event_range_request - should not be called";
+            };
+
+    callback_handlers.on_event_range_report =
+            [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
+                LOG(ERROR) << "on_event_range_report - should not be called";
+            };
+
+    callback_handlers.on_event_schedule_update =
+            [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                V1_6::NanDataPathScheduleUpdateInd hidl_struct;
+                if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
+                            msg, &hidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+                    if (!callback->eventDataPathScheduleUpdate_1_6(hidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_, callback_handlers);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
+        invalidate();
+    }
+
+    // Register for iface state toggle events.
+    iface_util::IfaceEventHandlers event_handlers = {};
+    event_handlers.on_state_toggle_off_on = [weak_ptr_this](const std::string& /* iface_name */) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        // Tell framework that NAN has been disabled.
+        WifiNanStatus status = {NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventDisabled(status).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+    iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
+}
+
+void WifiNanIface::invalidate() {
+    if (!isValid()) {
+        return;
+    }
+    // send commands to HAL to actually disable and destroy interfaces
+    legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
+    iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    event_cb_handler_1_2_.invalidate();
+    event_cb_handler_1_5_.invalidate();
+    is_valid_ = false;
+    if (is_dedicated_iface_) {
+        // If using a dedicated iface, set the iface down.
+        iface_util_.lock()->setUpState(ifname_, false);
+    }
+}
+
+bool WifiNanIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiNanIface::getName() {
+    return ifname_;
+}
+
+std::set<sp<V1_0::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+std::set<sp<V1_2::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_2() {
+    return event_cb_handler_1_2_.getCallbacks();
+}
+
+std::set<sp<V1_5::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_5() {
+    return event_cb_handler_1_5_.getCallbacks();
+}
+
+std::set<sp<V1_6::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_6() {
+    return event_cb_handler_1_6_.getCallbacks();
+}
+
+Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::registerEventCallback(
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallbackInternal, hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest(uint16_t cmd_id,
+                                                  getCapabilitiesRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getCapabilitiesRequestInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::enableRequest(uint16_t cmd_id, const V1_0::NanEnableRequest& msg,
+                                         enableRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequestInternal, hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::configRequest(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+                                         configRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequestInternal, hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::disableRequest(uint16_t cmd_id, disableRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::disableRequestInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::startPublishRequest(uint16_t cmd_id, const V1_0::NanPublishRequest& msg,
+                                               startPublishRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startPublishRequestInternal, hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopPublishRequest(uint16_t cmd_id, uint8_t sessionId,
+                                              stopPublishRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopPublishRequestInternal, hidl_status_cb, cmd_id,
+                           sessionId);
+}
+
+Return<void> WifiNanIface::startSubscribeRequest(uint16_t cmd_id,
+                                                 const V1_0::NanSubscribeRequest& msg,
+                                                 startSubscribeRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startSubscribeRequestInternal, hidl_status_cb, cmd_id,
+                           msg);
+}
+
+Return<void> WifiNanIface::stopSubscribeRequest(uint16_t cmd_id, uint8_t sessionId,
+                                                stopSubscribeRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopSubscribeRequestInternal, hidl_status_cb, cmd_id,
+                           sessionId);
+}
+
+Return<void> WifiNanIface::transmitFollowupRequest(uint16_t cmd_id,
+                                                   const NanTransmitFollowupRequest& msg,
+                                                   transmitFollowupRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::transmitFollowupRequestInternal, hidl_status_cb, cmd_id,
+                           msg);
+}
+
+Return<void> WifiNanIface::createDataInterfaceRequest(
+        uint16_t cmd_id, const hidl_string& iface_name,
+        createDataInterfaceRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::createDataInterfaceRequestInternal, hidl_status_cb,
+                           cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::deleteDataInterfaceRequest(
+        uint16_t cmd_id, const hidl_string& iface_name,
+        deleteDataInterfaceRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::deleteDataInterfaceRequestInternal, hidl_status_cb,
+                           cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::initiateDataPathRequest(uint16_t cmd_id,
+                                                   const V1_0::NanInitiateDataPathRequest& msg,
+                                                   initiateDataPathRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::initiateDataPathRequestInternal, hidl_status_cb, cmd_id,
+                           msg);
+}
+
+Return<void> WifiNanIface::respondToDataPathIndicationRequest(
+        uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg,
+        respondToDataPathIndicationRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::respondToDataPathIndicationRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::terminateDataPathRequest(uint16_t cmd_id, uint32_t ndpInstanceId,
+                                                    terminateDataPathRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::terminateDataPathRequestInternal, hidl_status_cb, cmd_id,
+                           ndpInstanceId);
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_2(
+        const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallback_1_2Internal, hidl_status_cb,
+                           callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_2(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+                                             const V1_2::NanConfigRequestSupplemental& msg2,
+                                             enableRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_2Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_2(uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
+                                             const V1_2::NanConfigRequestSupplemental& msg2,
+                                             configRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_2Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::enableRequest_1_4(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                             const V1_2::NanConfigRequestSupplemental& msg2,
+                                             enableRequest_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_4Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_4(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+                                             const V1_2::NanConfigRequestSupplemental& msg2,
+                                             configRequest_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_4Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_5(
+        const sp<V1_5::IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallback_1_5Internal, hidl_status_cb,
+                           callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_5(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                             const V1_5::NanConfigRequestSupplemental& msg2,
+                                             enableRequest_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_5Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_5(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+                                             const V1_5::NanConfigRequestSupplemental& msg2,
+                                             configRequest_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_5Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest_1_5(
+        uint16_t cmd_id, getCapabilitiesRequest_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getCapabilitiesRequest_1_5Internal, hidl_status_cb,
+                           cmd_id);
+}
+
+Return<void> WifiNanIface::enableRequest_1_6(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                             const V1_6::NanConfigRequestSupplemental& msg2,
+                                             enableRequest_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_6Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_6(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+                                             const V1_6::NanConfigRequestSupplemental& msg2,
+                                             configRequest_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_6Internal, hidl_status_cb, cmd_id, msg1,
+                           msg2);
+}
+
+Return<void> WifiNanIface::initiateDataPathRequest_1_6(uint16_t cmd_id,
+                                                       const V1_6::NanInitiateDataPathRequest& msg,
+                                                       initiateDataPathRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::initiateDataPathRequest_1_6Internal, hidl_status_cb,
+                           cmd_id, msg);
+}
+
+Return<void> WifiNanIface::respondToDataPathIndicationRequest_1_6(
+        uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg,
+        respondToDataPathIndicationRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::respondToDataPathIndicationRequest_1_6Internal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::startPublishRequest_1_6(uint16_t cmd_id,
+                                                   const V1_6::NanPublishRequest& msg,
+                                                   startPublishRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startPublishRequest_1_6Internal, hidl_status_cb, cmd_id,
+                           msg);
+}
+
+std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_6(
+        const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallback_1_6Internal, hidl_status_cb,
+                           callback);
+}
+
+WifiStatus WifiNanIface::registerEventCallbackInternal(
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t /* cmd_id */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequestInternal(uint16_t /* cmd_id */,
+                                               const V1_0::NanEnableRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequestInternal(uint16_t /* cmd_id */,
+                                               const V1_0::NanConfigRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startPublishRequestInternal(uint16_t /* cmd_id */,
+                                                     const V1_0::NanPublishRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId) {
+    legacy_hal::NanPublishCancelRequest legacy_msg;
+    legacy_msg.publish_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startSubscribeRequestInternal(uint16_t cmd_id,
+                                                       const V1_0::NanSubscribeRequest& msg) {
+    legacy_hal::NanSubscribeRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId) {
+    legacy_hal::NanSubscribeCancelRequest legacy_msg;
+    legacy_msg.subscribe_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::transmitFollowupRequestInternal(uint16_t cmd_id,
+                                                         const NanTransmitFollowupRequest& msg) {
+    legacy_hal::NanTransmitFollowupRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::createDataInterfaceRequestInternal(uint16_t cmd_id,
+                                                            const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(uint16_t cmd_id,
+                                                            const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::initiateDataPathRequestInternal(
+        uint16_t cmd_id, const V1_0::NanInitiateDataPathRequest& msg) {
+    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
+        uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg) {
+    legacy_hal::NanDataPathIndicationResponse legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::terminateDataPathRequestInternal(uint16_t cmd_id, uint32_t ndpInstanceId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
+        const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
+    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+    if (!event_cb_handler_.addCallback(callback_1_0)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    if (!event_cb_handler_1_2_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_2Internal(
+        uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */,
+        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_2Internal(
+        uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg1 */,
+        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_4Internal(
+        uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
+        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_4Internal(
+        uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
+        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_5Internal(
+        const sp<V1_5::IWifiNanIfaceEventCallback>& callback) {
+    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+    if (!event_cb_handler_.addCallback(callback_1_0)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
+    if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    if (!event_cb_handler_1_5_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequest_1_5Internal(uint16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_5Internal(
+        uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
+        const V1_5::NanConfigRequestSupplemental& /* msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_5Internal(
+        uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
+        const V1_5::NanConfigRequestSupplemental& /* msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_6Internal(uint16_t cmd_id,
+                                                   const V1_4::NanEnableRequest& msg1,
+                                                   const V1_6::NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanEnableRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanEnableRequest_1_6ToLegacy(msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::configRequest_1_6Internal(uint16_t cmd_id,
+                                                   const V1_4::NanConfigRequest& msg1,
+                                                   const V1_6::NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanConfigRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanConfigRequest_1_6ToLegacy(msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::initiateDataPathRequest_1_6Internal(
+        uint16_t cmd_id, const V1_6::NanInitiateDataPathRequest& msg) {
+    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::respondToDataPathIndicationRequest_1_6Internal(
+        uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg) {
+    legacy_hal::NanDataPathIndicationResponse legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponse_1_6ToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startPublishRequest_1_6Internal(uint16_t cmd_id,
+                                                         const V1_6::NanPublishRequest& msg) {
+    legacy_hal::NanPublishRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_6Internal(
+        const sp<V1_6::IWifiNanIfaceEventCallback>& callback) {
+    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+    if (!event_cb_handler_.addCallback(callback_1_0)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
+    if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    sp<V1_5::IWifiNanIfaceEventCallback> callback_1_5 = callback;
+    if (!event_cb_handler_1_5_.addCallback(callback_1_5)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    if (!event_cb_handler_1_6_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_nan_iface.h b/wifi/1.6/default/wifi_nan_iface.h
new file mode 100644
index 0000000..15bf572
--- /dev/null
+++ b/wifi/1.6/default/wifi_nan_iface.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_NAN_IFACE_H_
+#define WIFI_NAN_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.6/IWifiNanIface.h>
+#include <android/hardware/wifi/1.6/IWifiNanIfaceEventCallback.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using namespace android::hardware::wifi::V1_2;
+using namespace android::hardware::wifi::V1_4;
+using namespace android::hardware::wifi::V1_6;
+
+/**
+ * HIDL interface object used to control a NAN Iface instance.
+ */
+class WifiNanIface : public V1_6::IWifiNanIface {
+  public:
+    WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+                                       registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilitiesRequest(uint16_t cmd_id,
+                                        getCapabilitiesRequest_cb hidl_status_cb) override;
+    Return<void> enableRequest(uint16_t cmd_id, const V1_0::NanEnableRequest& msg,
+                               enableRequest_cb hidl_status_cb) override;
+    Return<void> configRequest(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+                               configRequest_cb hidl_status_cb) override;
+    Return<void> disableRequest(uint16_t cmd_id, disableRequest_cb hidl_status_cb) override;
+    Return<void> startPublishRequest(uint16_t cmd_id, const V1_0::NanPublishRequest& msg,
+                                     startPublishRequest_cb hidl_status_cb) override;
+    Return<void> stopPublishRequest(uint16_t cmd_id, uint8_t sessionId,
+                                    stopPublishRequest_cb hidl_status_cb) override;
+    Return<void> startSubscribeRequest(uint16_t cmd_id, const V1_0::NanSubscribeRequest& msg,
+                                       startSubscribeRequest_cb hidl_status_cb) override;
+    Return<void> stopSubscribeRequest(uint16_t cmd_id, uint8_t sessionId,
+                                      stopSubscribeRequest_cb hidl_status_cb) override;
+    Return<void> transmitFollowupRequest(uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+                                         transmitFollowupRequest_cb hidl_status_cb) override;
+    Return<void> createDataInterfaceRequest(uint16_t cmd_id, const hidl_string& iface_name,
+                                            createDataInterfaceRequest_cb hidl_status_cb) override;
+    Return<void> deleteDataInterfaceRequest(uint16_t cmd_id, const hidl_string& iface_name,
+                                            deleteDataInterfaceRequest_cb hidl_status_cb) override;
+    Return<void> initiateDataPathRequest(uint16_t cmd_id,
+                                         const V1_0::NanInitiateDataPathRequest& msg,
+                                         initiateDataPathRequest_cb hidl_status_cb) override;
+    Return<void> respondToDataPathIndicationRequest(
+            uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg,
+            respondToDataPathIndicationRequest_cb hidl_status_cb) override;
+    Return<void> terminateDataPathRequest(uint16_t cmd_id, uint32_t ndpInstanceId,
+                                          terminateDataPathRequest_cb hidl_status_cb) override;
+
+    Return<void> registerEventCallback_1_2(const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+                                           registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_2(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+                                   const V1_2::NanConfigRequestSupplemental& msg2,
+                                   enableRequest_1_2_cb hidl_status_cb) override;
+    Return<void> configRequest_1_2(uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
+                                   const V1_2::NanConfigRequestSupplemental& msg2,
+                                   configRequest_1_2_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_4(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                   const V1_2::NanConfigRequestSupplemental& msg2,
+                                   enableRequest_1_4_cb hidl_status_cb) override;
+    Return<void> configRequest_1_4(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+                                   const V1_2::NanConfigRequestSupplemental& msg2,
+                                   configRequest_1_4_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_5(const sp<V1_5::IWifiNanIfaceEventCallback>& callback,
+                                           registerEventCallback_1_5_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_5(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                   const V1_5::NanConfigRequestSupplemental& msg2,
+                                   enableRequest_1_5_cb hidl_status_cb) override;
+    Return<void> configRequest_1_5(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+                                   const V1_5::NanConfigRequestSupplemental& msg2,
+                                   configRequest_1_5_cb hidl_status_cb) override;
+    Return<void> getCapabilitiesRequest_1_5(uint16_t cmd_id,
+                                            getCapabilitiesRequest_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_6(const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
+                                           registerEventCallback_1_6_cb hidl_status_cb) override;
+    Return<void> initiateDataPathRequest_1_6(
+            uint16_t cmd_id, const V1_6::NanInitiateDataPathRequest& msg,
+            initiateDataPathRequest_1_6_cb hidl_status_cb) override;
+    Return<void> respondToDataPathIndicationRequest_1_6(
+            uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg,
+            respondToDataPathIndicationRequest_1_6_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_6(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                   const V1_6::NanConfigRequestSupplemental& msg2,
+                                   enableRequest_1_6_cb hidl_status_cb) override;
+    Return<void> configRequest_1_6(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+                                   const V1_6::NanConfigRequestSupplemental& msg2,
+                                   configRequest_1_6_cb hidl_status_cb) override;
+    Return<void> startPublishRequest_1_6(uint16_t cmd_id, const V1_6::NanPublishRequest& msg,
+                                         startPublishRequest_cb hidl_status_cb) override;
+
+  private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus registerEventCallbackInternal(const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
+    WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
+    WifiStatus enableRequestInternal(uint16_t cmd_id, const V1_0::NanEnableRequest& msg);
+    WifiStatus configRequestInternal(uint16_t cmd_id, const V1_0::NanConfigRequest& msg);
+    WifiStatus disableRequestInternal(uint16_t cmd_id);
+    WifiStatus startPublishRequestInternal(uint16_t cmd_id, const V1_0::NanPublishRequest& msg);
+    WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+    WifiStatus startSubscribeRequestInternal(uint16_t cmd_id, const V1_0::NanSubscribeRequest& msg);
+    WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+    WifiStatus transmitFollowupRequestInternal(uint16_t cmd_id,
+                                               const NanTransmitFollowupRequest& msg);
+    WifiStatus createDataInterfaceRequestInternal(uint16_t cmd_id, const std::string& iface_name);
+    WifiStatus deleteDataInterfaceRequestInternal(uint16_t cmd_id, const std::string& iface_name);
+    WifiStatus initiateDataPathRequestInternal(uint16_t cmd_id,
+                                               const V1_0::NanInitiateDataPathRequest& msg);
+    WifiStatus respondToDataPathIndicationRequestInternal(
+            uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg);
+    WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id, uint32_t ndpInstanceId);
+
+    WifiStatus registerEventCallback_1_2Internal(
+            const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
+    WifiStatus enableRequest_1_2Internal(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+                                         const V1_2::NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_2Internal(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+                                         const V1_2::NanConfigRequestSupplemental& msg2);
+    WifiStatus enableRequest_1_4Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                         const V1_2::NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_4Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
+                                         const V1_2::NanConfigRequestSupplemental& msg2);
+    WifiStatus registerEventCallback_1_5Internal(
+            const sp<V1_5::IWifiNanIfaceEventCallback>& callback);
+    WifiStatus enableRequest_1_5Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                         const V1_5::NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_5Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
+                                         const V1_5::NanConfigRequestSupplemental& msg2);
+    WifiStatus getCapabilitiesRequest_1_5Internal(uint16_t cmd_id);
+    WifiStatus registerEventCallback_1_6Internal(
+            const sp<V1_6::IWifiNanIfaceEventCallback>& callback);
+
+    WifiStatus enableRequest_1_6Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+                                         const V1_6::NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_6Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
+                                         const V1_6::NanConfigRequestSupplemental& msg2);
+    WifiStatus startPublishRequest_1_6Internal(uint16_t cmd_id, const V1_6::NanPublishRequest& msg);
+    WifiStatus initiateDataPathRequest_1_6Internal(uint16_t cmd_id,
+                                                   const V1_6::NanInitiateDataPathRequest& msg);
+    WifiStatus respondToDataPathIndicationRequest_1_6Internal(
+            uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg);
+
+    // all 1_0 and descendant callbacks
+    std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
+    // all 1_2 and descendant callbacks
+    std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
+    // all 1_5 and descendant callbacks
+    std::set<sp<V1_5::IWifiNanIfaceEventCallback>> getEventCallbacks_1_5();
+    // all 1_6 and descendant callbacks
+    std::set<sp<V1_6::IWifiNanIfaceEventCallback>> getEventCallbacks_1_6();
+
+    std::string ifname_;
+    bool is_dedicated_iface_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+    hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback> event_cb_handler_;
+    hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback> event_cb_handler_1_2_;
+    hidl_callback_util::HidlCallbackHandler<V1_5::IWifiNanIfaceEventCallback> event_cb_handler_1_5_;
+    hidl_callback_util::HidlCallbackHandler<V1_6::IWifiNanIfaceEventCallback> event_cb_handler_1_6_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.6/default/wifi_p2p_iface.cpp b/wifi/1.6/default/wifi_p2p_iface.cpp
new file mode 100644
index 0000000..d4b1fca
--- /dev/null
+++ b/wifi/1.6/default/wifi_p2p_iface.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiP2pIface::WifiP2pIface(const std::string& ifname,
+                           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiP2pIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiP2pIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiP2pIface::getName() {
+    return ifname_;
+}
+
+Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiP2pIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiP2pIface::getTypeInternal, hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
+}
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_p2p_iface.h b/wifi/1.6/default/wifi_p2p_iface.h
new file mode 100644
index 0000000..0089443
--- /dev/null
+++ b/wifi/1.6/default/wifi_p2p_iface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_P2P_IFACE_H_
+#define WIFI_P2P_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a P2P Iface instance.
+ */
+class WifiP2pIface : public V1_0::IWifiP2pIface {
+  public:
+    WifiP2pIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+
+  private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.6/default/wifi_rtt_controller.cpp b/wifi/1.6/default/wifi_rtt_controller.cpp
new file mode 100644
index 0000000..b328f31
--- /dev/null
+++ b/wifi/1.6/default/wifi_rtt_controller.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiRttController::WifiRttController(const std::string& iface_name,
+                                     const sp<IWifiIface>& bound_iface,
+                                     const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(iface_name), bound_iface_(bound_iface), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiRttController::invalidate() {
+    legacy_hal_.reset();
+    event_callbacks_.clear();
+    is_valid_ = false;
+}
+
+bool WifiRttController::isValid() {
+    return is_valid_;
+}
+
+std::vector<sp<V1_6::IWifiRttControllerEventCallback>> WifiRttController::getEventCallbacks() {
+    return event_callbacks_;
+}
+
+std::string WifiRttController::getIfaceName() {
+    return ifname_;
+}
+
+Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::registerEventCallback(
+        const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::registerEventCallbackInternal, hidl_status_cb,
+                           callback);
+}
+
+Return<void> WifiRttController::rangeRequest(uint32_t cmd_id,
+                                             const hidl_vec<V1_0::RttConfig>& rtt_configs,
+                                             rangeRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeRequestInternal, hidl_status_cb, cmd_id,
+                           rtt_configs);
+}
+
+Return<void> WifiRttController::rangeCancel(uint32_t cmd_id,
+                                            const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+                                            rangeCancel_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
+}
+
+Return<void> WifiRttController::getCapabilities(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::setLci(uint32_t cmd_id, const RttLciInformation& lci,
+                                       setLci_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
+}
+
+Return<void> WifiRttController::setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
+                                       setLcr_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
+}
+
+Return<void> WifiRttController::getResponderInfo(getResponderInfo_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getResponderInfoInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder(uint32_t cmd_id,
+                                                const V1_0::WifiChannelInfo& channel_hint,
+                                                uint32_t max_duration_seconds,
+                                                const V1_0::RttResponder& info,
+                                                enableResponder_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
+                           channel_hint, max_duration_seconds, info);
+}
+
+Return<void> WifiRttController::disableResponder(uint32_t cmd_id,
+                                                 disableResponder_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiRttController::registerEventCallback_1_4(
+        const sp<V1_4::IWifiRttControllerEventCallback>& callback,
+        registerEventCallback_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb,
+                           callback);
+}
+
+Return<void> WifiRttController::rangeRequest_1_4(uint32_t cmd_id,
+                                                 const hidl_vec<V1_4::RttConfig>& rtt_configs,
+                                                 rangeRequest_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeRequestInternal_1_4, hidl_status_cb, cmd_id,
+                           rtt_configs);
+}
+
+Return<void> WifiRttController::getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder_1_4(uint32_t cmd_id,
+                                                    const V1_0::WifiChannelInfo& channel_hint,
+                                                    uint32_t max_duration_seconds,
+                                                    const V1_4::RttResponder& info,
+                                                    enableResponder_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id,
+                           channel_hint, max_duration_seconds, info);
+}
+
+Return<void> WifiRttController::registerEventCallback_1_6(
+        const sp<V1_6::IWifiRttControllerEventCallback>& callback,
+        registerEventCallback_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::registerEventCallbackInternal_1_6, hidl_status_cb,
+                           callback);
+}
+
+Return<void> WifiRttController::rangeRequest_1_6(uint32_t cmd_id,
+                                                 const hidl_vec<V1_6::RttConfig>& rtt_configs,
+                                                 rangeRequest_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeRequestInternal_1_6, hidl_status_cb, cmd_id,
+                           rtt_configs);
+}
+
+Return<void> WifiRttController::getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getCapabilitiesInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiRttController::getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getResponderInfoInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder_1_6(uint32_t cmd_id,
+                                                    const V1_6::WifiChannelInfo& channel_hint,
+                                                    uint32_t max_duration_seconds,
+                                                    const V1_6::RttResponder& info,
+                                                    enableResponder_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::enableResponderInternal_1_6, hidl_status_cb, cmd_id,
+                           channel_hint, max_duration_seconds, info);
+}
+
+std::pair<WifiStatus, sp<IWifiIface>> WifiRttController::getBoundIfaceInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal(
+        const sp<V1_0::IWifiRttControllerEventCallback>& /* callback */) {
+    // Deprecated support for this api
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal(
+        uint32_t /* cmd_id */, const std::vector<V1_0::RttConfig>& /* rtt_configs */) {
+    // Deprecated support for this api
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeCancelInternal(
+        uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
+    std::vector<std::array<uint8_t, 6>> legacy_addrs;
+    for (const auto& addr : addrs) {
+        legacy_addrs.push_back(addr);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id, legacy_addrs);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttCapabilities> WifiRttController::getCapabilitiesInternal() {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id, const RttLciInformation& lci) {
+    legacy_hal::wifi_lci_information legacy_lci;
+    if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci, &legacy_lci)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr) {
+    legacy_hal::wifi_lcr_information legacy_lcr;
+    if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr, &legacy_lcr)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttResponder> WifiRttController::getResponderInfoInternal() {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::enableResponderInternal(
+        uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
+        uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
+}
+
+WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
+        const sp<V1_4::IWifiRttControllerEventCallback>& /* callback */) {
+    // Deprecated support for this api
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal_1_4(
+        uint32_t /* cmd_id */, const std::vector<V1_4::RttConfig>& /* rtt_configs */) {
+    // Deprecated support for this api
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, V1_4::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_4() {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_4::RttResponder> WifiRttController::getResponderInfoInternal_1_4() {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::enableResponderInternal_1_4(
+        uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
+        uint32_t /* max_duration_seconds */, const V1_4::RttResponder& /* info */) {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal_1_6(
+        const sp<V1_6::IWifiRttControllerEventCallback>& callback) {
+    // TODO(b/31632518): remove the callback when the client is destroyed
+    event_callbacks_.emplace_back(callback);
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal_1_6(
+        uint32_t cmd_id, const std::vector<V1_6::RttConfig>& rtt_configs) {
+    std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
+    if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    android::wp<WifiRttController> weak_ptr_this(this);
+    const auto& on_results_callback =
+            [weak_ptr_this](legacy_hal::wifi_request_id id,
+                            const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<V1_6::RttResult> hidl_results;
+                if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(results,
+                                                                            &hidl_results)) {
+                    LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    callback->onResults_1_6(id, hidl_results);
+                }
+            };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
+            ifname_, cmd_id, legacy_configs, on_results_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_6::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_6() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    V1_6::RttCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, V1_6::RttResponder> WifiRttController::getResponderInfoInternal_1_6() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    std::tie(legacy_status, legacy_responder) = legacy_hal_.lock()->getRttResponderInfo(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    V1_6::RttResponder hidl_responder;
+    if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder, &hidl_responder)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
+}
+
+WifiStatus WifiRttController::enableResponderInternal_1_6(uint32_t cmd_id,
+                                                          const V1_6::WifiChannelInfo& channel_hint,
+                                                          uint32_t max_duration_seconds,
+                                                          const V1_6::RttResponder& info) {
+    legacy_hal::wifi_channel_info legacy_channel_info;
+    if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    if (!hidl_struct_util::convertHidlRttResponderToLegacy(info, &legacy_responder)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder(
+            ifname_, cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_rtt_controller.h b/wifi/1.6/default/wifi_rtt_controller.h
new file mode 100644
index 0000000..fd5f68b
--- /dev/null
+++ b/wifi/1.6/default/wifi_rtt_controller.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_RTT_CONTROLLER_H_
+#define WIFI_RTT_CONTROLLER_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiIface.h>
+#include <android/hardware/wifi/1.6/IWifiRttController.h>
+#include <android/hardware/wifi/1.6/IWifiRttControllerEventCallback.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+/**
+ * HIDL interface object used to control all RTT operations.
+ */
+class WifiRttController : public V1_6::IWifiRttController {
+  public:
+    WifiRttController(const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+                      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::vector<sp<V1_6::IWifiRttControllerEventCallback>> getEventCallbacks();
+    std::string getIfaceName();
+
+    // HIDL methods exposed.
+    Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+                                       registerEventCallback_cb hidl_status_cb) override;
+    Return<void> rangeRequest(uint32_t cmd_id, const hidl_vec<V1_0::RttConfig>& rtt_configs,
+                              rangeRequest_cb hidl_status_cb) override;
+    Return<void> rangeCancel(uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+                             rangeCancel_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
+                        setLci_cb hidl_status_cb) override;
+    Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
+                        setLcr_cb hidl_status_cb) override;
+    Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
+    Return<void> enableResponder(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
+                                 uint32_t max_duration_seconds, const V1_0::RttResponder& info,
+                                 enableResponder_cb hidl_status_cb) override;
+    Return<void> disableResponder(uint32_t cmd_id, disableResponder_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_4(
+            const sp<V1_4::IWifiRttControllerEventCallback>& callback,
+            registerEventCallback_1_4_cb hidl_status_cb) override;
+    Return<void> rangeRequest_1_4(uint32_t cmd_id, const hidl_vec<V1_4::RttConfig>& rtt_configs,
+                                  rangeRequest_1_4_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) override;
+    Return<void> getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) override;
+    Return<void> enableResponder_1_4(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
+                                     uint32_t max_duration_seconds, const V1_4::RttResponder& info,
+                                     enableResponder_1_4_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_6(
+            const sp<V1_6::IWifiRttControllerEventCallback>& callback,
+            registerEventCallback_1_6_cb hidl_status_cb) override;
+    Return<void> rangeRequest_1_6(uint32_t cmd_id, const hidl_vec<V1_6::RttConfig>& rtt_configs,
+                                  rangeRequest_1_6_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) override;
+    Return<void> getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) override;
+    Return<void> enableResponder_1_6(uint32_t cmd_id, const V1_6::WifiChannelInfo& channel_hint,
+                                     uint32_t max_duration_seconds, const V1_6::RttResponder& info,
+                                     enableResponder_1_6_cb hidl_status_cb) override;
+
+  private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
+    WifiStatus registerEventCallbackInternal(
+            const sp<V1_0::IWifiRttControllerEventCallback>& callback);
+    WifiStatus rangeRequestInternal(uint32_t cmd_id,
+                                    const std::vector<V1_0::RttConfig>& rtt_configs);
+    WifiStatus rangeCancelInternal(uint32_t cmd_id,
+                                   const std::vector<hidl_array<uint8_t, 6>>& addrs);
+    std::pair<WifiStatus, V1_0::RttCapabilities> getCapabilitiesInternal();
+    WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
+    WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
+    std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
+    WifiStatus enableResponderInternal(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
+                                       uint32_t max_duration_seconds,
+                                       const V1_0::RttResponder& info);
+    WifiStatus disableResponderInternal(uint32_t cmd_id);
+    WifiStatus registerEventCallbackInternal_1_4(
+            const sp<V1_4::IWifiRttControllerEventCallback>& callback);
+    WifiStatus rangeRequestInternal_1_4(uint32_t cmd_id,
+                                        const std::vector<V1_4::RttConfig>& rtt_configs);
+    std::pair<WifiStatus, V1_4::RttCapabilities> getCapabilitiesInternal_1_4();
+    std::pair<WifiStatus, V1_4::RttResponder> getResponderInfoInternal_1_4();
+    WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
+                                           const V1_0::WifiChannelInfo& channel_hint,
+                                           uint32_t max_duration_seconds,
+                                           const V1_4::RttResponder& info);
+    WifiStatus registerEventCallbackInternal_1_6(
+            const sp<V1_6::IWifiRttControllerEventCallback>& callback);
+    WifiStatus rangeRequestInternal_1_6(uint32_t cmd_id,
+                                        const std::vector<V1_6::RttConfig>& rtt_configs);
+    std::pair<WifiStatus, V1_6::RttCapabilities> getCapabilitiesInternal_1_6();
+    std::pair<WifiStatus, V1_6::RttResponder> getResponderInfoInternal_1_6();
+    WifiStatus enableResponderInternal_1_6(uint32_t cmd_id,
+                                           const V1_6::WifiChannelInfo& channel_hint,
+                                           uint32_t max_duration_seconds,
+                                           const V1_6::RttResponder& info);
+
+    std::string ifname_;
+    sp<IWifiIface> bound_iface_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::vector<sp<V1_6::IWifiRttControllerEventCallback>> event_callbacks_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiRttController);
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.6/default/wifi_sta_iface.cpp b/wifi/1.6/default/wifi_sta_iface.cpp
new file mode 100644
index 0000000..dd11839
--- /dev/null
+++ b/wifi/1.6/default/wifi_sta_iface.cpp
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2016 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 <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_sta_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiStaIface::WifiStaIface(const std::string& ifname,
+                           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                           const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname), legacy_hal_(legacy_hal), iface_util_(iface_util), is_valid_(true) {
+    // Turn on DFS channel usage for STA iface.
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDfsFlag(ifname_, true);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to set DFS flag; DFS channels may be unavailable.";
+    }
+}
+
+void WifiStaIface::invalidate() {
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+bool WifiStaIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiStaIface::getName() {
+    return ifname_;
+}
+
+std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::registerEventCallback(const sp<IWifiStaIfaceEventCallback>& callback,
+                                                 registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::registerEventCallbackInternal, hidl_status_cb, callback);
+}
+
+Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getApfPacketFilterCapabilities(
+        getApfPacketFilterCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::installApfPacketFilter(uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+                                                  installApfPacketFilter_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::installApfPacketFilterInternal, hidl_status_cb, cmd_id,
+                           program);
+}
+
+Return<void> WifiStaIface::readApfPacketFilterData(readApfPacketFilterData_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::readApfPacketFilterDataInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getBackgroundScanCapabilities(
+        getBackgroundScanCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getBackgroundScanCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getValidFrequenciesForBand(
+        V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getValidFrequenciesForBandInternal, hidl_status_cb, band);
+}
+
+Return<void> WifiStaIface::startBackgroundScan(uint32_t cmd_id,
+                                               const StaBackgroundScanParameters& params,
+                                               startBackgroundScan_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startBackgroundScanInternal, hidl_status_cb, cmd_id,
+                           params);
+}
+
+Return<void> WifiStaIface::stopBackgroundScan(uint32_t cmd_id,
+                                              stopBackgroundScan_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopBackgroundScanInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::enableLinkLayerStatsCollection(
+        bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
+                           debug);
+}
+
+Return<void> WifiStaIface::disableLinkLayerStatsCollection(
+        disableLinkLayerStatsCollection_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_3(getLinkLayerStats_1_3_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal_1_3, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_5(getLinkLayerStats_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal_1_5, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+                                               startRssiMonitoring_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startRssiMonitoringInternal, hidl_status_cb, cmd_id,
+                           max_rssi, min_rssi);
+}
+
+Return<void> WifiStaIface::stopRssiMonitoring(uint32_t cmd_id,
+                                              stopRssiMonitoring_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopRssiMonitoringInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::getRoamingCapabilities(getRoamingCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getRoamingCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::configureRoaming(const StaRoamingConfig& config,
+                                            configureRoaming_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::configureRoamingInternal, hidl_status_cb, config);
+}
+
+Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
+                                           setRoamingState_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setRoamingStateInternal, hidl_status_cb, state);
+}
+
+Return<void> WifiStaIface::enableNdOffload(bool enable, enableNdOffload_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::enableNdOffloadInternal, hidl_status_cb, enable);
+}
+
+Return<void> WifiStaIface::startSendingKeepAlivePackets(
+        uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data, uint16_t ether_type,
+        const hidl_array<uint8_t, 6>& src_address, const hidl_array<uint8_t, 6>& dst_address,
+        uint32_t period_in_ms, startSendingKeepAlivePackets_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startSendingKeepAlivePacketsInternal, hidl_status_cb,
+                           cmd_id, ip_packet_data, ether_type, src_address, dst_address,
+                           period_in_ms);
+}
+
+Return<void> WifiStaIface::stopSendingKeepAlivePackets(
+        uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopSendingKeepAlivePacketsInternal, hidl_status_cb,
+                           cmd_id);
+}
+
+Return<void> WifiStaIface::setScanningMacOui(const hidl_array<uint8_t, 3>& oui,
+                                             setScanningMacOui_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setScanningMacOuiInternal, hidl_status_cb, oui);
+}
+
+Return<void> WifiStaIface::startDebugPacketFateMonitoring(
+        startDebugPacketFateMonitoring_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugTxPacketFates(getDebugTxPacketFates_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugTxPacketFatesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugRxPacketFates(getDebugRxPacketFates_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugRxPacketFatesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                                         setMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setMacAddressInternal, hidl_status_cb, mac);
+}
+
+Return<void> WifiStaIface::getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getFactoryMacAddressInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::setScanMode(bool enable, setScanMode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setScanModeInternal, hidl_status_cb, enable);
+}
+
+std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
+}
+
+WifiStatus WifiStaIface::registerEventCallbackInternal(
+        const sp<IWifiStaIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+            legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), 0};
+    }
+    uint32_t legacy_logger_feature_set;
+    std::tie(legacy_status, legacy_logger_feature_set) =
+            legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t hidl_caps;
+    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
+                legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, StaApfPacketFilterCapabilities>
+WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::PacketFilterCapabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaApfPacketFilterCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::installApfPacketFilterInternal(uint32_t /* cmd_id */,
+                                                        const std::vector<uint8_t>& program) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setPacketFilter(ifname_, program);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>> WifiStaIface::readApfPacketFilterDataInternal() {
+    const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>> legacy_status_and_data =
+            legacy_hal_.lock()->readApfPacketFilterData(ifname_);
+    return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
+            std::move(legacy_status_and_data.second)};
+}
+
+std::pair<WifiStatus, StaBackgroundScanCapabilities>
+WifiStaIface::getBackgroundScanCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_gscan_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getGscanCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaBackgroundScanCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
+            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiStaIface::startBackgroundScanInternal(uint32_t cmd_id,
+                                                     const StaBackgroundScanParameters& params) {
+    legacy_hal::wifi_scan_cmd_params legacy_params;
+    if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params, &legacy_params)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    android::wp<WifiStaIface> weak_ptr_this(this);
+    const auto& on_failure_callback = [weak_ptr_this](legacy_hal::wifi_request_id id) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onBackgroundScanFailure(id).isOk()) {
+                LOG(ERROR) << "Failed to invoke onBackgroundScanFailure callback";
+            }
+        }
+    };
+    const auto& on_results_callback =
+            [weak_ptr_this](legacy_hal::wifi_request_id id,
+                            const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
+                const auto shared_ptr_this = weak_ptr_this.promote();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<StaScanData> hidl_scan_datas;
+                if (!hidl_struct_util::convertLegacyVectorOfCachedGscanResultsToHidl(
+                            results, &hidl_scan_datas)) {
+                    LOG(ERROR) << "Failed to convert scan results to HIDL structs";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onBackgroundScanResults(id, hidl_scan_datas).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onBackgroundScanResults callback";
+                    }
+                }
+            };
+    const auto& on_full_result_callback = [weak_ptr_this](
+                                                  legacy_hal::wifi_request_id id,
+                                                  const legacy_hal::wifi_scan_result* result,
+                                                  uint32_t buckets_scanned) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        StaScanResult hidl_scan_result;
+        if (!hidl_struct_util::convertLegacyGscanResultToHidl(*result, true, &hidl_scan_result)) {
+            LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onBackgroundFullScanResult(id, buckets_scanned, hidl_scan_result)
+                         .isOk()) {
+                LOG(ERROR) << "Failed to invoke onBackgroundFullScanResult callback";
+            }
+        }
+    };
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->startGscan(ifname_, cmd_id, legacy_params, on_failure_callback,
+                                           on_results_callback, on_full_result_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableLinkLayerStats(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal() {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_3::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_3() {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_5::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_5() {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_6::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_6() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::LinkLayerStats legacy_stats;
+    std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    V1_6::StaLinkLayerStats hidl_stats;
+    if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &hidl_stats)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
+                                                     int32_t min_rssi) {
+    android::wp<WifiStaIface> weak_ptr_this(this);
+    const auto& on_threshold_breached_callback = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                                 std::array<uint8_t, 6> bssid,
+                                                                 int8_t rssi) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onRssiThresholdBreached(id, bssid, rssi).isOk()) {
+                LOG(ERROR) << "Failed to invoke onRssiThresholdBreached callback";
+            }
+        }
+    };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRssiMonitoring(
+            ifname_, cmd_id, max_rssi, min_rssi, on_threshold_breached_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, StaRoamingCapabilities> WifiStaIface::getRoamingCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_roaming_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRoamingCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaRoamingCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::configureRoamingInternal(const StaRoamingConfig& config) {
+    legacy_hal::wifi_roaming_config legacy_config;
+    if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config, &legacy_config)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableFirmwareRoaming(
+            ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->configureNdOffload(ifname_, enable);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
+        uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data, uint16_t ether_type,
+        const std::array<uint8_t, 6>& src_address, const std::array<uint8_t, 6>& dst_address,
+        uint32_t period_in_ms) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startSendingOffloadedPacket(
+            ifname_, cmd_id, ether_type, ip_packet_data, src_address, dst_address, period_in_ms);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setScanningMacOuiInternal(const std::array<uint8_t, 3>& /* oui */) {
+    // deprecated.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startPktFateMonitoring(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+WifiStaIface::getDebugTxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_tx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getTxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugTxPacketFateReport> hidl_fates;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(legacy_fates,
+                                                                        &hidl_fates)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+WifiStaIface::getDebugRxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_rx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getRxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugRxPacketFateReport> hidl_fates;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(legacy_fates,
+                                                                        &hidl_fates)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+WifiStatus WifiStaIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
+    bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+    if (!status) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>> WifiStaIface::getFactoryMacAddressInternal() {
+    std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifname_);
+    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+
+WifiStatus WifiStaIface::setScanModeInternal(bool enable) {
+    // OEM's need to implement this on their devices if needed.
+    LOG(WARNING) << "setScanModeInternal(" << enable << ") not supported";
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_sta_iface.h b/wifi/1.6/default/wifi_sta_iface.h
new file mode 100644
index 0000000..c01c50b
--- /dev/null
+++ b/wifi/1.6/default/wifi_sta_iface.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STA_IFACE_H_
+#define WIFI_STA_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a STA Iface instance.
+ */
+class WifiStaIface : public V1_6::IWifiStaIface {
+  public:
+    WifiStaIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(const sp<IWifiStaIfaceEventCallback>& callback,
+                                       registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> getApfPacketFilterCapabilities(
+            getApfPacketFilterCapabilities_cb hidl_status_cb) override;
+    Return<void> installApfPacketFilter(uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+                                        installApfPacketFilter_cb hidl_status_cb) override;
+    Return<void> readApfPacketFilterData(readApfPacketFilterData_cb hidl_status_cb) override;
+    Return<void> getBackgroundScanCapabilities(
+            getBackgroundScanCapabilities_cb hidl_status_cb) override;
+    Return<void> getValidFrequenciesForBand(V1_0::WifiBand band,
+                                            getValidFrequenciesForBand_cb hidl_status_cb) override;
+    Return<void> startBackgroundScan(uint32_t cmd_id, const StaBackgroundScanParameters& params,
+                                     startBackgroundScan_cb hidl_status_cb) override;
+    Return<void> stopBackgroundScan(uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
+    Return<void> enableLinkLayerStatsCollection(
+            bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
+    Return<void> disableLinkLayerStatsCollection(
+            disableLinkLayerStatsCollection_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats_1_3(getLinkLayerStats_1_3_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats_1_5(getLinkLayerStats_1_5_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) override;
+    Return<void> startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+                                     startRssiMonitoring_cb hidl_status_cb) override;
+    Return<void> stopRssiMonitoring(uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
+    Return<void> getRoamingCapabilities(getRoamingCapabilities_cb hidl_status_cb) override;
+    Return<void> configureRoaming(const StaRoamingConfig& config,
+                                  configureRoaming_cb hidl_status_cb) override;
+    Return<void> setRoamingState(StaRoamingState state, setRoamingState_cb hidl_status_cb) override;
+    Return<void> enableNdOffload(bool enable, enableNdOffload_cb hidl_status_cb) override;
+    Return<void> startSendingKeepAlivePackets(
+            uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data, uint16_t ether_type,
+            const hidl_array<uint8_t, 6>& src_address, const hidl_array<uint8_t, 6>& dst_address,
+            uint32_t period_in_ms, startSendingKeepAlivePackets_cb hidl_status_cb) override;
+    Return<void> stopSendingKeepAlivePackets(
+            uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) override;
+    Return<void> setScanningMacOui(const hidl_array<uint8_t, 3>& oui,
+                                   setScanningMacOui_cb hidl_status_cb) override;
+    Return<void> startDebugPacketFateMonitoring(
+            startDebugPacketFateMonitoring_cb hidl_status_cb) override;
+    Return<void> getDebugTxPacketFates(getDebugTxPacketFates_cb hidl_status_cb) override;
+    Return<void> getDebugRxPacketFates(getDebugRxPacketFates_cb hidl_status_cb) override;
+    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                               setMacAddress_cb hidl_status_cb) override;
+    Return<void> getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) override;
+    Return<void> setScanMode(bool enable, setScanMode_cb hidl_status_cb) override;
+
+  private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus registerEventCallbackInternal(const sp<IWifiStaIfaceEventCallback>& callback);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+    std::pair<WifiStatus, StaApfPacketFilterCapabilities> getApfPacketFilterCapabilitiesInternal();
+    WifiStatus installApfPacketFilterInternal(uint32_t cmd_id, const std::vector<uint8_t>& program);
+    std::pair<WifiStatus, std::vector<uint8_t>> readApfPacketFilterDataInternal();
+    std::pair<WifiStatus, StaBackgroundScanCapabilities> getBackgroundScanCapabilitiesInternal();
+    std::pair<WifiStatus, std::vector<WifiChannelInMhz>> getValidFrequenciesForBandInternal(
+            V1_0::WifiBand band);
+    WifiStatus startBackgroundScanInternal(uint32_t cmd_id,
+                                           const StaBackgroundScanParameters& params);
+    WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
+    WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
+    WifiStatus disableLinkLayerStatsCollectionInternal();
+    std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
+    std::pair<WifiStatus, V1_3::StaLinkLayerStats> getLinkLayerStatsInternal_1_3();
+    std::pair<WifiStatus, V1_5::StaLinkLayerStats> getLinkLayerStatsInternal_1_5();
+    std::pair<WifiStatus, V1_6::StaLinkLayerStats> getLinkLayerStatsInternal_1_6();
+    WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi);
+    WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
+    std::pair<WifiStatus, StaRoamingCapabilities> getRoamingCapabilitiesInternal();
+    WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
+    WifiStatus setRoamingStateInternal(StaRoamingState state);
+    WifiStatus enableNdOffloadInternal(bool enable);
+    WifiStatus startSendingKeepAlivePacketsInternal(uint32_t cmd_id,
+                                                    const std::vector<uint8_t>& ip_packet_data,
+                                                    uint16_t ether_type,
+                                                    const std::array<uint8_t, 6>& src_address,
+                                                    const std::array<uint8_t, 6>& dst_address,
+                                                    uint32_t period_in_ms);
+    WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
+    WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
+    WifiStatus startDebugPacketFateMonitoringInternal();
+    std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>> getDebugTxPacketFatesInternal();
+    std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>> getDebugRxPacketFatesInternal();
+    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+    std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal();
+    WifiStatus setScanModeInternal(bool enable);
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+    hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback> event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/1.6/default/wifi_status_util.cpp b/wifi/1.6/default/wifi_status_util.cpp
new file mode 100644
index 0000000..3b18e53
--- /dev/null
+++ b/wifi/1.6/default/wifi_status_util.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 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 "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+std::string legacyErrorToString(legacy_hal::wifi_error error) {
+    switch (error) {
+        case legacy_hal::WIFI_SUCCESS:
+            return "SUCCESS";
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+            return "UNINITIALIZED";
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return "NOT_AVAILABLE";
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return "NOT_SUPPORTED";
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+            return "INVALID_ARGS";
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return "INVALID_REQUEST_ID";
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return "TIMED_OUT";
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return "TOO_MANY_REQUESTS";
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return "OUT_OF_MEMORY";
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return "BUSY";
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return "UNKNOWN";
+        default:
+            return "UNKNOWN ERROR";
+    }
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code, const std::string& description) {
+    return {code, description};
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code) {
+    return createWifiStatus(code, "");
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, const std::string& desc) {
+    switch (error) {
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
+
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
+
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
+
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", timed out");
+
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", too many requests");
+
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", out of memory");
+
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return createWifiStatus(WifiStatusCode::ERROR_BUSY);
+
+        case legacy_hal::WIFI_ERROR_NONE:
+            return createWifiStatus(WifiStatusCode::SUCCESS, desc);
+
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+
+        default:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown error");
+    }
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
+    return createWifiStatusFromLegacyError(error, "");
+}
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.6/default/wifi_status_util.h b/wifi/1.6/default/wifi_status_util.h
new file mode 100644
index 0000000..ea1c294
--- /dev/null
+++ b/wifi/1.6/default/wifi_status_util.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STATUS_UTIL_H_
+#define WIFI_STATUS_UTIL_H_
+
+#include <android/hardware/wifi/1.4/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+std::string legacyErrorToString(legacy_hal::wifi_error error);
+WifiStatus createWifiStatus(WifiStatusCode code, const std::string& description);
+WifiStatus createWifiStatus(WifiStatusCode code);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+                                           const std::string& description);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
+
+}  // namespace implementation
+}  // namespace V1_6
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.6/types.hal b/wifi/1.6/types.hal
new file mode 100644
index 0000000..ef6965d
--- /dev/null
+++ b/wifi/1.6/types.hal
@@ -0,0 +1,1264 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi@1.6;
+
+import @1.0::MacAddress;
+import @1.0::NanCipherSuiteType;
+import @1.0::NanDataPathChannelCfg;
+import @1.0::NanDataPathConfirmInd;
+import @1.0::NanDataPathSecurityConfig;
+import @1.0::NanDataPathSecurityType;
+import @1.0::NanDiscoveryCommonConfig;
+import @1.0::NanInitiateDataPathRequest;
+import @1.0::NanMatchAlg;
+import @1.0::NanRangingIndication;
+import @1.0::NanRespondToDataPathIndicationRequest;
+import @1.0::NanPublishType;
+import @1.0::NanTxType;
+import @1.0::Rssi;
+import @1.0::RttBw;
+import @1.0::RttPeerType;
+import @1.0::RttStatus;
+import @1.0::RttType;
+import @1.0::StaLinkLayerIfaceStats;
+import @1.0::StaLinkLayerRadioStats;
+import @1.0::TimeSpanInPs;
+import @1.0::TimeStampInUs;
+import @1.0::TimeStampInMs;
+import @1.0::WifiChannelInMhz;
+import @1.0::WifiChannelWidthInMhz;
+import @1.0::WifiInformationElement;
+import @1.0::WifiRateNss;
+import @1.4::RttPreamble;
+import @1.4::WifiRatePreamble;
+import @1.5::NanConfigRequestSupplemental;
+import @1.5::StaLinkLayerIfaceContentionTimeStats;
+import @1.5::WifiIfaceMode;
+
+/**
+ * Channel operating width in Mhz.
+ */
+enum WifiChannelWidthInMhz : @1.0::WifiChannelWidthInMhz {
+    /**
+     * 320 MHz
+     */
+    WIDTH_320 = 7,
+};
+
+/**
+ * RTT Measurement Bandwidth.
+ */
+enum RttBw : @1.0::RttBw {
+    BW_320MHZ = 0x40,
+};
+
+/**
+ * RTT Measurement Preamble.
+ */
+enum RttPreamble : @1.4::RttPreamble {
+    /**
+     * Preamble type for 11be
+     */
+    EHT = 0x10,
+};
+
+/**
+ * Wifi Rate Preamble
+ */
+enum WifiRatePreamble : @1.4::WifiRatePreamble {
+    /**
+     * Preamble type for 11be
+     */
+    EHT = 6,
+};
+
+/**
+ * Channel information.
+ */
+struct WifiChannelInfo {
+    /**
+     * Channel width (20, 40, 80, 80+80, 160, 320).
+     */
+    WifiChannelWidthInMhz width;
+
+    /**
+     * Primary 20 MHz channel.
+     */
+    WifiChannelInMhz centerFreq;
+
+    /**
+     * Center frequency (MHz) first segment.
+     */
+    WifiChannelInMhz centerFreq0;
+
+    /**
+     * Center frequency (MHz) second segment.
+     */
+    WifiChannelInMhz centerFreq1;
+};
+
+/**
+ * RTT configuration.
+ */
+struct RttConfig {
+    /**
+     * Peer device mac address.
+     */
+    MacAddress addr;
+
+    /**
+     * 1-sided or 2-sided RTT.
+     */
+    RttType type;
+
+    /**
+     * Optional - peer device hint (STA, P2P, AP).
+     */
+    RttPeerType peer;
+
+    /**
+     * Required for STA-AP mode, optional for P2P, NBD etc.
+     */
+    WifiChannelInfo channel;
+
+    /**
+     * Time interval between bursts (units: 100 ms).
+     * Applies to 1-sided and 2-sided RTT multi-burst requests.
+     * Range: 0-31, 0: no preference by initiator (2-sided RTT).
+     */
+    uint32_t burstPeriod;
+
+    /**
+     * Total number of RTT bursts to be executed. It will be
+     * specified in the same way as the parameter "Number of
+     * Burst Exponent" found in the FTM frame format. It
+     * applies to both: 1-sided RTT and 2-sided RTT. Valid
+     * values are 0 to 15 as defined in 802.11mc std.
+     * 0 means single shot
+     * The implication of this parameter on the maximum
+     * number of RTT results is the following:
+     * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
+     * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+     */
+    uint32_t numBurst;
+
+    /**
+     * Num of frames per burst.
+     * Minimum value = 1, Maximum value = 31
+     * For 2-sided this equals the number of FTM frames
+     * to be attempted in a single burst. This also
+     * equals the number of FTM frames that the
+     * initiator will request that the responder send
+     * in a single frame.
+     */
+    uint32_t numFramesPerBurst;
+
+    /**
+     * Number of retries for a failed RTT frame.
+     * Applies to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+     */
+    uint32_t numRetriesPerRttFrame;
+
+    /**
+     * Following fields are only valid for 2-side RTT.
+     *
+     *
+     * Maximum number of retries that the initiator can
+     * retry an FTMR frame.
+     * Minimum value = 0, Maximum value = 3
+     */
+    uint32_t numRetriesPerFtmr;
+
+    /**
+     * Whether to request location civic info or not.
+     */
+    bool mustRequestLci;
+
+    /**
+     * Whether to request location civic records or not.
+     */
+    bool mustRequestLcr;
+
+    /**
+     * Applies to 1-sided and 2-sided RTT. Valid values will
+     * be 2-11 and 15 as specified by the 802.11mc std for
+     * the FTM parameter burst duration. In a multi-burst
+     * request, if responder overrides with larger value,
+     * the initiator will return failure. In a single-burst
+     * request if responder overrides with larger value,
+     * the initiator will sent TMR_STOP to terminate RTT
+     * at the end of the burst_duration it requested.
+     */
+    uint32_t burstDuration;
+
+    /**
+     * RTT preamble to be used in the RTT frames.
+     */
+    RttPreamble preamble;
+
+    /**
+     * RTT BW to be used in the RTT frames.
+     */
+    RttBw bw;
+};
+
+/**
+ * RTT Responder information
+ */
+struct RttResponder {
+    WifiChannelInfo channel;
+
+    RttPreamble preamble;
+};
+
+struct WifiChannelStats {
+    /**
+     * Channel information.
+     */
+    WifiChannelInfo channel;
+
+    /**
+     * Total time for which the radio is awake on this channel.
+     */
+    uint32_t onTimeInMs;
+
+    /**
+     * Total time for which CCA is held busy on this channel.
+     */
+    uint32_t ccaBusyTimeInMs;
+};
+
+struct StaLinkLayerRadioStats {
+    /**
+     * Baseline information as defined in HAL 1.0.
+     */
+    @1.0::StaLinkLayerRadioStats V1_0;
+
+    /**
+     * Total time for which the radio is awake due to NAN scan since boot or crash.
+     */
+    uint32_t onTimeInMsForNanScan;
+
+    /**
+     * Total time for which the radio is awake due to background scan since boot or crash.
+     */
+    uint32_t onTimeInMsForBgScan;
+
+    /**
+     * Total time for which the radio is awake due to roam scan since boot or crash.
+     */
+    uint32_t onTimeInMsForRoamScan;
+
+    /**
+     * Total time for which the radio is awake due to PNO scan since boot or crash.
+     */
+    uint32_t onTimeInMsForPnoScan;
+
+    /**
+     * Total time for which the radio is awake due to Hotspot 2.0 scans and GAS exchange since boot
+     * or crash.
+     */
+    uint32_t onTimeInMsForHs20Scan;
+
+    /**
+     * List of channel stats associated with this radio
+     */
+    vec<WifiChannelStats> channelStats;
+
+    /**
+     * Radio ID: An implementation specific value identifying the radio interface for which the
+     * stats are produced. Framework must not interpret this value. It must use this value for
+     * persistently identifying the statistics between calls,
+     * e.g. if the HAL provides them in different order.
+     */
+    int32_t radioId;
+};
+
+/**
+ * Per peer statistics.  The types of peer include the Access Point (AP), the Tunneled Direct Link
+ * Setup (TDLS), the Group Owner (GO), the Neighbor Awareness Networking (NAN), etc.
+ */
+struct StaPeerInfo {
+    /**
+     * Station count: The total number of stations currently associated with the peer.
+     */
+    uint16_t staCount;
+
+    /**
+     * Channel utilization: The percentage of time (normalized to 255, i.e., x% corresponds to
+     * (int) x * 255 / 100) that the medium is sensed as busy measured by either physical or
+     * virtual carrier sense (CS) mechanism.
+     */
+    uint16_t chanUtil;
+
+    /**
+     * Per rate statistics
+     */
+    vec<StaRateStat> rateStats;
+};
+
+/**
+ * Iface statistics for the current connection.
+ */
+struct StaLinkLayerIfaceStats {
+    /**
+     * Baseline information as defined in HAL 1.0.
+     */
+    @1.0::StaLinkLayerIfaceStats V1_0;
+
+    /**
+     * Duty cycle for the iface.
+     * if this iface is being served using time slicing on a radio with one or more ifaces
+     * (i.e MCC), then the duty cycle assigned to this iface in %.
+     * If not using time slicing (i.e SCC or DBS), set to 100.
+     */
+    uint8_t timeSliceDutyCycleInPercent;
+
+    /**
+     * WME Best Effort (BE) Access Category (AC) contention time statistics.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+
+    /**
+     * WME Background (BK) Access Category (AC) contention time statistics.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+
+    /**
+     * WME Video (VI) Access Category (AC) contention time statistics.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+
+    /**
+     * WME Voice (VO) Access Category (AC) contention time statistics.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+
+    /**
+     * Per peer statistics.
+     */
+    vec<StaPeerInfo> peers;
+};
+
+/**
+ * Link layer stats retrieved via |getLinkLayerStats|.
+ */
+struct StaLinkLayerStats {
+    StaLinkLayerIfaceStats iface;
+
+    vec<StaLinkLayerRadioStats> radios;
+
+    /**
+     * TimeStamp for each stats sample.
+     * This is the absolute milliseconds from boot when these stats were
+     * sampled.
+     */
+    TimeStampInMs timeStampInMs;
+};
+
+/**
+ * Wifi rate info.
+ */
+struct WifiRateInfo {
+    /**
+     * Preamble used for RTT measurements.
+     */
+    WifiRatePreamble preamble;
+
+    /**
+     * Number of spatial streams.
+     */
+    WifiRateNss nss;
+
+    /**
+     * Bandwidth of channel.
+     */
+    WifiChannelWidthInMhz bw;
+
+    /**
+     * OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps.
+     * HT/VHT/HE/EHT it would be mcs index.
+     */
+    uint8_t rateMcsIdx;
+
+    /**
+     * Bitrate in units of 100 Kbps.
+     */
+    uint32_t bitRateInKbps;
+};
+
+/**
+ * Per rate statistics.  The rate is characterized by the combination of preamble, number of spatial
+ * streams, transmission bandwidth, and modulation and coding scheme (MCS).
+ */
+struct StaRateStat {
+    /**
+     * Wifi rate information: preamble, number of spatial streams, bandwidth, MCS, etc.
+     */
+    WifiRateInfo rateInfo;
+
+    /**
+     * Number of successfully transmitted data packets (ACK received)
+     */
+    uint32_t txMpdu;
+
+    /**
+     * Number of received data packets
+     */
+    uint32_t rxMpdu;
+
+    /**
+     * Number of data packet losses (no ACK)
+     */
+    uint32_t mpduLost;
+
+    /**
+     * Number of data packet retries
+     */
+    uint32_t retries;
+};
+
+/**
+ * RTT results.
+ */
+struct RttResult {
+    /**
+     * Peer device mac address.
+     */
+    MacAddress addr;
+
+    /**
+     * Burst number in a multi-burst request.
+     */
+    uint32_t burstNum;
+
+    /**
+     * Total RTT measurement frames attempted.
+     */
+    uint32_t measurementNumber;
+
+    /**
+     * Total successful RTT measurement frames.
+     */
+    uint32_t successNumber;
+
+    /**
+     * Maximum number of "FTM frames per burst" supported by
+     * the responder STA. Applies to 2-sided RTT only.
+     * If reponder overrides with larger value:
+     * - for single-burst request initiator will truncate the
+     * larger value and send a TMR_STOP after receiving as
+     * many frames as originally requested.
+     * - for multi-burst request, initiator will return
+     * failure right away.
+     */
+    uint8_t numberPerBurstPeer;
+
+    /**
+     * Ranging status.
+     */
+    RttStatus status;
+
+    /**
+     * When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+     * this will be the time provided by the responder as to
+     * when the request can be tried again. Applies to 2-sided
+     * RTT only. In sec, 1-31sec.
+     */
+    uint8_t retryAfterDuration;
+
+    /**
+     * RTT type.
+     */
+    RttType type;
+
+    /**
+     * Average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB.
+     */
+    Rssi rssi;
+
+    /**
+     * Rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional).
+     */
+    Rssi rssiSpread;
+
+    /**
+     * 1-sided RTT: TX rate of RTT frame.
+     * 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+     */
+    WifiRateInfo txRate;
+
+    /**
+     * 1-sided RTT: TX rate of Ack from other side.
+     * 2-sided RTT: TX rate of FTM frame coming from responder.
+     */
+    WifiRateInfo rxRate;
+
+    /**
+     * Round trip time in picoseconds
+     */
+    TimeSpanInPs rtt;
+
+    /**
+     * Rtt standard deviation in picoseconds.
+     */
+    TimeSpanInPs rttSd;
+
+    /**
+     * Difference between max and min rtt times recorded in picoseconds.
+     */
+    TimeSpanInPs rttSpread;
+
+    /**
+     * Distance in mm (optional).
+     */
+    int32_t distanceInMm;
+
+    /**
+     * Standard deviation in mm (optional).
+     */
+    int32_t distanceSdInMm;
+
+    /**
+     * Difference between max and min distance recorded in mm (optional).
+     */
+    int32_t distanceSpreadInMm;
+
+    /**
+     * Time of the measurement (in microseconds since boot).
+     */
+    TimeStampInUs timeStampInUs;
+
+    /**
+     * in ms, actual time taken by the FW to finish one burst
+     * measurement. Applies to 1-sided and 2-sided RTT.
+     */
+    uint32_t burstDurationInMs;
+
+    /**
+     * Number of bursts allowed by the responder. Applies
+     * to 2-sided RTT only.
+     */
+    uint32_t negotiatedBurstNum;
+
+    /**
+     * for 11mc only.
+     */
+    WifiInformationElement lci;
+
+    /**
+     * for 11mc only.
+     */
+    WifiInformationElement lcr;
+};
+
+/**
+ * NAN data path channel information provided to the framework.
+ */
+struct NanDataPathChannelInfo {
+    /**
+     * Channel frequency in MHz.
+     */
+    WifiChannelInMhz channelFreq;
+
+    /**
+     * Channel bandwidth in MHz.
+     */
+    WifiChannelWidthInMhz channelBandwidth;
+
+    /**
+     * Number of spatial streams used in the channel.
+     */
+    uint32_t numSpatialStreams;
+};
+
+/**
+ * NAN Data path confirmation Indication structure.
+ * Event indication is received on both initiator and responder side when negotiation for a
+ * data-path finish: on success or failure.
+ */
+struct NanDataPathConfirmInd {
+    /**
+     * Baseline information as defined in HAL 1.0.
+     */
+    @1.0::NanDataPathConfirmInd V1_0;
+
+    /**
+     * The channel(s) on which the NDP is scheduled to operate.
+     * Updates to the operational channels are provided using the |eventDataPathScheduleUpdate|
+     * event.
+     */
+    vec<NanDataPathChannelInfo> channelInfo;
+};
+
+/**
+ * NAN data path channel information update indication structure.
+ * Event indication is received by all NDP owners whenever the channels on which the NDP operates
+ * are updated.
+ * Note: multiple NDPs may share the same schedule, the indication specifies all NDPs to which it
+ * applies.
+ */
+struct NanDataPathScheduleUpdateInd {
+    /**
+     * The discovery address (NMI) of the peer to which the NDP is connected.
+     */
+    MacAddress peerDiscoveryAddress;
+
+    /**
+     * The updated channel(s) information.
+     */
+    vec<NanDataPathChannelInfo> channelInfo;
+
+    /**
+     * The list of NDPs to which this update applies.
+     */
+    vec<uint32_t> ndpInstanceIds;
+};
+
+/**
+ * Wifi usable channel information.
+ */
+struct WifiUsableChannel {
+    /**
+     * Wifi channel freqeuncy in MHz.
+     */
+    WifiChannelInMhz channel;
+
+    /**
+     * Wifi channel bandwidth in MHz.
+     */
+    WifiChannelWidthInMhz channelBandwidth;
+
+    /**
+     * Iface modes feasible on this channel.
+     */
+    bitfield<WifiIfaceMode> ifaceModeMask;
+};
+
+/**
+ * RTT Capabilities.
+ */
+struct RttCapabilities {
+    /**
+     * if 1-sided rtt data collection is supported.
+     */
+    bool rttOneSidedSupported;
+
+    /**
+     * if ftm rtt data collection is supported.
+     */
+    bool rttFtmSupported;
+
+    /**
+     * if initiator supports LCI request. Applies to 2-sided RTT.
+     */
+    bool lciSupported;
+
+    /**
+     * if initiator supports LCR request. Applies to 2-sided RTT.
+     */
+    bool lcrSupported;
+
+    /**
+     * if 11mc responder mode is supported.
+     */
+    bool responderSupported;
+
+    /**
+     * Bit mask indicates what preamble is supported by initiator.
+     * Combination of |RttPreamble| values.
+     */
+    bitfield<RttPreamble> preambleSupport;
+
+    /**
+     * Bit mask indicates what BW is supported by initiator.
+     * Combination of |RttBw| values.
+     */
+    bitfield<RttBw> bwSupport;
+
+    /**
+     * Draft 11mc spec version supported by chip.
+     * For instance, version 4.0 must be 40 and version 4.3 must be 43 etc.
+     */
+    uint8_t mcVersion;
+};
+
+/**
+ * Cipher suite flags.
+ */
+enum NanCipherSuiteType : @1.0::NanCipherSuiteType {
+    /**
+     *  NCS-PK-128
+     */
+    PUBLIC_KEY_128_MASK = 1 << 2,
+    /**
+     *  NCS-PK-256
+     */
+    PUBLIC_KEY_256_MASK = 1 << 3,
+};
+
+/**
+ * NAN configuration request parameters added in the 1.2 HAL. These are supplemental to previous
+ * versions.
+ */
+struct NanConfigRequestSupplemental {
+    /**
+     * Baseline information as defined in HAL 1.5.
+     */
+    @1.5::NanConfigRequestSupplemental V1_5;
+
+    /**
+     * Controls NAN instant communication mode operate on which channel
+     */
+    uint32_t instantModeChannel;
+};
+
+/**
+ * Configuration of NAN data-path security.
+ */
+struct NanDataPathSecurityConfig {
+    /**
+     * Security configuration of the data-path (NDP). Security is enabled if not equal to
+     * |NanDataPathSecurityType.OPEN|.
+     * NAN Spec: Service Discovery Extension Attribute (SDEA) / Control / Security Required
+     */
+    NanDataPathSecurityType securityType;
+
+    /**
+     * Cipher type for data-paths. If |securityType| is |NanDataPathSecurityType.OPEN| then must
+     * be set to |NanCipherSuiteType.NONE|, otherwise a non-|NanCipherSuiteType.NONE| cipher suite
+     * must be specified.
+     */
+    NanCipherSuiteType cipherType;
+
+    /**
+     * Optional Pairwise Master Key (PMK). Must be specified (and is only used) if |securityType| is
+     * set to |NanDataPathSecurityType.PMK|.
+     * Ref: IEEE 802.11i
+     */
+    uint8_t[32] pmk;
+
+    /**
+     * Optional Passphrase. Must be specified (and is only used) if |securityType| is set to
+     * |NanDataPathSecurityType.PASSPHRASE|.
+     * Min length: |MIN_PASSPHRASE_LENGTH|
+     * Max length: |MAX_PASSPHRASE_LENGTH|
+     * NAN Spec: Appendix: Mapping passphrase to PMK for NCS-SK Cipher Suites
+     */
+    vec<uint8_t> passphrase;
+
+    /**
+     * Security Context Identifier attribute contains PMKID shall be included in NDP setup and
+     * response messages. Security Context Identifier, Identifies the Security Context. When
+     * security is enabled this field contains the 16 octet PMKID identifying the PMK used for
+     * setting up the Secure Data Path.
+     */
+    uint8_t[16] scid;
+};
+
+/**
+ * Response to a data-path request from a peer.
+ */
+struct NanRespondToDataPathIndicationRequest {
+    /**
+     * Accept (true) or reject (false) the request.
+     * NAN Spec: Data Path Attributes / NDP Attribute / Type and Status
+     */
+    bool acceptRequest;
+
+    /**
+     * ID of the data-path (NDP) for which we're responding - obtained as part of the request in
+     * |IWifiNanIfaceEventCallback.eventDataPathRequest|.
+     */
+    uint32_t ndpInstanceId;
+
+    /**
+     * NAN data interface name on which this data-path session is to be started.
+     * This must be an interface created using |IWifiNanIface.createDataInterfaceRequest|.
+     */
+    string ifaceName;
+
+    /**
+     * Security configuration of the requested data-path.
+     */
+    NanDataPathSecurityConfig securityConfig;
+
+    /**
+     * Arbitrary information communicated to the peer as part of the data-path setup process - there
+     * is no semantic meaning to these bytes. They are passed-through from sender to receiver as-is
+     * with no parsing.
+     * Max length: |NanCapabilities.maxAppInfoLen|.
+     * NAN Spec: Data Path Attributes / NDP Attribute / NDP Specific Info
+     */
+    vec<uint8_t> appInfo;
+
+    /**
+     * A service name to be used with |passphrase| to construct a Pairwise Master Key (PMK) for the
+     * data-path. Only relevant when a data-path is requested which is not associated with a NAN
+     * discovery session - e.g. using out-of-band discovery.
+     * Constraints: same as |NanDiscoveryCommonConfig.serviceName|
+     * NAN Spec: Appendix: Mapping pass-phrase to PMK for NCS-SK Cipher Suites
+     */
+    vec<uint8_t> serviceNameOutOfBand;
+};
+
+/**
+ *  Data Path Initiator requesting a data-path.
+ */
+struct NanInitiateDataPathRequest {
+    /**
+     * ID of the peer. Obtained as part of an earlier |IWifiNanIfaceEventCallback.eventMatch| or
+     * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+     */
+    uint32_t peerId;
+
+    /**
+     * NAN management interface MAC address of the peer. Obtained as part of an earlier
+     * |IWifiNanIfaceEventCallback.eventMatch| or |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+     */
+    MacAddress peerDiscMacAddr;
+
+    /**
+     * Config flag for channel request.
+     */
+    NanDataPathChannelCfg channelRequestType;
+
+    /**
+     * Channel frequency in MHz to start data-path. Not relevant if |channelRequestType| is
+     * |NanDataPathChannelCfg.CHANNEL_NOT_REQUESTED|.
+     */
+    WifiChannelInMhz channel;
+
+    /**
+     * NAN data interface name on which this data-path session is to be initiated.
+     * This must be an interface created using |IWifiNanIface.createDataInterfaceRequest|.
+     */
+    string ifaceName;
+
+    /**
+     * Security configuration of the requested data-path.
+     */
+    NanDataPathSecurityConfig securityConfig;
+
+    /**
+     * Arbitrary information communicated to the peer as part of the data-path setup process - there
+     * is no semantic meaning to these bytes. They are passed-through from sender to receiver as-is
+     * with no parsing.
+     * Max length: |NanCapabilities.maxAppInfoLen|.
+     * NAN Spec: Data Path Attributes / NDP Attribute / NDP Specific Info
+     */
+    vec<uint8_t> appInfo;
+
+    /**
+     * A service name to be used with |passphrase| to construct a Pairwise Master Key (PMK) for the
+     * data-path. Only relevant when a data-path is requested which is not associated with a NAN
+     * discovery session - e.g. using out-of-band discovery.
+     * Constraints: same as |NanDiscoveryCommonConfig.serviceName|
+     * NAN Spec: Appendix: Mapping pass-phrase to PMK for NCS-SK Cipher Suites
+     */
+    vec<uint8_t> serviceNameOutOfBand;
+};
+
+/**
+ * Configurations of NAN discovery sessions: common to publish and subscribe discovery.
+ */
+struct NanDiscoveryCommonConfig {
+    /**
+     * The ID of the discovery session being configured. A value of 0 specifies a request to create
+     * a new discovery session. The new discovery session ID is returned with
+     * |IWifiNanIfaceEventCallback.notifyStartPublishResponse| or
+     * |IWifiNanIfaceEventCallback.notifyStartSubscribeResponse|.
+     * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+     */
+    uint8_t sessionId;
+
+    /**
+     * The lifetime of the discovery session in seconds. A value of 0 means run forever or until
+     * canceled using |IWifiIface.stopPublishRequest| or |IWifiIface.stopSubscribeRequest|.
+     */
+    uint16_t ttlSec;
+
+    /**
+     * Indicates the interval between two Discovery Windows in which the device supporting the
+     * service is awake to transmit or receive the Service Discovery frames. Valid values of Awake
+     * DW Interval are: 1, 2, 4, 8 and 16. A value of 0 will default to 1. Does not override
+     * |NanBandSpecificConfig.discoveryWindowIntervalVal| configurations if those are specified.
+     */
+    uint16_t discoveryWindowPeriod;
+
+    /**
+     * The lifetime of the discovery session in number of transmitted SDF discovery packets. A value
+     * of 0 means forever or until canceled using |IWifiIface.stopPublishRequest| or
+     * |IWifiIface.stopSubscribeRequest|.
+     */
+    uint8_t discoveryCount;
+
+    /**
+     * UTF-8 encoded string identifying the service.
+     * Max length: |NanCapabilities.maxServiceNameLen|.
+     * NAN Spec: The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric
+     * values (A-Z, a-z, 0-9), the hyphen ('-'), and the period ('.'). All valid multi-byte UTF-8
+     * characters are acceptable in a Service Name.
+     */
+    vec<uint8_t> serviceName;
+
+    /**
+     * Specifies how often to trigger |IWifiNanIfaceEventCallback.eventMatch| when continuously
+     * discovering the same discovery session (with no changes).
+     */
+    NanMatchAlg discoveryMatchIndicator;
+
+    /**
+     * Arbitrary information communicated in discovery packets - there is no semantic meaning to these
+     * bytes. They are passed-through from publisher to subscriber as-is with no parsing.
+     * Max length: |NanCapabilities.maxServiceSpecificInfoLen|.
+     * NAN Spec: Service Descriptor Attribute (SDA) / Service Info
+     */
+    vec<uint8_t> serviceSpecificInfo;
+
+    /**
+     * Arbitrary information communicated in discovery packets - there is no semantic meaning to these
+     * bytes. They are passed-through from publisher to subscriber as-is with no parsing.
+     * Max length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|.
+     * Spec: Service Descriptor Extension Attribute (SDEA) / Service Info
+     */
+    vec<uint8_t> extendedServiceSpecificInfo;
+
+    /**
+     * Ordered sequence of <length, value> pairs (|length| uses 1 byte and contains the number of
+     * bytes in the |value| field) which specify further match criteria (beyond the service name).
+     * The match behavior is specified in details in the NAN spec.
+     * Publisher: used in SOLICITED or SOLICITED_UNSOLICITED sessions.
+     * Subscriber: used in ACTIVE or PASSIVE sessions.
+     * Max length: |NanCapabilities.maxMatchFilterLen|.
+     * NAN Spec: matching_filter_rx
+     */
+    vec<uint8_t> rxMatchFilter;
+
+    /**
+     * Ordered sequence of <length, value> pairs (|length| uses 1 byte and contains the number of
+     * bytes in the |value| field) which specify further match criteria (beyond the service name).
+     * The match behavior is specified in details in the NAN spec.
+     * Publisher: used if provided.
+     * Subscriber: used (if provided) only in ACTIVE sessions.
+     * Max length: |NanCapabilities.maxMatchFilterLen|.
+     * NAN Spec: matching_filter_tx and Service Descriptor Attribute (SDA) / Matching Filter
+     */
+    vec<uint8_t> txMatchFilter;
+
+    /**
+     * Specifies whether or not the discovery session uses the
+     * |NanBandSpecificConfig.rssiCloseProximity| value (configured in enable/configure requests) to
+     * filter out matched discovered peers.
+     * NAN Spec: Service Descriptor Attribute / Service Control / Discovery Range Limited.
+     */
+    bool useRssiThreshold;
+
+    /**
+     * Controls whether or not the |IWifiNanIfaceEventCallback.eventPublishTerminated| (for publish
+     * discovery sessions) or |IWifiNanIfaceEventCallback.eventSubscribeTerminated| (for subscribe
+     * discovery sessions) will be delivered.
+     */
+    bool disableDiscoveryTerminationIndication;
+
+    /**
+     * Controls whether or not the |IWifiNanIfaceEventCallback.eventMatchExpired| will be delivered.
+     */
+    bool disableMatchExpirationIndication;
+
+    /**
+     * Controls whether or not the |IWifiNanIfaceEventCallback.eventFollowupReceived| will be
+     * delivered.
+     */
+    bool disableFollowupReceivedIndication;
+
+    /**
+     * Security configuration of data-paths created in the context of this discovery session. Security
+     * parameters can be overridden during the actual construction of the data-path - allowing
+     * individual data-paths to have unique PMKs or Passphrases.
+     */
+    NanDataPathSecurityConfig securityConfig;
+
+    /**
+     * Specifies whether or not there is a ranging requirement in this discovery session.
+     * Ranging is only performed if all other match criteria with the peer are met. Ranging must
+     * be performed if both peers in the discovery session (publisher and subscriber) set this
+     * flag to true. Otherwise, if either peer sets this flag to false, ranging must not be performed
+     * and must not impact discovery decisions.
+     * Note: specifying that ranging is required also implies that this device must automatically
+     * accept ranging requests from peers.
+     * NAN Spec: Service Discovery Extension Attribute (SDEA) / Control / Ranging Require.
+     */
+    bool rangingRequired;
+
+    /**
+     * Interval in msec between two ranging measurements. Only relevant if |rangingRequired| is true.
+     * If the Awake DW interval specified either in |discoveryWindowPeriod| or in
+     * |NanBandSpecificConfig.discoveryWindowIntervalVal| is larger than the ranging interval then
+     * priority is given to Awake DW interval.
+     */
+    uint32_t rangingIntervalMsec;
+
+    /**
+     * The type of ranging feedback to be provided by discovery session matches
+     * |IWifiNanIfaceEventCallback.eventMatch|. Only relevant if |rangingRequired| is true.
+     */
+    bitfield<NanRangingIndication> configRangingIndications;
+
+    /**
+     * The ingress and egress distance in cm. If ranging is enabled (|rangingEnabled| is true) then
+     * |configRangingIndications| is used to determine whether ingress and/or egress (or neither)
+     * are used to determine whether a match has occurred.
+     * NAN Spec: Service Discovery Extension Attribute (SDEA) / Ingress & Egress Range Limit
+     */
+    uint16_t distanceIngressCm;
+
+    uint16_t distanceEgressCm;
+};
+
+/**
+ * Publish request: specifies a publish discovery operation.
+ */
+struct NanPublishRequest {
+    /**
+     * Common configuration of discovery sessions.
+     */
+    NanDiscoveryCommonConfig baseConfigs;
+
+    /**
+     * The type of the publish discovery session.
+     */
+    NanPublishType publishType;
+
+    /**
+     * For publishType of |NanPublishType.SOLICITED| or |NanPublishType.UNSOLICITED_SOLICITED|
+     * specifies the type of transmission used for responding to the probing subscribe discovery
+     * peer.
+     */
+    NanTxType txType;
+
+    /**
+     * Specifies whether data-path requests |IWifiNanIfaceEventCallback.eventDataPathRequest| (in
+     * the context of this discovery session) are automatically accepted (if true) - in which case
+     * the Responder must not call the |IWifiNanIface.respondToDataPathIndicationRequest| method and
+     * the device must automatically accept the data-path request and complete the negotiation.
+     */
+    bool autoAcceptDataPathRequests;
+};
+
+/**
+ * Match indication structure
+ */
+struct NanMatchInd {
+    /**
+     * Publish or subscribe discovery session ID of an existing discovery session.
+     * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+     */
+    uint8_t discoverySessionId;
+
+    /**
+     * A unique ID of the peer. Can be subsequently used in |IWifiNanIface.transmitFollowupRequest| or
+     * to set up a data-path.
+     */
+    uint32_t peerId;
+
+    /**
+     * The NAN Discovery (management) MAC address of the peer.
+     */
+    MacAddress addr;
+
+    /**
+     * The arbitrary information contained in the |NanDiscoveryCommonConfig.serviceSpecificInfo| of
+     * the peer's discovery session configuration.
+     * Max length: |NanCapabilities.maxServiceSpecificInfoLen|.
+     * NAN Spec: Service Descriptor Attribute (SDA) / Service Info
+     */
+    vec<uint8_t> serviceSpecificInfo;
+
+    /**
+     * Arbitrary information communicated in discovery packets - there is no semantic meaning to these
+     * bytes. They are passed-through from publisher to subscriber as-is with no parsing.
+     * Max length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|.
+     * Spec: Service Descriptor Extension Attribute (SDEA) / Service Info
+     */
+    vec<uint8_t> extendedServiceSpecificInfo;
+
+    /**
+     * The match filter from the discovery packet (publish or subscribe) which caused service
+     * discovery. Matches the |NanDiscoveryCommonConfig.txMatchFilter| of the peer's Unsolicited
+     * publish message or of the local device's Active subscribe message.
+     * Max length: |NanCapabilities.maxMatchFilterLen|.
+     * NAN Spec: Service Descriptor Attribute (SDA) / Matching Filter
+     */
+    vec<uint8_t> matchFilter;
+
+    /**
+     * Indicates the type of discovery: true if match occurred on a Beacon frame, false if the match
+     * occurred on a Service Discovery Frames (SDF).
+     */
+    bool matchOccuredInBeaconFlag;
+
+    /**
+     * Flag to indicate firmware is out of resource and that it can no longer track this Service Name.
+     * Indicates that while |IWifiNanIfaceEventCallback.eventMatch| will be received, the
+     * |NanDiscoveryCommonConfig.discoveryMatchIndicator| configuration will not be honored.
+     */
+    bool outOfResourceFlag;
+
+    /**
+     * If RSSI filtering was enabled using |NanDiscoveryCommonConfig.useRssiThreshold| in discovery
+     * session setup then this field contains the received RSSI value. It will contain 0 if RSSI
+     * filtering was not enabled.
+     * RSSI values are returned without sign, e.g. -70dBm will be returned as 70.
+     */
+    uint8_t rssiValue;
+
+    /**
+     * Cipher type for data-paths constructed in the context of this discovery session. Valid if
+     * |peerRequiresSecurityEnabledInNdp| is true.
+     */
+    NanCipherSuiteType peerCipherType;
+
+    /**
+     * Indicates whether or not the peer requires security enabled in any data-path (NDP) constructed
+     * in the context of this discovery session. The |cipherType| specifies the cipher type for such
+     * data-paths.
+     * NAN Spec: Service Discovery Extension Attribute (SDEA) / Control / Security Required
+     */
+    bool peerRequiresSecurityEnabledInNdp;
+
+    /**
+     * Indicates whether or not the peer requires (and hence allows) ranging in the context of this
+     * discovery session.
+     * Note that ranging is only performed if all other match criteria with the peer are met.
+     * NAN Spec: Service Discovery Extension Attribute (SDEA) / Control / Ranging Require.
+     */
+    bool peerRequiresRanging;
+
+    /**
+     * Ranging indication supersedes the NanMatchAlg specification.
+     * Ex: If NanMatchAlg is MATCH_ONCE, but ranging indications is continuous then continuous
+     * match notifications will be received (with ranging information).
+     * Ranging indication data is provided if Ranging required is enabled in the discovery
+     * specification and:
+     *   1) continuous ranging specified.
+     *   2) ingress/egress specified and:
+     *       - notify once for ingress >= ingress_distance and egress <= egress_distance,
+     *       - same for ingress_egress_both
+     * If the Awake DW intervals are larger than the ranging intervals then priority is given to the
+     * device DW intervals.
+     *
+     * If ranging was required and executed contains the distance to the peer in MM. The
+     * |rangingIndicationType| field specifies the event which triggered ranging.
+     */
+    uint32_t rangingMeasurementInMm;
+
+    /**
+     * The ranging event(s) which triggered the ranging. E.g. can indicate that continuous ranging was
+     * requested, or else that an ingress event occurred.
+     */
+    bitfield<NanRangingIndication> rangingIndicationType;
+
+    /**
+     * Security Context Identifier attribute contains PMKID shall be included in NDP setup and
+     * response messages. Security Context Identifier, Identifies the Security Context. For NAN
+     * Shared Key Cipher Suite, this field contains the 16 octet PMKID identifying the PMK used for
+     * setting up the Secure Data Path.
+     */
+    vec<uint8_t> scid;
+};
+
+/**
+ * NDP Capabilities response.
+ */
+struct NanCapabilities {
+    /**
+     * Maximum number of clusters which the device can join concurrently.
+     */
+    uint32_t maxConcurrentClusters;
+
+    /**
+     * Maximum number of concurrent publish discovery sessions.
+     */
+    uint32_t maxPublishes;
+
+    /**
+     * Maximum number of concurrent subscribe discovery sessions.
+     */
+    uint32_t maxSubscribes;
+
+    /**
+     * Maximum length (in bytes) of service name.
+     */
+    uint32_t maxServiceNameLen;
+
+    /**
+     * Maximum length (in bytes) of individual match filters.
+     */
+    uint32_t maxMatchFilterLen;
+
+    /**
+     * Maximum length (in bytes) of aggregate match filters across all active sessions.
+     */
+    uint32_t maxTotalMatchFilterLen;
+
+    /**
+     * Maximum length (in bytes) of the service specific info field.
+     */
+    uint32_t maxServiceSpecificInfoLen;
+
+    /**
+     * Maximum length (in bytes) of the extended service specific info field.
+     */
+    uint32_t maxExtendedServiceSpecificInfoLen;
+
+    /**
+     * Maximum number of data interfaces (NDI) which can be created concurrently on the device.
+     */
+    uint32_t maxNdiInterfaces;
+
+    /**
+     * Maximum number of data paths (NDP) which can be created concurrently on the device, across all
+     * data interfaces (NDI).
+     */
+    uint32_t maxNdpSessions;
+
+    /**
+     * Maximum length (in bytes) of application info field (used in data-path negotiations).
+     */
+    uint32_t maxAppInfoLen;
+
+    /**
+     * Maximum number of transmitted followup messages which can be queued by the firmware.
+     */
+    uint32_t maxQueuedTransmitFollowupMsgs;
+
+    /**
+     * Maximum number MAC interface addresses which can be specified to a subscribe discovery session.
+     */
+    uint32_t maxSubscribeInterfaceAddresses;
+
+    /**
+     * The set of supported Cipher suites. The |NanCipherSuiteType| bit fields are used.
+     */
+    bitfield<NanCipherSuiteType> supportedCipherSuites;
+
+    /**
+     * Flag to indicate id instant communication mode is supported.
+     */
+    bool instantCommunicationModeSupportFlag;
+};
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl
index 890d986..4d78640 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl
@@ -41,8 +41,9 @@
   BANDWIDTH_80 = 4,
   BANDWIDTH_80P80 = 5,
   BANDWIDTH_160 = 6,
-  BANDWIDTH_2160 = 7,
-  BANDWIDTH_4320 = 8,
-  BANDWIDTH_6480 = 9,
-  BANDWIDTH_8640 = 10,
+  BANDWIDTH_320 = 7,
+  BANDWIDTH_2160 = 8,
+  BANDWIDTH_4320 = 9,
+  BANDWIDTH_6480 = 10,
+  BANDWIDTH_8640 = 11,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
index 6b60d17..af0e960 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
@@ -40,4 +40,5 @@
   WIFI_STANDARD_11AC = 2,
   WIFI_STANDARD_11AX = 3,
   WIFI_STANDARD_11AD = 4,
+  WIFI_STANDARD_11BE = 5,
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl
index 844c838..8d8d7bb 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl
@@ -43,4 +43,5 @@
   boolean enableHeMultiUserBeamformer;
   boolean enableHeTargetWakeTime;
   boolean enableEdmg;
+  boolean enable80211BE;
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IHostapdCallback.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IHostapdCallback.aidl
index 36d2104..9dd062a 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IHostapdCallback.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IHostapdCallback.aidl
@@ -36,5 +36,5 @@
 interface IHostapdCallback {
   oneway void onApInstanceInfoChanged(in android.hardware.wifi.hostapd.ApInfo apInfo);
   oneway void onConnectedClientsChanged(in android.hardware.wifi.hostapd.ClientInfo clientInfo);
-  oneway void onFailure(in String ifaceName);
+  oneway void onFailure(in String ifaceName, in String instanceName);
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/NetworkParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/NetworkParams.aidl
index ffe2f33..4554223 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/NetworkParams.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/NetworkParams.aidl
@@ -39,4 +39,5 @@
   android.hardware.wifi.hostapd.EncryptionType encryptionType;
   String passphrase;
   boolean isMetered;
+  byte[] vendorElements;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl
index c982402..e605153 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl
@@ -29,8 +29,9 @@
     BANDWIDTH_80 = 4,
     BANDWIDTH_80P80 = 5,
     BANDWIDTH_160 = 6,
-    BANDWIDTH_2160 = 7,
-    BANDWIDTH_4320 = 8,
-    BANDWIDTH_6480 = 9,
-    BANDWIDTH_8640 = 10,
+    BANDWIDTH_320 = 7,
+    BANDWIDTH_2160 = 8,
+    BANDWIDTH_4320 = 9,
+    BANDWIDTH_6480 = 10,
+    BANDWIDTH_8640 = 11,
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
index 2cda55b..f4e3eb0 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
@@ -27,6 +27,7 @@
  * WIFI_STANDARD_11AC = hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 1.
  * WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211A and High Efficiency supported.
  * WIFI_STANDARD_11AD = hw_mode is HOSTAPD_MODE_IEEE80211AD.
+ * WIFI_STANDARD_11BE = hw_mode is HOSTAPD_MODE_IEEE80211A and Extreme High Throughput supported.
  */
 @VintfStability
 @Backing(type="int")
@@ -37,4 +38,5 @@
     WIFI_STANDARD_11AC = 2,
     WIFI_STANDARD_11AX = 3,
     WIFI_STANDARD_11AD = 4,
+    WIFI_STANDARD_11BE = 5,
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl
index 210e99f..e66a24a 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl
@@ -68,4 +68,10 @@
      * Enable EDMG (802.11ay), this option is only allowed for the 60GHz band.
      */
     boolean enableEdmg;
+    /**
+     * Whether IEEE 802.11be (Extreme High Throughput) is enabled or not.
+     * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+     * used with Extreme High Throughput.
+     */
+    boolean enable80211BE;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IHostapdCallback.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IHostapdCallback.aidl
index 7b04944..456f46a 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IHostapdCallback.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IHostapdCallback.aidl
@@ -41,7 +41,10 @@
      * Invoked when an asynchronous failure is encountered in one of the access
      * points added via |IHostapd.addAccessPoint|.
      *
-     * @param ifaceName Name of the interface.
+     * @param ifaceName Name of the interface which was added via
+     *                  |IHostapd.addAccessPoint|.
+     * @param instanceName Name of the AP instance which is associated with
+     *                     the interface.
      */
-    oneway void onFailure(in String ifaceName);
+    oneway void onFailure(in String ifaceName, in String instanceName);
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/NetworkParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/NetworkParams.aidl
index df84eca..47d9e6f 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/NetworkParams.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/NetworkParams.aidl
@@ -44,4 +44,12 @@
      * CHARGEABLE_PUBLIC_NETWORK when set to true.
      */
     boolean isMetered;
+    /**
+     * Additional vendor specific elements for Beacon and Probe Response frames
+     * This parameter can be used to add additional vendor specific element(s) into
+     * the end of the Beacon and Probe Response frames. The format for these
+     * element(s) is a binary dump of the raw information elements (id+len+payload for
+     * one or more elements). Example: byte[]{ 221, 4, 17, 34, 51, 1 }
+     */
+    byte[] vendorElements;
 }
diff --git a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
index 41c54b3..cd7ff82 100644
--- a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
+++ b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
@@ -232,7 +232,7 @@
         const ::aidl::android::hardware::wifi::hostapd::ClientInfo &) override {
         return ndk::ScopedAStatus::ok();
     }
-    ::ndk::ScopedAStatus onFailure(const std::string &) override {
+    ::ndk::ScopedAStatus onFailure(const std::string&, const std::string&) override {
         return ndk::ScopedAStatus::ok();
     }
 };
@@ -431,6 +431,7 @@
     EXPECT_TRUE(status.isOk());
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HostapdAidl);
 INSTANTIATE_TEST_SUITE_P(
     Hostapd, HostapdAidl,
     testing::ValuesIn(android::getAidlHalInstanceNames(IHostapd::descriptor)),
diff --git a/wifi/netlinkinterceptor/aidl/Android.bp b/wifi/netlinkinterceptor/aidl/Android.bp
new file mode 100644
index 0000000..924edee
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.net.nlinterceptor",
+    vendor_available: true,
+    srcs: ["android/hardware/net/nlinterceptor/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
diff --git a/wifi/netlinkinterceptor/aidl/aidl_api/NetlinkInterceptor/current/android/hardware/net/nlinterceptor/IInterceptor.aidl b/wifi/netlinkinterceptor/aidl/aidl_api/NetlinkInterceptor/current/android/hardware/net/nlinterceptor/IInterceptor.aidl
new file mode 100644
index 0000000..249b343
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/aidl_api/NetlinkInterceptor/current/android/hardware/net/nlinterceptor/IInterceptor.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.net.nlinterceptor;
+@VintfStability
+interface IInterceptor {
+  int createSocket(in int nlFamily, in int clientNlPid, in String clientName);
+  void closeSocket(in int nlFamily, in int interceptorNlPid);
+  void subscribeGroup(in int nlFamily, in int interceptorNlPid, in int nlGroup);
+  void unsubscribeGroup(in int nlFamily, in int interceptorNlPid, in int nlGroup);
+}
diff --git a/wifi/netlinkinterceptor/aidl/aidl_api/android.hardware.net.nlinterceptor/current/android/hardware/net/nlinterceptor/IInterceptor.aidl b/wifi/netlinkinterceptor/aidl/aidl_api/android.hardware.net.nlinterceptor/current/android/hardware/net/nlinterceptor/IInterceptor.aidl
new file mode 100644
index 0000000..3d0f955
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/aidl_api/android.hardware.net.nlinterceptor/current/android/hardware/net/nlinterceptor/IInterceptor.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.net.nlinterceptor;
+@VintfStability
+interface IInterceptor {
+  android.hardware.net.nlinterceptor.InterceptedSocket createSocket(in int nlFamily, in int clientNlPid, in String clientName);
+  void closeSocket(in android.hardware.net.nlinterceptor.InterceptedSocket handle);
+  void subscribeGroup(in android.hardware.net.nlinterceptor.InterceptedSocket handle, in int nlGroup);
+  void unsubscribeGroup(in android.hardware.net.nlinterceptor.InterceptedSocket handle, in int nlGroup);
+}
diff --git a/wifi/netlinkinterceptor/aidl/aidl_api/android.hardware.net.nlinterceptor/current/android/hardware/net/nlinterceptor/InterceptedSocket.aidl b/wifi/netlinkinterceptor/aidl/aidl_api/android.hardware.net.nlinterceptor/current/android/hardware/net/nlinterceptor/InterceptedSocket.aidl
new file mode 100644
index 0000000..b679be5
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/aidl_api/android.hardware.net.nlinterceptor/current/android/hardware/net/nlinterceptor/InterceptedSocket.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.net.nlinterceptor;
+@VintfStability
+parcelable InterceptedSocket {
+  int nlFamily;
+  int portId;
+}
diff --git a/wifi/netlinkinterceptor/aidl/android/hardware/net/nlinterceptor/IInterceptor.aidl b/wifi/netlinkinterceptor/aidl/android/hardware/net/nlinterceptor/IInterceptor.aidl
new file mode 100644
index 0000000..c222a1e
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/android/hardware/net/nlinterceptor/IInterceptor.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.net.nlinterceptor;
+
+import android.hardware.net.nlinterceptor.InterceptedSocket;
+
+/**
+ * Netlink Interceptor
+ *
+ * This HAL provides a way for Android services to route their Netlink traffic to a location other
+ * than the Kernel. One might want to do this for a variety of reasons:
+ * -> Route Netlink traffic to a different host.
+ * -> Route Netlink traffic to a different VM.
+ * -> Convert Netlink commands into proprietary vendor hardware commands.
+ *
+ * Some important notes regarding Netlink Interceptor.
+ * -> All int values are treated as unsigned.
+ * -> Users of Netlink Interceptor must close their sockets with closeSocket manually.
+ * -> PID != process ID. In this case, it is "port ID", a unique number assigned by the kernel to a
+ *    given Netlink socket.
+ * -> Netlink PIDs are only unique per family. This means that for all NETLINK_GENERIC sockets,
+ *    there can only be one socket with PID "1234". HOWEVER, there can ALSO be a Netlink socket
+ *    using NETLINK_ROUTE which has a PID of "1234". Hence, in order to uniquely identify a Netlink
+ *    socket, both the PID and Netlink Family are required.
+ */
+@VintfStability
+interface IInterceptor {
+    /**
+     * Creates a Netlink socket on both the HU and TCU, and a bi-directional gRPC stream to carry
+     * data between them. This must be closed by the caller with closeSocket().
+     *
+     * @param nlFamily - Netlink Family. Support for families other than NETLINK_GENERIC is still
+     * experimental.
+     * @param clientNlPid - Port ID of the caller's Netlink socket.
+     * @param clientName - Human readable name of the caller. Used for debugging.
+     *
+     * @return InterceptedSocket identifying the socket on the HU allocated for the caller.
+     */
+    InterceptedSocket createSocket(in int nlFamily, in int clientNlPid, in String clientName);
+
+    /**
+     * Closes a socket and gRPC stream given the socket's identifier. This must be invoked manually
+     * by the caller of createSocket().
+     *
+     * @param handle - unique identifier for a socket returned by createSocket.
+     */
+    void closeSocket(in InterceptedSocket handle);
+
+    /**
+     * Subscribes a socket on the TCU to a Netlink multicast group.
+     *
+     * @param handle - unique identifier for a socket returned by createSocket.
+     * @param nlGroup - A single Netlink multicast group that the caller wants to subscribe to.
+     */
+    void subscribeGroup(in InterceptedSocket handle, in int nlGroup);
+
+    /**
+     * Unsubscribes a socket on the TCU from a Netlink multicast group.
+     *
+     * @param handle - unique identifier for a socket returned by createSocket.
+     * @param nlGroup - A single Netlink multicast group that the caller wants to unsubscribe from.
+     */
+    void unsubscribeGroup(in InterceptedSocket handle, in int nlGroup);
+}
diff --git a/wifi/netlinkinterceptor/aidl/android/hardware/net/nlinterceptor/InterceptedSocket.aidl b/wifi/netlinkinterceptor/aidl/android/hardware/net/nlinterceptor/InterceptedSocket.aidl
new file mode 100644
index 0000000..d74a556
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/android/hardware/net/nlinterceptor/InterceptedSocket.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.net.nlinterceptor;
+
+/**
+ * Unique identifier for a Netlink socket.
+ */
+@VintfStability
+parcelable InterceptedSocket {
+    /**
+     * Netlink family of the identified socket
+     */
+    int nlFamily;
+
+    /**
+     * Netlink port ID of the identified socket.
+     */
+    int portId;
+}
diff --git a/wifi/netlinkinterceptor/aidl/default/Android.bp b/wifi/netlinkinterceptor/aidl/default/Android.bp
new file mode 100644
index 0000000..5227e51
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.net.nlinterceptor-service.default",
+    init_rc: ["nlinterceptor-default.rc"],
+    vintf_fragments: ["nlinterceptor-default.xml"],
+    vendor: true,
+    relative_install_path: "hw",
+    defaults: ["nlinterceptor@defaults"],
+    shared_libs: [
+        "android.hardware.net.nlinterceptor-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "libnlinterceptor",
+        "libnl++",
+    ],
+    srcs: [
+        "InterceptorRelay.cpp",
+        "NetlinkInterceptor.cpp",
+        "service.cpp",
+        "util.cpp",
+    ],
+}
diff --git a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
new file mode 100644
index 0000000..ded9122
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InterceptorRelay.h"
+
+#include <android-base/logging.h>
+#include <libnl++/printer.h>
+#include <poll.h>
+
+#include <chrono>
+
+#include "util.h"
+
+namespace android::nlinterceptor {
+using namespace std::chrono_literals;
+
+static constexpr std::chrono::milliseconds kPollTimeout = 300ms;
+static constexpr bool kSuperVerbose = true;
+
+InterceptorRelay::InterceptorRelay(uint32_t nlFamily, uint32_t clientNlPid,
+                                   const std::string& clientName)
+    : mClientName(clientName),
+      mNlSocket(std::make_optional<nl::Socket>(nlFamily, 0, 0)),
+      mClientNlPid(clientNlPid) {}
+
+InterceptorRelay::~InterceptorRelay() {
+    mRunning = false;
+    if (mRelayThread.joinable()) mRelayThread.join();
+}
+
+uint32_t InterceptorRelay::getPid() {
+    auto pidMaybe = mNlSocket->getPid();
+    CHECK(pidMaybe.has_value()) << "Failed to get pid of nl::Socket!";
+    return *pidMaybe;
+}
+
+void InterceptorRelay::relayMessages() {
+    pollfd fds[] = {
+        mNlSocket->preparePoll(POLLIN),
+    };
+    while (mRunning) {
+        if (poll(fds, countof(fds), kPollTimeout.count()) < 0) {
+            PLOG(FATAL) << "poll failed";
+            return;
+        }
+        const auto nlsockEvents = fds[0].revents;
+
+        if (isSocketBad(nlsockEvents)) {
+            LOG(ERROR) << "Netlink socket is bad";
+            mRunning = false;
+            return;
+        }
+        if (!isSocketReadable(nlsockEvents)) continue;
+
+        const auto [msgMaybe, sa] = mNlSocket->receiveFrom();
+        if (!msgMaybe.has_value()) {
+            LOG(ERROR) << "Failed to receive Netlink data!";
+            mRunning = false;
+            return;
+        }
+        const auto msg = *msgMaybe;
+        if (!msg.firstOk()) {
+            LOG(ERROR) << "Netlink packet is malformed!";
+            // Test messages might be empty, this isn't fatal.
+            continue;
+        }
+        if constexpr (kSuperVerbose) {
+            LOG(VERBOSE) << "[" << mClientName
+                         << "] nlMsg: " << nl::toString(msg, NETLINK_GENERIC);
+        }
+
+        uint32_t destinationPid = 0;
+        if (sa.nl_pid == 0) {
+            destinationPid = mClientNlPid;
+        }
+
+        if (!mNlSocket->send(msg, destinationPid)) {
+            LOG(ERROR) << "Failed to send Netlink message!";
+            mRunning = false;
+            return;
+        }
+    }
+    LOG(VERBOSE) << "[" << mClientName << "] Exiting relay thread!";
+}
+
+bool InterceptorRelay::start() {
+    if (mRunning) {
+        LOG(ERROR)
+            << "Can't relay messages: InterceptorRelay is already running!";
+        return false;
+    }
+    if (mRelayThread.joinable()) {
+        LOG(ERROR) << "relay thread is already running!";
+        return false;
+    }
+    if (!mNlSocket.has_value()) {
+        LOG(ERROR) << "Netlink socket not initialized!";
+        return false;
+    }
+
+    mRunning = true;
+    mRelayThread = std::thread(&InterceptorRelay::relayMessages, this);
+
+    LOG(VERBOSE) << "Relay threads initialized";
+    return true;
+}
+
+bool InterceptorRelay::subscribeGroup(uint32_t nlGroup) {
+    return mNlSocket->addMembership(nlGroup);
+}
+
+bool InterceptorRelay::unsubscribeGroup(uint32_t nlGroup) {
+    return mNlSocket->dropMembership(nlGroup);
+}
+
+}  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.h b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.h
new file mode 100644
index 0000000..0178c90
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <libnl++/Socket.h>
+
+#include <mutex>
+#include <thread>
+
+namespace android::nlinterceptor {
+
+class InterceptorRelay {
+   public:
+    /**
+     * Wrapper around the netlink socket and thread which relays messages.
+     *
+     * \param nlFamily - netlink family to use for the netlink socket.
+     * \param clientNlPid - pid of the client netlink socket.
+     * \param clientName - name of the client to be used for debugging.
+     */
+    InterceptorRelay(uint32_t nlFamily, uint32_t clientNlPid,
+                     const std::string& clientName);
+
+    /**
+     * Stops the relay thread if running and destroys itself.
+     */
+    ~InterceptorRelay();
+
+    /**
+     * Returns the PID of the internal Netlink socket.
+     *
+     * \return value of PID,
+     */
+    uint32_t getPid();
+
+    /**
+     * Spawns relay thread.
+     */
+    bool start();
+
+    /**
+     * Subscribes the internal socket to a single Netlink multicast group.
+     *
+     * \param nlGroup - Netlink group to subscribe to.
+     * \returns - true for success, false for failure.
+     */
+    bool subscribeGroup(uint32_t nlGroup);
+
+    /**
+     * Unsubscribes the internal socket from a single Netlink multicast group.
+     *
+     * \param nlGroup - Netlink group to unsubscribe from.
+     * \returns - true for success, false for failure.
+     */
+    bool unsubscribeGroup(uint32_t nlGroup);
+
+   private:
+    std::string mClientName;  ///< Name of client (Wificond, for example).
+    std::optional<nl::Socket> mNlSocket;
+    const uint32_t mClientNlPid = 0;  ///< pid of client NL socket.
+
+    /**
+     * If set to true, the relay thread should be running. Setting this to false
+     * stops the relay thread.
+     */
+    std::atomic_bool mRunning = false;
+
+    /**
+     * Reads incoming Netlink messages destined for mNlSocket. If from the
+     * kernel, the message is relayed to the client specified in the
+     * constructor. Otherwise, the message is relayed to the kernel. This will
+     * run as long as mRunning is set to true.
+     */
+    void relayMessages();
+
+    std::thread mRelayThread;
+};
+
+}  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/aidl/default/NetlinkInterceptor.cpp b/wifi/netlinkinterceptor/aidl/default/NetlinkInterceptor.cpp
new file mode 100644
index 0000000..908ecf2
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/NetlinkInterceptor.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NetlinkInterceptor.h"
+
+#include <android-base/logging.h>
+#include <libnl++/Socket.h>
+
+namespace android::nlinterceptor {
+
+ndk::ScopedAStatus NetlinkInterceptor::createSocket(
+    int32_t nlFamilyAidl, int32_t clientNlPidAidl,
+    const std::string& clientName, AidlInterceptedSocket* interceptedSocket) {
+    auto nlFamily = static_cast<uint32_t>(nlFamilyAidl);
+    auto clientNlPid = static_cast<uint32_t>(clientNlPidAidl);
+    uint32_t interceptorNlPid = 0;
+
+    std::unique_ptr<InterceptorRelay> interceptor =
+        std::make_unique<InterceptorRelay>(nlFamily, clientNlPid, clientName);
+
+    interceptorNlPid = interceptor->getPid();
+
+    if (interceptorNlPid == 0) {
+        LOG(ERROR) << "Failed to create a Netlink socket for " << clientName
+                   << ", " << nlFamily << ":" << clientNlPid;
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+
+    if (mClientMap.find({nlFamily, interceptorNlPid}) != mClientMap.end()) {
+        LOG(ERROR) << "A socket with pid " << interceptorNlPid
+                   << " already exists!";
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+
+    if (!interceptor->start()) {
+        LOG(ERROR) << "Failed to start interceptor thread!";
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+
+    if (!mClientMap
+             .emplace(InterceptedSocket(nlFamily, interceptorNlPid),
+                      std::move(interceptor))
+             .second) {
+        // If this happens, it is very bad.
+        LOG(FATAL) << "Failed to insert interceptor instance with pid "
+                   << interceptorNlPid << " into map!";
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+
+    interceptedSocket->nlFamily = nlFamily;
+    interceptedSocket->portId = interceptorNlPid;
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus NetlinkInterceptor::closeSocket(
+    const AidlInterceptedSocket& interceptedSocket) {
+    InterceptedSocket sock(interceptedSocket);
+
+    auto interceptorIt = mClientMap.find(sock);
+    if (interceptorIt == mClientMap.end()) {
+        LOG(ERROR) << "closeSocket Failed! No such socket " << sock;
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+    mClientMap.erase(interceptorIt);
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus NetlinkInterceptor::subscribeGroup(
+    const AidlInterceptedSocket& interceptedSocket, int32_t nlGroupAidl) {
+    InterceptedSocket sock(interceptedSocket);
+    auto nlGroup = static_cast<uint32_t>(nlGroupAidl);
+
+    auto interceptorIt = mClientMap.find(sock);
+    if (interceptorIt == mClientMap.end()) {
+        LOG(ERROR) << "subscribeGroup failed! No such socket " << sock;
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+
+    auto& interceptor = interceptorIt->second;
+    if (!interceptor->subscribeGroup(nlGroup)) {
+        LOG(ERROR) << "Failed to subscribe " << sock << " to " << nlGroup;
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus NetlinkInterceptor::unsubscribeGroup(
+    const AidlInterceptedSocket& interceptedSocket, int32_t nlGroupAidl) {
+    InterceptedSocket sock(interceptedSocket);
+    auto nlGroup = static_cast<uint32_t>(nlGroupAidl);
+
+    auto interceptorIt = mClientMap.find(sock);
+    if (interceptorIt == mClientMap.end()) {
+        LOG(ERROR) << "unsubscribeGroup failed! No such socket " << sock;
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+
+    auto& interceptor = interceptorIt->second;
+    if (!interceptor->unsubscribeGroup(nlGroup)) {
+        LOG(ERROR) << "Failed to unsubscribe " << sock << " from " << nlGroup;
+        return ndk::ScopedAStatus(AStatus_fromStatus(::android::UNKNOWN_ERROR));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+}  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/aidl/default/NetlinkInterceptor.h b/wifi/netlinkinterceptor/aidl/default/NetlinkInterceptor.h
new file mode 100644
index 0000000..8345654
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/NetlinkInterceptor.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/net/nlinterceptor/BnInterceptor.h>
+#include <libnlinterceptor/libnlinterceptor.h>
+
+#include <map>
+
+#include "InterceptorRelay.h"
+
+namespace android::nlinterceptor {
+
+class NetlinkInterceptor
+    : public ::aidl::android::hardware::net::nlinterceptor::BnInterceptor {
+    using ClientMap =
+        std::map<::android::nlinterceptor::InterceptedSocket,
+                 std::unique_ptr<::android::nlinterceptor::InterceptorRelay>>;
+
+    using AidlInterceptedSocket =
+        ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket;
+
+   public:
+    ndk::ScopedAStatus createSocket(
+        int32_t nlFamily, int32_t clientNlPid, const std::string& clientName,
+        AidlInterceptedSocket* interceptedSocket) override;
+
+    ndk::ScopedAStatus closeSocket(
+        const AidlInterceptedSocket& interceptedSocket) override;
+
+    ndk::ScopedAStatus subscribeGroup(
+        const AidlInterceptedSocket& interceptedSocket,
+        int32_t nlGroup) override;
+
+    ndk::ScopedAStatus unsubscribeGroup(
+        const AidlInterceptedSocket& interceptedSocket,
+        int32_t nlGroup) override;
+
+   private:
+    ClientMap mClientMap;
+};
+
+}  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/aidl/default/OWNERS b/wifi/netlinkinterceptor/aidl/default/OWNERS
new file mode 100644
index 0000000..b738dac
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/OWNERS
@@ -0,0 +1,2 @@
+chrisweir@google.com
+twasilczyk@google.com
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc b/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc
new file mode 100644
index 0000000..353cb27
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc
@@ -0,0 +1,4 @@
+service nlinterceptor /vendor/bin/hw/android.hardware.net.nlinterceptor-service.default
+    class hal
+    user root
+    group system inet
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.xml b/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.xml
new file mode 100644
index 0000000..d7d257e
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.xml
@@ -0,0 +1,9 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.net.nlinterceptor</name>
+        <interface>
+            <name>IInterceptor</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/wifi/netlinkinterceptor/aidl/default/service.cpp b/wifi/netlinkinterceptor/aidl/default/service.cpp
new file mode 100644
index 0000000..2aec3a5
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/service.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "NetlinkInterceptor.h"
+
+namespace android::nlinterceptor {
+using namespace std::string_literals;
+
+static void service() {
+    base::SetDefaultTag("nlinterceptor");
+    base::SetMinimumLogSeverity(base::VERBOSE);
+    LOG(DEBUG) << "Netlink Interceptor service starting...";
+
+    // TODO(202549296): Sometimes this causes an Address Sanitizer error.
+    auto interceptor = ndk::SharedRefBase::make<NetlinkInterceptor>();
+    const auto instance = NetlinkInterceptor::descriptor + "/default"s;
+    const auto status = AServiceManager_addService(
+        interceptor->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    LOG(FATAL) << "Netlink Interceptor has stopped";
+}
+
+}  // namespace android::nlinterceptor
+
+int main() {
+    ::android::nlinterceptor::service();
+    return 0;
+}
diff --git a/wifi/netlinkinterceptor/aidl/default/util.cpp b/wifi/netlinkinterceptor/aidl/default/util.cpp
new file mode 100644
index 0000000..c734747
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/util.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util.h"
+
+#include <poll.h>
+
+namespace android::nlinterceptor {
+
+bool isSocketReadable(const short revents) { return 0 != (revents & POLLIN); }
+
+bool isSocketBad(const short revents) {
+    return 0 != (revents & (POLLERR | POLLHUP | POLLNVAL));
+}
+
+}  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/aidl/default/util.h b/wifi/netlinkinterceptor/aidl/default/util.h
new file mode 100644
index 0000000..9b8ec63
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/util.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+
+#include <functional>
+
+namespace android::nlinterceptor {
+
+/**
+ * Handy-dandy helper to get the size of a statically initialized array.
+ *
+ * \param N the array to get the size of.
+ * \return the size of the array.
+ */
+template <typename T, size_t N>
+size_t countof(T (&)[N]) {
+    return N;
+}
+
+/**
+ * Helper to check if socket is readable (POLLIN is set).
+ *
+ * \param revents pollfd.revents value to check.
+ * \return true if socket is ready to read.
+ */
+bool isSocketReadable(short revents);
+
+/**
+ * Helper to check if socket is bad (POLLERR, POLLHUP or POLLNVAL is set).
+ *
+ * \param revents pollfd.revents value to check.
+ * \return true if socket is bad.
+ */
+bool isSocketBad(short revents);
+
+}  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/Android.bp b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
new file mode 100644
index 0000000..00cae32
--- /dev/null
+++ b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
@@ -0,0 +1,65 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+    name: "nlinterceptor@defaults",
+    cpp_std: "experimental",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wsuggest-override",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libutils",
+    ],
+    sanitize: {
+        address: true,
+        undefined: true,
+        all_undefined: true,
+        fuzzer: true,
+        cfi: true,
+        integer_overflow: true,
+        scs: true,
+    },
+    strip: {
+        keep_symbols_and_debug_frame: true,
+    },
+}
+
+cc_library_static {
+    name: "libnlinterceptor",
+    defaults: ["nlinterceptor@defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.net.nlinterceptor-V1-ndk",
+        "libbinder_ndk",
+    ],
+    srcs: [
+        "libnlinterceptor.cpp",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/include/libnlinterceptor/libnlinterceptor.h b/wifi/netlinkinterceptor/libnlinterceptor/include/libnlinterceptor/libnlinterceptor.h
new file mode 100644
index 0000000..ac8653e
--- /dev/null
+++ b/wifi/netlinkinterceptor/libnlinterceptor/include/libnlinterceptor/libnlinterceptor.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+
+#include <aidl/android/hardware/net/nlinterceptor/InterceptedSocket.h>
+#include <android-base/unique_fd.h>
+#include <linux/netlink.h>
+
+#include <optional>
+#include <string>
+
+namespace android::nlinterceptor {
+
+/**
+ * Wrapper structure to uniquely identifies a socket that Netlink Interceptor
+ * has allocated for us.
+ */
+struct InterceptedSocket {
+    uint32_t nlFamily;
+    uint32_t portId;
+
+    InterceptedSocket(
+        ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket sock);
+    InterceptedSocket(uint32_t nlFamily, uint32_t portId);
+
+    bool operator<(const InterceptedSocket& other) const;
+    operator sockaddr_nl() const;
+    operator ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket()
+        const;
+};
+
+/**
+ * Output stream operator for InterceptedSocket
+ */
+std::ostream& operator<<(std::ostream& os, const InterceptedSocket& sock);
+
+/**
+ * Checks if an instance Netlink Interceptor exists.
+ *
+ * \return true if supported, false if not.
+ */
+bool isEnabled();
+
+/**
+ * Asks Netlink Interceptor to allocate a socket to which we can send Netlink
+ * traffic.
+ *
+ * \param clientSocket - File descriptor for the client's Netlink socket.
+ * \param clientName - Human readable name of the client application.
+ * \return Identifier for the socket created by Netlink Interceptor, nullopt on
+ * error.
+ */
+std::optional<InterceptedSocket> createSocket(base::borrowed_fd clientSocket,
+                                              const std::string& clientName);
+
+/**
+ * Asks Netlink Interceptor to close a socket that it created for us previously,
+ * if it exists.
+ *
+ * \param sock - Identifier for the socket created by Netlink Interceptor.
+ */
+void closeSocket(const InterceptedSocket& sock);
+
+/**
+ * Asks Netlink Interceptor to subscribe a socket that it created for us
+ * previously to a specified multicast group.
+ *
+ * \param sock - Identifier for the socket created by Netlink Interceptor.
+ * \param group - A single Netlink multicast group for which we would like to
+ * receive events.
+ * \return true for success, false if something went wrong.
+ */
+bool subscribe(const InterceptedSocket& sock, uint32_t group);
+
+/**
+ * Asks Netlink Interceptor to unsubscribe a socket that it created for us
+ * previously from a specified multicast group.
+ *
+ * \param sock - Identifier for the socket created by Netlink Interceptor.
+ * \param group - A single Netlink multicast group for which we no longer wish
+ * to receive events.
+ * \return true for success, false if something went wrong.
+ */
+bool unsubscribe(const InterceptedSocket& sock, uint32_t group);
+}  // namespace android::nlinterceptor
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// C wrappers for libnlinterceptor
+struct android_nlinterceptor_InterceptedSocket {
+    uint32_t nlFamily;
+    uint32_t portId;
+};
+
+bool android_nlinterceptor_isEnabled();
+
+bool android_nlinterceptor_createSocket(
+    int clientSocketFd, const char* clientName,
+    struct android_nlinterceptor_InterceptedSocket* interceptedSocket);
+
+void android_nlinterceptor_closeSocket(
+    const struct android_nlinterceptor_InterceptedSocket* sock);
+
+bool android_nlinterceptor_subscribe(
+    const struct android_nlinterceptor_InterceptedSocket* sock, uint32_t group);
+
+bool android_nlinterceptor_unsubscribe(
+    const struct android_nlinterceptor_InterceptedSocket* sock, uint32_t group);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/libnlinterceptor.cpp b/wifi/netlinkinterceptor/libnlinterceptor/libnlinterceptor.cpp
new file mode 100644
index 0000000..575f900
--- /dev/null
+++ b/wifi/netlinkinterceptor/libnlinterceptor/libnlinterceptor.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/net/nlinterceptor/IInterceptor.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android/binder_manager.h>
+#include <libnlinterceptor/libnlinterceptor.h>
+#include <linux/netlink.h>
+
+#include <mutex>
+
+namespace android::nlinterceptor {
+using namespace std::string_literals;
+using namespace ::aidl::android::hardware::net::nlinterceptor;
+using base::borrowed_fd;
+using AidlInterceptedSocket =
+    ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket;
+
+static const auto kServiceName = IInterceptor::descriptor + "/default"s;
+
+InterceptedSocket::InterceptedSocket(
+    ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket sock)
+    : nlFamily(sock.nlFamily), portId(sock.portId) {}
+
+InterceptedSocket::InterceptedSocket(uint32_t nlFamily, uint32_t portId)
+    : nlFamily(nlFamily), portId(portId) {}
+
+std::ostream& operator<<(std::ostream& os, const InterceptedSocket& sock) {
+    return os << "family: " << sock.nlFamily << ", portId: " << sock.portId;
+}
+
+bool InterceptedSocket::operator<(const InterceptedSocket& other) const {
+    if (nlFamily != other.nlFamily) {
+        return nlFamily < other.nlFamily;
+    }
+    return portId < other.portId;
+}
+
+InterceptedSocket::operator sockaddr_nl() const {
+    return {
+        .nl_family = AF_NETLINK,
+        .nl_pad = 0,
+        .nl_pid = portId,
+        .nl_groups = 0,
+    };
+}
+
+InterceptedSocket::operator AidlInterceptedSocket() const {
+    return {
+        .nlFamily = static_cast<int32_t>(nlFamily),
+        .portId = static_cast<int32_t>(portId),
+    };
+}
+
+bool isEnabled() {
+    static std::mutex supportedMutex;
+    static std::optional<bool> interceptorSupported;
+    // Avoid querying service manager when we can cache the result.
+    if (interceptorSupported.has_value()) return *interceptorSupported;
+    std::lock_guard lock(supportedMutex);
+    if (interceptorSupported.has_value()) return *interceptorSupported;
+
+    if (!AServiceManager_isDeclared(kServiceName.c_str())) {
+        interceptorSupported = false;
+        return false;
+    }
+    interceptorSupported = true;
+    return true;
+}
+
+static IInterceptor& getInstance() {
+    static std::mutex instanceMutex;
+    static std::shared_ptr<IInterceptor> interceptorInstance;
+    CHECK(isEnabled()) << "Can't getInstance! Interceptor not supported!";
+    // Don't overwrite the pointer once we've acquired it.
+    if (interceptorInstance != nullptr) return *interceptorInstance;
+    std::lock_guard lock(instanceMutex);
+    if (interceptorInstance != nullptr) return *interceptorInstance;
+    interceptorInstance = IInterceptor::fromBinder(
+        ndk::SpAIBinder(AServiceManager_waitForService(kServiceName.c_str())));
+    CHECK(interceptorInstance != nullptr)
+        << "Failed to get Netlink Interceptor service!";
+    return *interceptorInstance;
+}
+
+std::optional<InterceptedSocket> createSocket(borrowed_fd clientSocket,
+                                              const std::string& clientName) {
+    sockaddr_nl nladdr = {};
+    socklen_t nlsize = sizeof(nladdr);
+    if (getsockname(clientSocket.get(), reinterpret_cast<sockaddr*>(&nladdr),
+                    &nlsize) < 0) {
+        PLOG(ERROR) << "Failed to get pid of fd passed by " << clientName;
+        return std::nullopt;
+    }
+
+    ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket
+        interceptedSocket;
+    auto aidlStatus = getInstance().createSocket(
+        nladdr.nl_family, nladdr.nl_pid, clientName, &interceptedSocket);
+    if (!aidlStatus.isOk()) {
+        return std::nullopt;
+    }
+
+    return InterceptedSocket{nladdr.nl_family,
+                             uint32_t(interceptedSocket.portId)};
+}
+
+void closeSocket(const InterceptedSocket& sock) {
+    auto aidlStatus = getInstance().closeSocket(sock);
+    if (!aidlStatus.isOk()) {
+        LOG(ERROR) << "Failed to close socket with pid = " << sock.portId;
+    }
+}
+
+bool subscribe(const InterceptedSocket& sock, uint32_t group) {
+    auto aidlStatus = getInstance().subscribeGroup(sock, group);
+    return aidlStatus.isOk();
+}
+
+bool unsubscribe(const InterceptedSocket& sock, uint32_t group) {
+    auto aidlStatus = getInstance().unsubscribeGroup(sock, group);
+    return aidlStatus.isOk();
+}
+
+extern "C" bool android_nlinterceptor_isEnabled() { return isEnabled(); }
+
+extern "C" bool android_nlinterceptor_createSocket(
+    int clientSocketFd, const char* clientName,
+    android_nlinterceptor_InterceptedSocket* interceptedSocket) {
+    if (!clientName || clientSocketFd <= 0) return false;
+    const auto maybeSocket =
+        createSocket(borrowed_fd(clientSocketFd), clientName);
+    if (!maybeSocket) return false;
+    *interceptedSocket = {.nlFamily = maybeSocket->nlFamily,
+                          .portId = maybeSocket->portId};
+    return true;
+}
+
+extern "C" void android_nlinterceptor_closeSocket(
+    const android_nlinterceptor_InterceptedSocket* sock) {
+    if (!sock) {
+        LOG(ERROR) << "Can't close socket identified by a null pointer!";
+        return;
+    }
+    closeSocket({sock->nlFamily, sock->portId});
+}
+
+extern "C" bool android_nlinterceptor_subscribe(
+    const android_nlinterceptor_InterceptedSocket* sock, uint32_t group) {
+    if (!sock) return false;
+    return subscribe({sock->nlFamily, sock->portId}, group);
+}
+
+extern "C" bool android_nlinterceptor_unsubscribe(
+    const android_nlinterceptor_InterceptedSocket* sock, uint32_t group) {
+    if (!sock) return false;
+    return unsubscribe({sock->nlFamily, sock->portId}, group);
+}
+
+}  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/vts/OWNERS b/wifi/netlinkinterceptor/vts/OWNERS
new file mode 100644
index 0000000..b738dac
--- /dev/null
+++ b/wifi/netlinkinterceptor/vts/OWNERS
@@ -0,0 +1,2 @@
+chrisweir@google.com
+twasilczyk@google.com
diff --git a/wifi/netlinkinterceptor/vts/functional/Android.bp b/wifi/netlinkinterceptor/vts/functional/Android.bp
new file mode 100644
index 0000000..33284e8
--- /dev/null
+++ b/wifi/netlinkinterceptor/vts/functional/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalNetlinkInterceptorV1_0Test",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    cpp_std: "experimental",
+    srcs: [
+        "interceptor_aidl_test.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.net.nlinterceptor-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "libgmock",
+        "android.hardware.automotive.can@libnetdevice",
+        "libnl++",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/wifi/netlinkinterceptor/vts/functional/interceptor_aidl_test.cpp b/wifi/netlinkinterceptor/vts/functional/interceptor_aidl_test.cpp
new file mode 100644
index 0000000..b26d8ec
--- /dev/null
+++ b/wifi/netlinkinterceptor/vts/functional/interceptor_aidl_test.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/net/nlinterceptor/IInterceptor.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <libnetdevice/libnetdevice.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
+#include <libnl++/printer.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <chrono>
+#include <thread>
+
+using aidl::android::hardware::net::nlinterceptor::IInterceptor;
+using AidlInterceptedSocket =
+    ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket;
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+
+class InterceptorAidlTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        android::base::SetDefaultTag("InterceptorAidlTest");
+        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+        const auto instance = IInterceptor::descriptor + "/default"s;
+        mNlInterceptorService = IInterceptor::fromBinder(
+            ndk::SpAIBinder(AServiceManager_getService(instance.c_str())));
+
+        ASSERT_NE(mNlInterceptorService, nullptr);
+        mSocket = std::make_unique<android::nl::Socket>(NETLINK_ROUTE);
+        ASSERT_TRUE(mSocket->getPid().has_value());
+
+        // If the test broke last run, clean up our mess, don't worry about "no
+        // such device".
+        if (android::netdevice::del(mTestIfaceName)) {
+            LOG(WARNING) << "Test interface wasn't cleaned up on previous run!";
+        }
+    }
+
+    void multicastReceiver();
+
+    std::shared_ptr<IInterceptor> mNlInterceptorService;
+    std::unique_ptr<android::nl::Socket> mSocket;
+    bool mRunning;
+    bool mGotMulticast;
+    const std::string mTestIfaceName = "interceptorvts0";
+};
+
+TEST_P(InterceptorAidlTest, createSocketTest) {
+    // Ask IInterceptor for a socket.
+    AidlInterceptedSocket interceptedSocket;
+    auto aidlStatus = mNlInterceptorService->createSocket(
+        NETLINK_ROUTE, *(mSocket->getPid()), "createSocketTest",
+        &interceptedSocket);
+    ASSERT_TRUE(aidlStatus.isOk());
+    ASSERT_NE(interceptedSocket.portId, 0);
+    uint32_t interceptorPid = interceptedSocket.portId;
+
+    // Ask the kernel to tell us what interfaces are available.
+    android::nl::MessageFactory<rtgenmsg> req(RTM_GETLINK,
+                                              NLM_F_REQUEST | NLM_F_DUMP);
+    req->rtgen_family = AF_PACKET;
+    sockaddr_nl sa = {.nl_family = AF_NETLINK,
+                      .nl_pad = 0,
+                      .nl_pid = interceptorPid,
+                      .nl_groups = 0};
+    EXPECT_TRUE(mSocket->send(req, sa));
+
+    // We'll likely get back several messages, as indicated by the MULTI flag.
+    unsigned received = 0;
+    for (const auto msg : *mSocket) {
+        ASSERT_NE(msg->nlmsg_type, NLMSG_ERROR);
+        ++received;
+        break;
+        if (msg->nlmsg_type == NLMSG_DONE) {
+            // TODO(202548749): NLMSG_DONE on NETLINK_ROUTE doesn't work?
+            break;
+        }
+    }
+    ASSERT_GE(received, 1);
+
+    // Close the socket and make sure it's stopped working.
+    aidlStatus = mNlInterceptorService->closeSocket(interceptedSocket);
+    EXPECT_TRUE(aidlStatus.isOk());
+    EXPECT_FALSE(mSocket->send(req, sa));
+}
+
+static bool isSocketReadable(const short revents) {
+    return 0 != (revents & POLLIN);
+}
+
+static bool isSocketBad(const short revents) {
+    return 0 != (revents & (POLLERR | POLLHUP | POLLNVAL));
+}
+
+void InterceptorAidlTest::multicastReceiver() {
+    pollfd fds[] = {
+        mSocket->preparePoll(POLLIN),
+    };
+    while (mRunning) {
+        if (poll(fds, 1, 300) < 0) {
+            PLOG(FATAL) << "poll failed";
+            return;
+        }
+        const auto nlsockEvents = fds[0].revents;
+        ASSERT_FALSE(isSocketBad(nlsockEvents));
+        if (!isSocketReadable(nlsockEvents)) continue;
+
+        const auto [msgMaybe, sa] = mSocket->receiveFrom();
+        ASSERT_TRUE(msgMaybe.has_value());
+        auto msg = *msgMaybe;
+
+        // Multicast messages have 0 for their pid and sequence number.
+        if (msg->nlmsg_pid == 0 && msg->nlmsg_seq == 0) {
+            mGotMulticast = true;
+        }
+    }
+}
+
+TEST_P(InterceptorAidlTest, subscribeGroupTest) {
+    // Ask IInterceptor for a socket.
+    AidlInterceptedSocket interceptedSocket;
+    auto aidlStatus = mNlInterceptorService->createSocket(
+        NETLINK_ROUTE, *(mSocket->getPid()), "subscribeGroupTest",
+        &interceptedSocket);
+    ASSERT_TRUE(aidlStatus.isOk());
+    ASSERT_TRUE(interceptedSocket.portId != 0);
+
+    // Listen for interface up/down events.
+    aidlStatus =
+        mNlInterceptorService->subscribeGroup(interceptedSocket, RTNLGRP_LINK);
+    ASSERT_TRUE(aidlStatus.isOk());
+
+    // Start a thread to receive a multicast
+    mRunning = true;
+    mGotMulticast = false;
+    std::thread successfulReceiver(&InterceptorAidlTest::multicastReceiver,
+                                   this);
+
+    // TODO(201695162): use futures with wait_for instead of a sleep_for().
+    std::this_thread::sleep_for(50ms);
+    // create a network interface and bring it up to trigger a multicast event.
+    ASSERT_TRUE(android::netdevice::add(mTestIfaceName, /*type=*/"dummy"));
+    ASSERT_TRUE(android::netdevice::up(mTestIfaceName));
+    std::this_thread::sleep_for(50ms);
+    EXPECT_TRUE(mGotMulticast);
+    mRunning = false;
+    successfulReceiver.join();
+
+    // Stop listening to interface up/down events.
+    aidlStatus = mNlInterceptorService->unsubscribeGroup(interceptedSocket,
+                                                         RTNLGRP_LINK);
+    ASSERT_TRUE(aidlStatus.isOk());
+
+    // This time, we should hear nothing.
+    mGotMulticast = false;
+    mRunning = true;
+    std::thread unsuccessfulReceiver(&InterceptorAidlTest::multicastReceiver,
+                                     this);
+    std::this_thread::sleep_for(50ms);
+    ASSERT_TRUE(android::netdevice::down(mTestIfaceName));
+    ASSERT_TRUE(android::netdevice::del(mTestIfaceName));
+    std::this_thread::sleep_for(50ms);
+    EXPECT_FALSE(mGotMulticast);
+    mRunning = false;
+    unsuccessfulReceiver.join();
+
+    aidlStatus = mNlInterceptorService->closeSocket(interceptedSocket);
+    EXPECT_TRUE(aidlStatus.isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InterceptorAidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, InterceptorAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IInterceptor::descriptor)),
+                         android::PrintInstanceNameToString);
diff --git a/wifi/supplicant/1.3/vts/OWNERS b/wifi/supplicant/1.3/vts/OWNERS
deleted file mode 100644
index 287152d..0000000
--- a/wifi/supplicant/1.3/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/supplicant/OWNERS b/wifi/supplicant/OWNERS
new file mode 100644
index 0000000..7febd60
--- /dev/null
+++ b/wifi/supplicant/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 33618
+arabawy@google.com
+etancohen@google.com
+gbiren@google.com
+lzye@google.com
diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp
new file mode 100644
index 0000000..d00dd21
--- /dev/null
+++ b/wifi/supplicant/aidl/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.wifi.supplicant",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/wifi/supplicant/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.wifi",
+            ],
+            min_sdk_version: "30",
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AnqpData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AnqpData.aidl
new file mode 100644
index 0000000..d8e49d7
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AnqpData.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+parcelable AnqpData {
+  byte[] venueName;
+  byte[] roamingConsortium;
+  byte[] ipAddrTypeAvailability;
+  byte[] naiRealm;
+  byte[] anqp3gppCellularNetwork;
+  byte[] domainName;
+  byte[] venueUrl;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AnqpInfoId.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AnqpInfoId.aidl
new file mode 100644
index 0000000..cc32360
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AnqpInfoId.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum AnqpInfoId {
+  VENUE_NAME = 258,
+  ROAMING_CONSORTIUM = 261,
+  IP_ADDR_TYPE_AVAILABILITY = 262,
+  NAI_REALM = 263,
+  ANQP_3GPP_CELLULAR_NETWORK = 264,
+  DOMAIN_NAME = 268,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AssociationRejectionData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AssociationRejectionData.aidl
new file mode 100644
index 0000000..f6830dc
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AssociationRejectionData.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+parcelable AssociationRejectionData {
+  byte[] ssid;
+  byte[] bssid;
+  android.hardware.wifi.supplicant.StaIfaceStatusCode statusCode;
+  boolean timedOut;
+  boolean isMboAssocDisallowedReasonCodePresent;
+  android.hardware.wifi.supplicant.MboAssocDisallowedReasonCode mboAssocDisallowedReason;
+  boolean isOceRssiBasedAssocRejectAttrPresent;
+  android.hardware.wifi.supplicant.OceRssiBasedAssocRejectAttr oceRssiBasedAssocRejectData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuthAlgMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuthAlgMask.aidl
new file mode 100644
index 0000000..9cd178d
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuthAlgMask.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum AuthAlgMask {
+  OPEN = 1,
+  SHARED = 2,
+  LEAP = 4,
+  SAE = 16,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmData.aidl
new file mode 100644
index 0000000..34d894d
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmData.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable BssTmData {
+  android.hardware.wifi.supplicant.BssTmStatusCode status;
+  android.hardware.wifi.supplicant.BssTmDataFlagsMask flags;
+  int assocRetryDelayMs;
+  android.hardware.wifi.supplicant.MboTransitionReasonCode mboTransitionReason;
+  android.hardware.wifi.supplicant.MboCellularDataConnectionPrefValue mboCellPreference;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl
new file mode 100644
index 0000000..f215f05
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum BssTmDataFlagsMask {
+  WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = 1,
+  WNM_MODE_ABRIDGED = 2,
+  WNM_MODE_DISASSOCIATION_IMMINENT = 4,
+  WNM_MODE_BSS_TERMINATION_INCLUDED = 8,
+  WNM_MODE_ESS_DISASSOCIATION_IMMINENT = 16,
+  MBO_TRANSITION_REASON_CODE_INCLUDED = 32,
+  MBO_ASSOC_RETRY_DELAY_INCLUDED = 64,
+  MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = 128,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmStatusCode.aidl
new file mode 100644
index 0000000..c95825f
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmStatusCode.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum BssTmStatusCode {
+  ACCEPT = 0,
+  REJECT_UNSPECIFIED = 1,
+  REJECT_INSUFFICIENT_BEACON = 2,
+  REJECT_INSUFFICIENT_CAPABITY = 3,
+  REJECT_BSS_TERMINATION_UNDESIRED = 4,
+  REJECT_BSS_TERMINATION_DELAY_REQUEST = 5,
+  REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+  REJECT_NO_SUITABLE_CANDIDATES = 7,
+  REJECT_LEAVING_ESS = 8,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssidChangeReason.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssidChangeReason.aidl
new file mode 100644
index 0000000..1d24579
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssidChangeReason.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum BssidChangeReason {
+  ASSOC_START = 0,
+  ASSOC_COMPLETE = 1,
+  DISASSOC = 2,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BtCoexistenceMode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BtCoexistenceMode.aidl
new file mode 100644
index 0000000..bdc1b4a
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BtCoexistenceMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum BtCoexistenceMode {
+  ENABLED = 0,
+  DISABLED = 1,
+  SENSE = 2,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
new file mode 100644
index 0000000..433b3d80
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable ConnectionCapabilities {
+  android.hardware.wifi.supplicant.WifiTechnology technology;
+  int channelBandwidth;
+  int maxNumberTxSpatialStreams;
+  int maxNumberRxSpatialStreams;
+  android.hardware.wifi.supplicant.LegacyMode legacyMode;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DebugLevel.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DebugLevel.aidl
new file mode 100644
index 0000000..fbfb5b3
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DebugLevel.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DebugLevel {
+  EXCESSIVE = 0,
+  MSGDUMP = 1,
+  DEBUG = 2,
+  INFO = 3,
+  WARNING = 4,
+  ERROR = 5,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppAkm.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppAkm.aidl
new file mode 100644
index 0000000..df2aef8
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppAkm.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppAkm {
+  PSK = 0,
+  PSK_SAE = 1,
+  SAE = 2,
+  DPP = 3,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppCurve.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppCurve.aidl
new file mode 100644
index 0000000..e69da44
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppCurve.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppCurve {
+  PRIME256V1 = 0,
+  SECP384R1 = 1,
+  SECP521R1 = 2,
+  BRAINPOOLP256R1 = 3,
+  BRAINPOOLP384R1 = 4,
+  BRAINPOOLP512R1 = 5,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppEventType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppEventType.aidl
new file mode 100644
index 0000000..9e394fc
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppEventType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppEventType {
+  CONFIGURATION_SENT = 0,
+  CONFIGURATION_APPLIED = 1,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppFailureCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppFailureCode.aidl
new file mode 100644
index 0000000..7e7c806
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppFailureCode.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppFailureCode {
+  INVALID_URI = 0,
+  AUTHENTICATION = 1,
+  NOT_COMPATIBLE = 2,
+  CONFIGURATION = 3,
+  BUSY = 4,
+  TIMEOUT = 5,
+  FAILURE = 6,
+  NOT_SUPPORTED = 7,
+  CONFIGURATION_REJECTED = 8,
+  CANNOT_FIND_NETWORK = 9,
+  ENROLLEE_AUTHENTICATION = 10,
+  URI_GENERATION = 11,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppNetRole.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppNetRole.aidl
new file mode 100644
index 0000000..c6d3522
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppNetRole.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppNetRole {
+  STA = 0,
+  AP = 1,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppProgressCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppProgressCode.aidl
new file mode 100644
index 0000000..f0618a5
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppProgressCode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppProgressCode {
+  AUTHENTICATION_SUCCESS = 0,
+  RESPONSE_PENDING = 1,
+  CONFIGURATION_SENT_WAITING_RESPONSE = 2,
+  CONFIGURATION_ACCEPTED = 3,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppResponderBootstrapInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppResponderBootstrapInfo.aidl
new file mode 100644
index 0000000..8b6492b
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppResponderBootstrapInfo.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable DppResponderBootstrapInfo {
+  int bootstrapId;
+  int listenChannel;
+  String uri;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapErrorCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapErrorCode.aidl
new file mode 100644
index 0000000..2cf81d9
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapErrorCode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum EapErrorCode {
+  SIM_GENERAL_FAILURE_AFTER_AUTH = 0,
+  SIM_TEMPORARILY_DENIED = 1026,
+  SIM_NOT_SUBSCRIBED = 1031,
+  SIM_GENERAL_FAILURE_BEFORE_AUTH = 16384,
+  SIM_VENDOR_SPECIFIC_EXPIRED_CERT = 16385,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapMethod.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapMethod.aidl
new file mode 100644
index 0000000..4ab23af
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapMethod.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum EapMethod {
+  PEAP = 0,
+  TLS = 1,
+  TTLS = 2,
+  PWD = 3,
+  SIM = 4,
+  AKA = 5,
+  AKA_PRIME = 6,
+  WFA_UNAUTH_TLS = 7,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapPhase2Method.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapPhase2Method.aidl
new file mode 100644
index 0000000..4bd93a0
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/EapPhase2Method.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum EapPhase2Method {
+  NONE = 0,
+  PAP = 1,
+  MSPAP = 2,
+  MSPAPV2 = 3,
+  GTC = 4,
+  SIM = 5,
+  AKA = 6,
+  AKA_PRIME = 7,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ExtRadioWorkDefaults.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ExtRadioWorkDefaults.aidl
new file mode 100644
index 0000000..cbf1a3e
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ExtRadioWorkDefaults.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum ExtRadioWorkDefaults {
+  TIMEOUT_IN_SECS = 10,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/FreqRange.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/FreqRange.aidl
new file mode 100644
index 0000000..0971d51
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/FreqRange.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+parcelable FreqRange {
+  int min;
+  int max;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupCipherMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupCipherMask.aidl
new file mode 100644
index 0000000..f2da925
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupCipherMask.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum GroupCipherMask {
+  WEP40 = 2,
+  WEP104 = 4,
+  TKIP = 8,
+  CCMP = 16,
+  GTK_NOT_USED = 16384,
+  GCMP_256 = 256,
+  SMS4 = 128,
+  GCMP_128 = 64,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl
new file mode 100644
index 0000000..c24d6cc
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum GroupMgmtCipherMask {
+  BIP_GMAC_128 = 2048,
+  BIP_GMAC_256 = 4096,
+  BIP_CMAC_256 = 8192,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GsmRand.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GsmRand.aidl
new file mode 100644
index 0000000..599a683
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GsmRand.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable GsmRand {
+  byte[] data;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/Hs20AnqpData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/Hs20AnqpData.aidl
new file mode 100644
index 0000000..43b182a
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/Hs20AnqpData.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable Hs20AnqpData {
+  byte[] operatorFriendlyName;
+  byte[] wanMetrics;
+  byte[] connectionCapability;
+  byte[] osuProvidersList;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/Hs20AnqpSubtypes.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/Hs20AnqpSubtypes.aidl
new file mode 100644
index 0000000..270d43b
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/Hs20AnqpSubtypes.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum Hs20AnqpSubtypes {
+  OPERATOR_FRIENDLY_NAME = 3,
+  WAN_METRICS = 4,
+  CONNECTION_CAPABILITY = 5,
+  OSU_PROVIDERS_LIST = 8,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
new file mode 100644
index 0000000..b4371fd
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+interface ISupplicant {
+  android.hardware.wifi.supplicant.ISupplicantP2pIface addP2pInterface(in String ifName);
+  android.hardware.wifi.supplicant.ISupplicantStaIface addStaInterface(in String ifName);
+  android.hardware.wifi.supplicant.DebugLevel getDebugLevel();
+  android.hardware.wifi.supplicant.ISupplicantP2pIface getP2pInterface(in String ifName);
+  android.hardware.wifi.supplicant.ISupplicantStaIface getStaInterface(in String ifName);
+  boolean isDebugShowKeysEnabled();
+  boolean isDebugShowTimestampEnabled();
+  android.hardware.wifi.supplicant.IfaceInfo[] listInterfaces();
+  void registerCallback(in android.hardware.wifi.supplicant.ISupplicantCallback callback);
+  void removeInterface(in android.hardware.wifi.supplicant.IfaceInfo ifaceInfo);
+  void setConcurrencyPriority(in android.hardware.wifi.supplicant.IfaceType type);
+  void setDebugParams(in android.hardware.wifi.supplicant.DebugLevel level, in boolean showTimestamp, in boolean showKeys);
+  oneway void terminate();
+  const int EXT_RADIO_WORK_TIMEOUT_IN_SECS = 10;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
new file mode 100644
index 0000000..72ab3b9
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+interface ISupplicantCallback {
+  oneway void onInterfaceCreated(in String ifaceName);
+  oneway void onInterfaceRemoved(in String ifaceName);
+  oneway void onTerminating();
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
new file mode 100644
index 0000000..ca7be73
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+interface ISupplicantP2pIface {
+  void addBonjourService(in byte[] query, in byte[] response);
+  void addGroup(in boolean persistent, in int persistentNetworkId);
+  void addGroupWithConfig(in byte[] ssid, in String pskPassphrase, in boolean persistent, in int freq, in byte[] peerAddress, in boolean joinExistingGroup);
+  android.hardware.wifi.supplicant.ISupplicantP2pNetwork addNetwork();
+  void addUpnpService(in int version, in String serviceName);
+  void cancelConnect();
+  void cancelServiceDiscovery(in long identifier);
+  void cancelWps(in String groupIfName);
+  void configureExtListen(in int periodInMillis, in int intervalInMillis);
+  String connect(in byte[] peerAddress, in android.hardware.wifi.supplicant.WpsProvisionMethod provisionMethod, in String preSelectedPin, in boolean joinExistingGroup, in boolean persistent, in int goIntent);
+  byte[] createNfcHandoverRequestMessage();
+  byte[] createNfcHandoverSelectMessage();
+  void enableWfd(in boolean enable);
+  void find(in int timeoutInSec);
+  void flush();
+  void flushServices();
+  byte[] getDeviceAddress();
+  boolean getEdmg();
+  android.hardware.wifi.supplicant.P2pGroupCapabilityMask getGroupCapability(in byte[] peerAddress);
+  String getName();
+  android.hardware.wifi.supplicant.ISupplicantP2pNetwork getNetwork(in int id);
+  byte[] getSsid(in byte[] peerAddress);
+  android.hardware.wifi.supplicant.IfaceType getType();
+  void invite(in String groupIfName, in byte[] goDeviceAddress, in byte[] peerAddress);
+  int[] listNetworks();
+  void provisionDiscovery(in byte[] peerAddress, in android.hardware.wifi.supplicant.WpsProvisionMethod provisionMethod);
+  void registerCallback(in android.hardware.wifi.supplicant.ISupplicantP2pIfaceCallback callback);
+  void reinvoke(in int persistentNetworkId, in byte[] peerAddress);
+  void reject(in byte[] peerAddress);
+  void removeBonjourService(in byte[] query);
+  void removeGroup(in String groupIfName);
+  void removeNetwork(in int id);
+  void removeUpnpService(in int version, in String serviceName);
+  void reportNfcHandoverInitiation(in byte[] select);
+  void reportNfcHandoverResponse(in byte[] request);
+  long requestServiceDiscovery(in byte[] peerAddress, in byte[] query);
+  void saveConfig();
+  void setDisallowedFrequencies(in android.hardware.wifi.supplicant.FreqRange[] ranges);
+  void setEdmg(in boolean enable);
+  void setGroupIdle(in String groupIfName, in int timeoutInSec);
+  void setListenChannel(in int channel, in int operatingClass);
+  void setMacRandomization(in boolean enable);
+  void setMiracastMode(in android.hardware.wifi.supplicant.MiracastMode mode);
+  void setPowerSave(in String groupIfName, in boolean enable);
+  void setSsidPostfix(in byte[] postfix);
+  void setWfdDeviceInfo(in byte[] info);
+  void setWfdR2DeviceInfo(in byte[] info);
+  void setWpsConfigMethods(in android.hardware.wifi.supplicant.WpsConfigMethods configMethods);
+  void setWpsDeviceName(in String name);
+  void setWpsDeviceType(in byte[] type);
+  void setWpsManufacturer(in String manufacturer);
+  void setWpsModelName(in String modelName);
+  void setWpsModelNumber(in String modelNumber);
+  void setWpsSerialNumber(in String serialNumber);
+  void startWpsPbc(in String groupIfName, in byte[] bssid);
+  String startWpsPinDisplay(in String groupIfName, in byte[] bssid);
+  void startWpsPinKeypad(in String groupIfName, in String pin);
+  void stopFind();
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
new file mode 100644
index 0000000..826d916
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+interface ISupplicantP2pIfaceCallback {
+  oneway void onDeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo);
+  oneway void onDeviceLost(in byte[] p2pDeviceAddress);
+  oneway void onFindStopped();
+  oneway void onGoNegotiationCompleted(in android.hardware.wifi.supplicant.P2pStatusCode status);
+  oneway void onGoNegotiationRequest(in byte[] srcAddress, in android.hardware.wifi.supplicant.WpsDevPasswordId passwordId);
+  oneway void onGroupFormationFailure(in String failureReason);
+  oneway void onGroupFormationSuccess();
+  oneway void onGroupRemoved(in String groupIfname, in boolean isGroupOwner);
+  oneway void onGroupStarted(in String groupIfname, in boolean isGroupOwner, in byte[] ssid, in int frequency, in byte[] psk, in String passphrase, in byte[] goDeviceAddress, in boolean isPersistent);
+  oneway void onInvitationReceived(in byte[] srcAddress, in byte[] goDeviceAddress, in byte[] bssid, in int persistentNetworkId, in int operatingFrequency);
+  oneway void onInvitationResult(in byte[] bssid, in android.hardware.wifi.supplicant.P2pStatusCode status);
+  oneway void onProvisionDiscoveryCompleted(in byte[] p2pDeviceAddress, in boolean isRequest, in android.hardware.wifi.supplicant.P2pProvDiscStatusCode status, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in String generatedPin);
+  oneway void onR2DeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo);
+  oneway void onServiceDiscoveryResponse(in byte[] srcAddress, in char updateIndicator, in byte[] tlvs);
+  oneway void onStaAuthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
+  oneway void onStaDeauthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
+  oneway void onGroupFrequencyChanged(in String groupIfname, in int frequency);
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pNetwork.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pNetwork.aidl
new file mode 100644
index 0000000..ef72724
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pNetwork.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+interface ISupplicantP2pNetwork {
+  byte[] getBssid();
+  android.hardware.wifi.supplicant.MacAddress[] getClientList();
+  int getId();
+  String getInterfaceName();
+  byte[] getSsid();
+  android.hardware.wifi.supplicant.IfaceType getType();
+  boolean isCurrent();
+  boolean isGroupOwner();
+  boolean isPersistent();
+  void setClientList(in android.hardware.wifi.supplicant.MacAddress[] clients);
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
new file mode 100644
index 0000000..ca40379
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+interface ISupplicantStaIface {
+  int addDppPeerUri(in String uri);
+  int addExtRadioWork(in String name, in int freqInMhz, in int timeoutInSec);
+  android.hardware.wifi.supplicant.ISupplicantStaNetwork addNetwork();
+  void addRxFilter(in android.hardware.wifi.supplicant.RxFilterType type);
+  void cancelWps();
+  void disconnect();
+  void enableAutoReconnect(in boolean enable);
+  void filsHlpAddRequest(in byte[] dst_mac, in byte[] pkt);
+  void filsHlpFlushRequest();
+  android.hardware.wifi.supplicant.DppResponderBootstrapInfo generateDppBootstrapInfoForResponder(in byte[] macAddress, in String deviceInfo, in android.hardware.wifi.supplicant.DppCurve curve);
+  android.hardware.wifi.supplicant.ConnectionCapabilities getConnectionCapabilities();
+  android.hardware.wifi.supplicant.KeyMgmtMask getKeyMgmtCapabilities();
+  byte[] getMacAddress();
+  String getName();
+  android.hardware.wifi.supplicant.ISupplicantStaNetwork getNetwork(in int id);
+  android.hardware.wifi.supplicant.IfaceType getType();
+  android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask getWpaDriverCapabilities();
+  void initiateAnqpQuery(in byte[] macAddress, in android.hardware.wifi.supplicant.AnqpInfoId[] infoElements, in android.hardware.wifi.supplicant.Hs20AnqpSubtypes[] subTypes);
+  void initiateHs20IconQuery(in byte[] macAddress, in String fileName);
+  void initiateTdlsDiscover(in byte[] macAddress);
+  void initiateTdlsSetup(in byte[] macAddress);
+  void initiateTdlsTeardown(in byte[] macAddress);
+  void initiateVenueUrlAnqpQuery(in byte[] macAddress);
+  int[] listNetworks();
+  void reassociate();
+  void reconnect();
+  void registerCallback(in android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback callback);
+  void removeDppUri(in int id);
+  void removeExtRadioWork(in int id);
+  void removeNetwork(in int id);
+  void removeRxFilter(in android.hardware.wifi.supplicant.RxFilterType type);
+  void setBtCoexistenceMode(in android.hardware.wifi.supplicant.BtCoexistenceMode mode);
+  void setBtCoexistenceScanModeEnabled(in boolean enable);
+  void setCountryCode(in byte[] code);
+  void setExternalSim(in boolean useExternalSim);
+  void setMboCellularDataStatus(in boolean available);
+  void setPowerSave(in boolean enable);
+  void setSuspendModeEnabled(in boolean enable);
+  void setWpsConfigMethods(in android.hardware.wifi.supplicant.WpsConfigMethods configMethods);
+  void setWpsDeviceName(in String name);
+  void setWpsDeviceType(in byte[] type);
+  void setWpsManufacturer(in String manufacturer);
+  void setWpsModelName(in String modelName);
+  void setWpsModelNumber(in String modelNumber);
+  void setWpsSerialNumber(in String serialNumber);
+  void startDppConfiguratorInitiator(in int peerBootstrapId, in int ownBootstrapId, in String ssid, in String password, in String psk, in android.hardware.wifi.supplicant.DppNetRole netRole, in android.hardware.wifi.supplicant.DppAkm securityAkm);
+  void startDppEnrolleeInitiator(in int peerBootstrapId, in int ownBootstrapId);
+  void startDppEnrolleeResponder(in int listenChannel);
+  void startRxFilter();
+  void startWpsPbc(in byte[] bssid);
+  String startWpsPinDisplay(in byte[] bssid);
+  void startWpsPinKeypad(in String pin);
+  void startWpsRegistrar(in byte[] bssid, in String pin);
+  void stopDppInitiator();
+  void stopDppResponder(in int ownBootstrapId);
+  void stopRxFilter();
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
new file mode 100644
index 0000000..37b34cf
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+interface ISupplicantStaIfaceCallback {
+  oneway void onAnqpQueryDone(in byte[] bssid, in android.hardware.wifi.supplicant.AnqpData data, in android.hardware.wifi.supplicant.Hs20AnqpData hs20Data);
+  oneway void onAssociationRejected(in android.hardware.wifi.supplicant.AssociationRejectionData assocRejectData);
+  oneway void onAuthenticationTimeout(in byte[] bssid);
+  oneway void onBssTmHandlingDone(in android.hardware.wifi.supplicant.BssTmData tmData);
+  oneway void onBssidChanged(in android.hardware.wifi.supplicant.BssidChangeReason reason, in byte[] bssid);
+  oneway void onDisconnected(in byte[] bssid, in boolean locallyGenerated, in android.hardware.wifi.supplicant.StaIfaceReasonCode reasonCode);
+  oneway void onDppFailure(in android.hardware.wifi.supplicant.DppFailureCode code, in String ssid, in String channelList, in char[] bandList);
+  oneway void onDppProgress(in android.hardware.wifi.supplicant.DppProgressCode code);
+  oneway void onDppSuccess(in android.hardware.wifi.supplicant.DppEventType event);
+  oneway void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk, in android.hardware.wifi.supplicant.DppAkm securityAkm);
+  oneway void onDppSuccessConfigSent();
+  oneway void onEapFailure(in int errorCode);
+  oneway void onExtRadioWorkStart(in int id);
+  oneway void onExtRadioWorkTimeout(in int id);
+  oneway void onHs20DeauthImminentNotice(in byte[] bssid, in int reasonCode, in int reAuthDelayInSec, in String url);
+  oneway void onHs20IconQueryDone(in byte[] bssid, in String fileName, in byte[] data);
+  oneway void onHs20SubscriptionRemediation(in byte[] bssid, in android.hardware.wifi.supplicant.OsuMethod osuMethod, in String url);
+  oneway void onHs20TermsAndConditionsAcceptanceRequestedNotification(in byte[] bssid, in String url);
+  oneway void onNetworkAdded(in int id);
+  oneway void onNetworkNotFound(in byte[] ssid);
+  oneway void onNetworkRemoved(in int id);
+  oneway void onPmkCacheAdded(in long expirationTimeInSec, in byte[] serializedEntry);
+  oneway void onStateChanged(in android.hardware.wifi.supplicant.StaIfaceCallbackState newState, in byte[] bssid, in int id, in byte[] ssid, in boolean filsHlpSent);
+  oneway void onWpsEventFail(in byte[] bssid, in android.hardware.wifi.supplicant.WpsConfigError configError, in android.hardware.wifi.supplicant.WpsErrorIndication errorInd);
+  oneway void onWpsEventPbcOverlap();
+  oneway void onWpsEventSuccess();
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
new file mode 100644
index 0000000..bdc5f34
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+interface ISupplicantStaNetwork {
+  void disable();
+  void enable(in boolean noConnect);
+  void enableSaePkOnlyMode(in boolean enable);
+  void enableSuiteBEapOpenSslCiphers();
+  void enableTlsSuiteBEapPhase1Param(in boolean enable);
+  android.hardware.wifi.supplicant.AuthAlgMask getAuthAlg();
+  byte[] getBssid();
+  String getEapAltSubjectMatch();
+  byte[] getEapAnonymousIdentity();
+  String getEapCACert();
+  String getEapCAPath();
+  String getEapClientCert();
+  String getEapDomainSuffixMatch();
+  boolean getEapEngine();
+  String getEapEngineId();
+  byte[] getEapIdentity();
+  android.hardware.wifi.supplicant.EapMethod getEapMethod();
+  byte[] getEapPassword();
+  android.hardware.wifi.supplicant.EapPhase2Method getEapPhase2Method();
+  String getEapPrivateKeyId();
+  String getEapSubjectMatch();
+  boolean getEdmg();
+  android.hardware.wifi.supplicant.GroupCipherMask getGroupCipher();
+  android.hardware.wifi.supplicant.GroupMgmtCipherMask getGroupMgmtCipher();
+  int getId();
+  String getIdStr();
+  String getInterfaceName();
+  android.hardware.wifi.supplicant.KeyMgmtMask getKeyMgmt();
+  android.hardware.wifi.supplicant.OcspType getOcsp();
+  android.hardware.wifi.supplicant.PairwiseCipherMask getPairwiseCipher();
+  android.hardware.wifi.supplicant.ProtoMask getProto();
+  byte[] getPsk();
+  String getPskPassphrase();
+  boolean getRequirePmf();
+  String getSaePassword();
+  String getSaePasswordId();
+  boolean getScanSsid();
+  byte[] getSsid();
+  android.hardware.wifi.supplicant.IfaceType getType();
+  String getWapiCertSuite();
+  byte[] getWepKey(in int keyIdx);
+  int getWepTxKeyIdx();
+  byte[] getWpsNfcConfigurationToken();
+  void registerCallback(in android.hardware.wifi.supplicant.ISupplicantStaNetworkCallback callback);
+  void select();
+  void sendNetworkEapIdentityResponse(in byte[] identity, in byte[] encryptedIdentity);
+  void sendNetworkEapSimGsmAuthFailure();
+  void sendNetworkEapSimGsmAuthResponse(in android.hardware.wifi.supplicant.NetworkResponseEapSimGsmAuthParams[] params);
+  void sendNetworkEapSimUmtsAuthFailure();
+  void sendNetworkEapSimUmtsAuthResponse(in android.hardware.wifi.supplicant.NetworkResponseEapSimUmtsAuthParams params);
+  void sendNetworkEapSimUmtsAutsResponse(in byte[] auts);
+  void setAuthAlg(in android.hardware.wifi.supplicant.AuthAlgMask authAlgMask);
+  void setBssid(in byte[] bssid);
+  void setEapAltSubjectMatch(in String match);
+  void setEapAnonymousIdentity(in byte[] identity);
+  void setEapCACert(in String path);
+  void setEapCAPath(in String path);
+  void setEapClientCert(in String path);
+  void setEapDomainSuffixMatch(in String match);
+  void setEapEncryptedImsiIdentity(in byte[] identity);
+  void setEapEngine(in boolean enable);
+  void setEapEngineID(in String id);
+  void setEapErp(in boolean enable);
+  void setEapIdentity(in byte[] identity);
+  void setEapMethod(in android.hardware.wifi.supplicant.EapMethod method);
+  void setEapPassword(in byte[] password);
+  void setEapPhase2Method(in android.hardware.wifi.supplicant.EapPhase2Method method);
+  void setEapPrivateKeyId(in String id);
+  void setEapSubjectMatch(in String match);
+  void setEdmg(in boolean enable);
+  void setGroupCipher(in android.hardware.wifi.supplicant.GroupCipherMask groupCipherMask);
+  void setGroupMgmtCipher(in android.hardware.wifi.supplicant.GroupMgmtCipherMask groupMgmtCipherMask);
+  void setIdStr(in String idStr);
+  void setKeyMgmt(in android.hardware.wifi.supplicant.KeyMgmtMask keyMgmtMask);
+  void setOcsp(in android.hardware.wifi.supplicant.OcspType ocspType);
+  void setPairwiseCipher(in android.hardware.wifi.supplicant.PairwiseCipherMask pairwiseCipherMask);
+  void setPmkCache(in byte[] serializedEntry);
+  void setProactiveKeyCaching(in boolean enable);
+  void setProto(in android.hardware.wifi.supplicant.ProtoMask protoMask);
+  void setPsk(in byte[] psk);
+  void setPskPassphrase(in String psk);
+  void setRequirePmf(in boolean enable);
+  void setSaeH2eMode(in android.hardware.wifi.supplicant.SaeH2eMode mode);
+  void setSaePassword(in String saePassword);
+  void setSaePasswordId(in String saePasswordId);
+  void setScanSsid(in boolean enable);
+  void setSsid(in byte[] ssid);
+  void setUpdateIdentifier(in int id);
+  void setWapiCertSuite(in String suite);
+  void setWepKey(in int keyIdx, in byte[] wepKey);
+  void setWepTxKeyIdx(in int keyIdx);
+  void setRoamingConsortiumSelection(in byte[] selectedRcoi);
+  const int SSID_MAX_LEN_IN_BYTES = 32;
+  const int PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8;
+  const int PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63;
+  const int WEP_KEYS_MAX_NUM = 4;
+  const int WEP40_KEY_LEN_IN_BYTES = 5;
+  const int WEP104_KEY_LEN_IN_BYTES = 13;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
new file mode 100644
index 0000000..6276a35
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+interface ISupplicantStaNetworkCallback {
+  oneway void onNetworkEapIdentityRequest();
+  oneway void onNetworkEapSimGsmAuthRequest(in android.hardware.wifi.supplicant.NetworkRequestEapSimGsmAuthParams params);
+  oneway void onNetworkEapSimUmtsAuthRequest(in android.hardware.wifi.supplicant.NetworkRequestEapSimUmtsAuthParams params);
+  oneway void onTransitionDisable(in android.hardware.wifi.supplicant.TransitionDisableIndication ind);
+  oneway void onServerCertificateAvailable(in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceInfo.aidl
new file mode 100644
index 0000000..6706c8c
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceInfo.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+parcelable IfaceInfo {
+  android.hardware.wifi.supplicant.IfaceType type;
+  String name;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceType.aidl
new file mode 100644
index 0000000..557dbd7
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum IfaceType {
+  STA = 0,
+  P2P = 1,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/KeyMgmtMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
new file mode 100644
index 0000000..7228480
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum KeyMgmtMask {
+  WPA_EAP = 1,
+  WPA_PSK = 2,
+  NONE = 4,
+  IEEE8021X = 8,
+  FT_EAP = 32,
+  FT_PSK = 64,
+  OSEN = 32768,
+  WPA_EAP_SHA256 = 128,
+  WPA_PSK_SHA256 = 256,
+  SAE = 1024,
+  SUITE_B_192 = 131072,
+  OWE = 4194304,
+  DPP = 8388608,
+  WAPI_PSK = 4096,
+  WAPI_CERT = 8192,
+  FILS_SHA256 = 262144,
+  FILS_SHA384 = 524288,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/LegacyMode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/LegacyMode.aidl
new file mode 100644
index 0000000..6896d75
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/LegacyMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum LegacyMode {
+  UNKNOWN = 0,
+  A_MODE = 1,
+  B_MODE = 2,
+  G_MODE = 3,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MacAddress.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MacAddress.aidl
new file mode 100644
index 0000000..d17930a
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MacAddress.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable MacAddress {
+  byte[] data;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboAssocDisallowedReasonCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboAssocDisallowedReasonCode.aidl
new file mode 100644
index 0000000..661165d
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboAssocDisallowedReasonCode.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum MboAssocDisallowedReasonCode {
+  RESERVED = 0,
+  UNSPECIFIED = 1,
+  MAX_NUM_STA_ASSOCIATED = 2,
+  AIR_INTERFACE_OVERLOADED = 3,
+  AUTH_SERVER_OVERLOADED = 4,
+  INSUFFICIENT_RSSI = 5,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboCellularDataConnectionPrefValue.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboCellularDataConnectionPrefValue.aidl
new file mode 100644
index 0000000..c4024d0
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboCellularDataConnectionPrefValue.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum MboCellularDataConnectionPrefValue {
+  EXCLUDED = 0,
+  NOT_PREFERRED = 1,
+  PREFERRED = 255,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboTransitionReasonCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboTransitionReasonCode.aidl
new file mode 100644
index 0000000..caed095
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MboTransitionReasonCode.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum MboTransitionReasonCode {
+  UNSPECIFIED = 0,
+  EXCESSIVE_FRAME_LOSS = 1,
+  EXCESSIVE_TRAFFIC_DELAY = 2,
+  INSUFFICIENT_BANDWIDTH = 3,
+  LOAD_BALANCING = 4,
+  LOW_RSSI = 5,
+  RX_EXCESSIVE_RETRIES = 6,
+  HIGH_INTERFERENCE = 7,
+  GRAY_ZONE = 8,
+  TRANSITION_TO_PREMIUM_AP = 9,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MiracastMode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MiracastMode.aidl
new file mode 100644
index 0000000..6bc9e4d
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MiracastMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum MiracastMode {
+  DISABLED = 0,
+  SOURCE = 1,
+  SINK = 2,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkRequestEapSimGsmAuthParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkRequestEapSimGsmAuthParams.aidl
new file mode 100644
index 0000000..1f03bb8
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkRequestEapSimGsmAuthParams.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable NetworkRequestEapSimGsmAuthParams {
+  android.hardware.wifi.supplicant.GsmRand[] rands;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkRequestEapSimUmtsAuthParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkRequestEapSimUmtsAuthParams.aidl
new file mode 100644
index 0000000..956a799
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkRequestEapSimUmtsAuthParams.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+parcelable NetworkRequestEapSimUmtsAuthParams {
+  byte[] rand;
+  byte[] autn;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkResponseEapSimGsmAuthParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkResponseEapSimGsmAuthParams.aidl
new file mode 100644
index 0000000..29415b7
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkResponseEapSimGsmAuthParams.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+parcelable NetworkResponseEapSimGsmAuthParams {
+  byte[] kc;
+  byte[] sres;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.aidl
new file mode 100644
index 0000000..4e58dd8
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable NetworkResponseEapSimUmtsAuthParams {
+  byte[] res;
+  byte[] ik;
+  byte[] ck;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OceRssiBasedAssocRejectAttr.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OceRssiBasedAssocRejectAttr.aidl
new file mode 100644
index 0000000..95a95bc
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OceRssiBasedAssocRejectAttr.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@VintfStability
+parcelable OceRssiBasedAssocRejectAttr {
+  int deltaRssi;
+  int retryDelayS;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OcspType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OcspType.aidl
new file mode 100644
index 0000000..89de811
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OcspType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum OcspType {
+  NONE = 0,
+  REQUEST_CERT_STATUS = 1,
+  REQUIRE_CERT_STATUS = 2,
+  REQUIRE_ALL_CERTS_STATUS = 3,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OsuMethod.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OsuMethod.aidl
new file mode 100644
index 0000000..1b99e2f
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OsuMethod.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum OsuMethod {
+  OMA_DM = 0,
+  SOAP_XML_SPP = 1,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl
new file mode 100644
index 0000000..ffee12c
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum P2pGroupCapabilityMask {
+  GROUP_OWNER = 1,
+  PERSISTENT_GROUP = 2,
+  GROUP_LIMIT = 4,
+  INTRA_BSS_DIST = 8,
+  CROSS_CONN = 16,
+  PERSISTENT_RECONN = 32,
+  GROUP_FORMATION = 64,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvDiscStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvDiscStatusCode.aidl
new file mode 100644
index 0000000..c8e53b9
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvDiscStatusCode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum P2pProvDiscStatusCode {
+  SUCCESS = 0,
+  TIMEOUT = 1,
+  REJECTED = 2,
+  TIMEOUT_JOIN = 3,
+  INFO_UNAVAILABLE = 4,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pStatusCode.aidl
new file mode 100644
index 0000000..c7ad383
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pStatusCode.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum P2pStatusCode {
+  SUCCESS = 0,
+  FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
+  FAIL_INCOMPATIBLE_PARAMS = 2,
+  FAIL_LIMIT_REACHED = 3,
+  FAIL_INVALID_PARAMS = 4,
+  FAIL_UNABLE_TO_ACCOMMODATE = 5,
+  FAIL_PREV_PROTOCOL_ERROR = 6,
+  FAIL_NO_COMMON_CHANNELS = 7,
+  FAIL_UNKNOWN_GROUP = 8,
+  FAIL_BOTH_GO_INTENT_15 = 9,
+  FAIL_INCOMPATIBLE_PROV_METHOD = 10,
+  FAIL_REJECTED_BY_USER = 11,
+  SUCCESS_DEFERRED = 12,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl
new file mode 100644
index 0000000..d9b00e1
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum PairwiseCipherMask {
+  NONE = 1,
+  TKIP = 8,
+  CCMP = 16,
+  GCMP_128 = 64,
+  SMS4 = 128,
+  GCMP_256 = 256,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ProtoMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ProtoMask.aidl
new file mode 100644
index 0000000..de92428
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ProtoMask.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum ProtoMask {
+  WPA = 1,
+  RSN = 2,
+  WAPI = 4,
+  OSEN = 8,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/RxFilterType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/RxFilterType.aidl
new file mode 100644
index 0000000..63f5bf2
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/RxFilterType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum RxFilterType {
+  V4_MULTICAST = 0,
+  V6_MULTICAST = 1,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SaeH2eMode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SaeH2eMode.aidl
new file mode 100644
index 0000000..978c337
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SaeH2eMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="byte") @VintfStability
+enum SaeH2eMode {
+  DISABLED = 0,
+  H2E_OPTIONAL = 1,
+  H2E_MANDATORY = 2,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceCallbackState.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceCallbackState.aidl
new file mode 100644
index 0000000..d78cfa2
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceCallbackState.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum StaIfaceCallbackState {
+  DISCONNECTED = 0,
+  IFACE_DISABLED = 1,
+  INACTIVE = 2,
+  SCANNING = 3,
+  AUTHENTICATING = 4,
+  ASSOCIATING = 5,
+  ASSOCIATED = 6,
+  FOURWAY_HANDSHAKE = 7,
+  GROUP_HANDSHAKE = 8,
+  COMPLETED = 9,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceReasonCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceReasonCode.aidl
new file mode 100644
index 0000000..f26e7c5
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceReasonCode.aidl
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum StaIfaceReasonCode {
+  UNSPECIFIED = 1,
+  PREV_AUTH_NOT_VALID = 2,
+  DEAUTH_LEAVING = 3,
+  DISASSOC_DUE_TO_INACTIVITY = 4,
+  DISASSOC_AP_BUSY = 5,
+  CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+  CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+  DISASSOC_STA_HAS_LEFT = 8,
+  STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+  PWR_CAPABILITY_NOT_VALID = 10,
+  SUPPORTED_CHANNEL_NOT_VALID = 11,
+  BSS_TRANSITION_DISASSOC = 12,
+  INVALID_IE = 13,
+  MICHAEL_MIC_FAILURE = 14,
+  FOURWAY_HANDSHAKE_TIMEOUT = 15,
+  GROUP_KEY_UPDATE_TIMEOUT = 16,
+  IE_IN_4WAY_DIFFERS = 17,
+  GROUP_CIPHER_NOT_VALID = 18,
+  PAIRWISE_CIPHER_NOT_VALID = 19,
+  AKMP_NOT_VALID = 20,
+  UNSUPPORTED_RSN_IE_VERSION = 21,
+  INVALID_RSN_IE_CAPAB = 22,
+  IEEE_802_1X_AUTH_FAILED = 23,
+  CIPHER_SUITE_REJECTED = 24,
+  TDLS_TEARDOWN_UNREACHABLE = 25,
+  TDLS_TEARDOWN_UNSPECIFIED = 26,
+  SSP_REQUESTED_DISASSOC = 27,
+  NO_SSP_ROAMING_AGREEMENT = 28,
+  BAD_CIPHER_OR_AKM = 29,
+  NOT_AUTHORIZED_THIS_LOCATION = 30,
+  SERVICE_CHANGE_PRECLUDES_TS = 31,
+  UNSPECIFIED_QOS_REASON = 32,
+  NOT_ENOUGH_BANDWIDTH = 33,
+  DISASSOC_LOW_ACK = 34,
+  EXCEEDED_TXOP = 35,
+  STA_LEAVING = 36,
+  END_TS_BA_DLS = 37,
+  UNKNOWN_TS_BA = 38,
+  TIMEOUT = 39,
+  PEERKEY_MISMATCH = 45,
+  AUTHORIZED_ACCESS_LIMIT_REACHED = 46,
+  EXTERNAL_SERVICE_REQUIREMENTS = 47,
+  INVALID_FT_ACTION_FRAME_COUNT = 48,
+  INVALID_PMKID = 49,
+  INVALID_MDE = 50,
+  INVALID_FTE = 51,
+  MESH_PEERING_CANCELLED = 52,
+  MESH_MAX_PEERS = 53,
+  MESH_CONFIG_POLICY_VIOLATION = 54,
+  MESH_CLOSE_RCVD = 55,
+  MESH_MAX_RETRIES = 56,
+  MESH_CONFIRM_TIMEOUT = 57,
+  MESH_INVALID_GTK = 58,
+  MESH_INCONSISTENT_PARAMS = 59,
+  MESH_INVALID_SECURITY_CAP = 60,
+  MESH_PATH_ERROR_NO_PROXY_INFO = 61,
+  MESH_PATH_ERROR_NO_FORWARDING_INFO = 62,
+  MESH_PATH_ERROR_DEST_UNREACHABLE = 63,
+  MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64,
+  MESH_CHANNEL_SWITCH_REGULATORY_REQ = 65,
+  MESH_CHANNEL_SWITCH_UNSPECIFIED = 66,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceStatusCode.aidl
new file mode 100644
index 0000000..13529a5
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/StaIfaceStatusCode.aidl
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum StaIfaceStatusCode {
+  SUCCESS = 0,
+  UNSPECIFIED_FAILURE = 1,
+  TDLS_WAKEUP_ALTERNATE = 2,
+  TDLS_WAKEUP_REJECT = 3,
+  SECURITY_DISABLED = 5,
+  UNACCEPTABLE_LIFETIME = 6,
+  NOT_IN_SAME_BSS = 7,
+  CAPS_UNSUPPORTED = 10,
+  REASSOC_NO_ASSOC = 11,
+  ASSOC_DENIED_UNSPEC = 12,
+  NOT_SUPPORTED_AUTH_ALG = 13,
+  UNKNOWN_AUTH_TRANSACTION = 14,
+  CHALLENGE_FAIL = 15,
+  AUTH_TIMEOUT = 16,
+  AP_UNABLE_TO_HANDLE_NEW_STA = 17,
+  ASSOC_DENIED_RATES = 18,
+  ASSOC_DENIED_NOSHORT = 19,
+  SPEC_MGMT_REQUIRED = 22,
+  PWR_CAPABILITY_NOT_VALID = 23,
+  SUPPORTED_CHANNEL_NOT_VALID = 24,
+  ASSOC_DENIED_NO_SHORT_SLOT_TIME = 25,
+  ASSOC_DENIED_NO_HT = 27,
+  R0KH_UNREACHABLE = 28,
+  ASSOC_DENIED_NO_PCO = 29,
+  ASSOC_REJECTED_TEMPORARILY = 30,
+  ROBUST_MGMT_FRAME_POLICY_VIOLATION = 31,
+  UNSPECIFIED_QOS_FAILURE = 32,
+  DENIED_INSUFFICIENT_BANDWIDTH = 33,
+  DENIED_POOR_CHANNEL_CONDITIONS = 34,
+  DENIED_QOS_NOT_SUPPORTED = 35,
+  REQUEST_DECLINED = 37,
+  INVALID_PARAMETERS = 38,
+  REJECTED_WITH_SUGGESTED_CHANGES = 39,
+  INVALID_IE = 40,
+  GROUP_CIPHER_NOT_VALID = 41,
+  PAIRWISE_CIPHER_NOT_VALID = 42,
+  AKMP_NOT_VALID = 43,
+  UNSUPPORTED_RSN_IE_VERSION = 44,
+  INVALID_RSN_IE_CAPAB = 45,
+  CIPHER_REJECTED_PER_POLICY = 46,
+  TS_NOT_CREATED = 47,
+  DIRECT_LINK_NOT_ALLOWED = 48,
+  DEST_STA_NOT_PRESENT = 49,
+  DEST_STA_NOT_QOS_STA = 50,
+  ASSOC_DENIED_LISTEN_INT_TOO_LARGE = 51,
+  INVALID_FT_ACTION_FRAME_COUNT = 52,
+  INVALID_PMKID = 53,
+  INVALID_MDIE = 54,
+  INVALID_FTIE = 55,
+  REQUESTED_TCLAS_NOT_SUPPORTED = 56,
+  INSUFFICIENT_TCLAS_PROCESSING_RESOURCES = 57,
+  TRY_ANOTHER_BSS = 58,
+  GAS_ADV_PROTO_NOT_SUPPORTED = 59,
+  NO_OUTSTANDING_GAS_REQ = 60,
+  GAS_RESP_NOT_RECEIVED = 61,
+  STA_TIMED_OUT_WAITING_FOR_GAS_RESP = 62,
+  GAS_RESP_LARGER_THAN_LIMIT = 63,
+  REQ_REFUSED_HOME = 64,
+  ADV_SRV_UNREACHABLE = 65,
+  REQ_REFUSED_SSPN = 67,
+  REQ_REFUSED_UNAUTH_ACCESS = 68,
+  INVALID_RSNIE = 72,
+  U_APSD_COEX_NOT_SUPPORTED = 73,
+  U_APSD_COEX_MODE_NOT_SUPPORTED = 74,
+  BAD_INTERVAL_WITH_U_APSD_COEX = 75,
+  ANTI_CLOGGING_TOKEN_REQ = 76,
+  FINITE_CYCLIC_GROUP_NOT_SUPPORTED = 77,
+  CANNOT_FIND_ALT_TBTT = 78,
+  TRANSMISSION_FAILURE = 79,
+  REQ_TCLAS_NOT_SUPPORTED = 80,
+  TCLAS_RESOURCES_EXCHAUSTED = 81,
+  REJECTED_WITH_SUGGESTED_BSS_TRANSITION = 82,
+  REJECT_WITH_SCHEDULE = 83,
+  REJECT_NO_WAKEUP_SPECIFIED = 84,
+  SUCCESS_POWER_SAVE_MODE = 85,
+  PENDING_ADMITTING_FST_SESSION = 86,
+  PERFORMING_FST_NOW = 87,
+  PENDING_GAP_IN_BA_WINDOW = 88,
+  REJECT_U_PID_SETTING = 89,
+  REFUSED_EXTERNAL_REASON = 92,
+  REFUSED_AP_OUT_OF_MEMORY = 93,
+  REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED = 94,
+  QUERY_RESP_OUTSTANDING = 95,
+  REJECT_DSE_BAND = 96,
+  TCLAS_PROCESSING_TERMINATED = 97,
+  TS_SCHEDULE_CONFLICT = 98,
+  DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
+  MCCAOP_RESERVATION_CONFLICT = 100,
+  MAF_LIMIT_EXCEEDED = 101,
+  MCCA_TRACK_LIMIT_EXCEEDED = 102,
+  DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
+  ASSOC_DENIED_NO_VHT = 104,
+  ENABLEMENT_DENIED = 105,
+  RESTRICTION_FROM_AUTHORIZED_GDB = 106,
+  AUTHORIZATION_DEENABLED = 107,
+  FILS_AUTHENTICATION_FAILURE = 112,
+  UNKNOWN_AUTHENTICATION_SERVER = 113,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl
new file mode 100644
index 0000000..32d71a3
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum SupplicantStatusCode {
+  SUCCESS = 0,
+  FAILURE_UNKNOWN = 1,
+  FAILURE_ARGS_INVALID = 2,
+  FAILURE_IFACE_INVALID = 3,
+  FAILURE_IFACE_UNKNOWN = 4,
+  FAILURE_IFACE_EXISTS = 5,
+  FAILURE_IFACE_DISABLED = 6,
+  FAILURE_IFACE_NOT_DISCONNECTED = 7,
+  FAILURE_NETWORK_INVALID = 8,
+  FAILURE_NETWORK_UNKNOWN = 9,
+  FAILURE_UNSUPPORTED = 10,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl
new file mode 100644
index 0000000..7c63217
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum TransitionDisableIndication {
+  USE_WPA3_PERSONAL = 1,
+  USE_SAE_PK = 2,
+  USE_WPA3_ENTERPRISE = 4,
+  USE_ENHANCED_OPEN = 8,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WifiTechnology.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WifiTechnology.aidl
new file mode 100644
index 0000000..bf5081e
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WifiTechnology.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum WifiTechnology {
+  UNKNOWN = 0,
+  LEGACY = 1,
+  HT = 2,
+  VHT = 3,
+  HE = 4,
+  EHT = 5,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
new file mode 100644
index 0000000..9a0a924
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum WpaDriverCapabilitiesMask {
+  MBO = 1,
+  OCE = 2,
+  SAE_PK = 4,
+  WFD_R2 = 8,
+  TRUST_ON_FIRST_USE = 16,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigError.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigError.aidl
new file mode 100644
index 0000000..c48b282
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigError.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum WpsConfigError {
+  NO_ERROR = 0,
+  OOB_IFACE_READ_ERROR = 1,
+  DECRYPTION_CRC_FAILURE = 2,
+  CHAN_24_NOT_SUPPORTED = 3,
+  CHAN_50_NOT_SUPPORTED = 4,
+  SIGNAL_TOO_WEAK = 5,
+  NETWORK_AUTH_FAILURE = 6,
+  NETWORK_ASSOC_FAILURE = 7,
+  NO_DHCP_RESPONSE = 8,
+  FAILED_DHCP_CONFIG = 9,
+  IP_ADDR_CONFLICT = 10,
+  NO_CONN_TO_REGISTRAR = 11,
+  MULTIPLE_PBC_DETECTED = 12,
+  ROGUE_SUSPECTED = 13,
+  DEVICE_BUSY = 14,
+  SETUP_LOCKED = 15,
+  MSG_TIMEOUT = 16,
+  REG_SESS_TIMEOUT = 17,
+  DEV_PASSWORD_AUTH_FAILURE = 18,
+  CHAN_60G_NOT_SUPPORTED = 19,
+  PUBLIC_KEY_HASH_MISMATCH = 20,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigMethods.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigMethods.aidl
new file mode 100644
index 0000000..c98c479
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigMethods.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum WpsConfigMethods {
+  USBA = 1,
+  ETHERNET = 2,
+  LABEL = 4,
+  DISPLAY = 8,
+  EXT_NFC_TOKEN = 16,
+  INT_NFC_TOKEN = 32,
+  NFC_INTERFACE = 64,
+  PUSHBUTTON = 128,
+  KEYPAD = 256,
+  VIRT_PUSHBUTTON = 640,
+  PHY_PUSHBUTTON = 1152,
+  P2PS = 4096,
+  VIRT_DISPLAY = 8200,
+  PHY_DISPLAY = 16392,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl
new file mode 100644
index 0000000..975f1ab
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum WpsDevPasswordId {
+  DEFAULT = 0,
+  USER_SPECIFIED = 1,
+  MACHINE_SPECIFIED = 2,
+  REKEY = 3,
+  PUSHBUTTON = 4,
+  REGISTRAR_SPECIFIED = 5,
+  NFC_CONNECTION_HANDOVER = 7,
+  P2PS_DEFAULT = 8,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsErrorIndication.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsErrorIndication.aidl
new file mode 100644
index 0000000..50e69ff
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsErrorIndication.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum WpsErrorIndication {
+  NO_ERROR = 0,
+  SECURITY_TKIP_ONLY_PROHIBITED = 1,
+  SECURITY_WEP_PROHIBITED = 2,
+  AUTH_FAILURE = 3,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
new file mode 100644
index 0000000..f6dba23
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum WpsProvisionMethod {
+  PBC = 0,
+  DISPLAY = 1,
+  KEYPAD = 2,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AnqpData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AnqpData.aidl
new file mode 100644
index 0000000..5bc1015
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AnqpData.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * ANQP data for IEEE Std 802.11-2016.
+ * The format of the data within these elements follows the IEEE
+ * Std 802.11-2016 standard, section 9.4.5.
+ */
+@VintfStability
+parcelable AnqpData {
+    byte[] venueName;
+    byte[] roamingConsortium;
+    byte[] ipAddrTypeAvailability;
+    byte[] naiRealm;
+    byte[] anqp3gppCellularNetwork;
+    byte[] domainName;
+    byte[] venueUrl;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AnqpInfoId.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AnqpInfoId.aidl
new file mode 100644
index 0000000..7b2eb23
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AnqpInfoId.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Access Network Query Protocol info ID elements
+ * for IEEE Std 802.11u-2011.
+ */
+@VintfStability
+@Backing(type="int")
+enum AnqpInfoId {
+    VENUE_NAME = 258,
+    ROAMING_CONSORTIUM = 261,
+    IP_ADDR_TYPE_AVAILABILITY = 262,
+    NAI_REALM = 263,
+    ANQP_3GPP_CELLULAR_NETWORK = 264,
+    DOMAIN_NAME = 268,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AssociationRejectionData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AssociationRejectionData.aidl
new file mode 100644
index 0000000..5673021
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AssociationRejectionData.aidl
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.MboAssocDisallowedReasonCode;
+import android.hardware.wifi.supplicant.OceRssiBasedAssocRejectAttr;
+import android.hardware.wifi.supplicant.StaIfaceStatusCode;
+
+/**
+ * Association Rejection related information.
+ */
+@VintfStability
+parcelable AssociationRejectionData {
+    /**
+     * SSID of the AP that rejected the association.
+     */
+    byte[] ssid;
+    /**
+     * BSSID of the AP that rejected the association.
+     */
+    byte[/* 6 */] bssid;
+    /*
+     * 802.11 code to indicate the reject reason.
+     * Refer to section 8.4.1.9 of IEEE 802.11 spec.
+     */
+    StaIfaceStatusCode statusCode;
+    /*
+     * Flag to indicate that failure is due to timeout rather than
+     * explicit rejection response from the AP.
+     */
+    boolean timedOut;
+    /**
+     * Flag to indicate that MboAssocDisallowedReasonCode is present
+     * in the (Re-)Association response frame.
+     */
+    boolean isMboAssocDisallowedReasonCodePresent;
+    /**
+     * mboAssocDisallowedReason is extracted from MBO association disallowed attribute
+     * in (Re-)Association response frame to indicate that the AP is not accepting new
+     * associations.
+     * Refer MBO spec v1.2 section 4.2.4 Table 13 for the details of reason code.
+     * The value is undefined if isMboAssocDisallowedReasonCodePresent is false.
+     */
+    MboAssocDisallowedReasonCode mboAssocDisallowedReason;
+    /**
+     * Flag to indicate that OceRssiBasedAssocRejectAttr is present
+     * in the (Re-)Association response frame.
+     */
+    boolean isOceRssiBasedAssocRejectAttrPresent;
+    /*
+     * OCE RSSI-based (Re-)Association rejection attribute.
+     * The contents are undefined if isOceRssiBasedAssocRejectAttrPresent is false.
+     */
+    OceRssiBasedAssocRejectAttr oceRssiBasedAssocRejectData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AuthAlgMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AuthAlgMask.aidl
new file mode 100644
index 0000000..039d41d
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AuthAlgMask.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possible mask of values for AuthAlg param.
+ * See /external/wpa_supplicant_8/src/common/defs.h for
+ * the historical values (starting at WPA_AUTH_ALG_OPEN).
+ */
+@VintfStability
+@Backing(type="int")
+enum AuthAlgMask {
+    OPEN = 1 << 0,
+    SHARED = 1 << 1,
+    LEAP = 1 << 2,
+    SAE = 1 << 4,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmData.aidl
new file mode 100644
index 0000000..233e54a
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmData.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.BssTmDataFlagsMask;
+import android.hardware.wifi.supplicant.BssTmStatusCode;
+import android.hardware.wifi.supplicant.MboCellularDataConnectionPrefValue;
+import android.hardware.wifi.supplicant.MboTransitionReasonCode;
+
+/**
+ * Data retrieved from received BSS transition management request frame.
+ */
+@VintfStability
+parcelable BssTmData {
+    /*
+     * Status code filled in BSS transition management response frame
+     */
+    BssTmStatusCode status;
+    /*
+     * Bitmask of BssTmDataFlagsMask
+     */
+    BssTmDataFlagsMask flags;
+    /*
+     * Duration for which STA shouldn't try to re-associate.
+     */
+    int assocRetryDelayMs;
+    /*
+     * Reason for BSS transition request.
+     */
+    MboTransitionReasonCode mboTransitionReason;
+    /*
+     * Cellular Data Connection preference value.
+     */
+    MboCellularDataConnectionPrefValue mboCellPreference;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl
new file mode 100644
index 0000000..1eb75f4
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Bitmask of various information retrieved from BSS transition management request frame.
+ */
+@VintfStability
+@Backing(type="int")
+enum BssTmDataFlagsMask {
+    /**
+     * Preferred candidate list included.
+     */
+    WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = 1 << 0,
+    /**
+     * Abridged.
+     */
+    WNM_MODE_ABRIDGED = 1 << 1,
+    /**
+     * Disassociation Imminent.
+     */
+    WNM_MODE_DISASSOCIATION_IMMINENT = 1 << 2,
+    /**
+     * BSS termination included.
+     */
+    WNM_MODE_BSS_TERMINATION_INCLUDED = 1 << 3,
+    /**
+     * ESS Disassociation Imminent.
+     */
+    WNM_MODE_ESS_DISASSOCIATION_IMMINENT = 1 << 4,
+    /**
+     * MBO transition reason code included.
+     */
+    MBO_TRANSITION_REASON_CODE_INCLUDED = 1 << 5,
+    /**
+     * MBO retry delay time included.
+     */
+    MBO_ASSOC_RETRY_DELAY_INCLUDED = 1 << 6,
+    /**
+     * MBO cellular data connection preference value included.
+     */
+    MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = 1 << 7,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmStatusCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmStatusCode.aidl
new file mode 100644
index 0000000..51fbfed
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssTmStatusCode.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * IEEE Std 802.11-2016 - Table 9-357.
+ * BTM status code filled in BSS transition management response frame.
+ */
+@VintfStability
+@Backing(type="byte")
+enum BssTmStatusCode {
+    ACCEPT = 0,
+    REJECT_UNSPECIFIED = 1,
+    REJECT_INSUFFICIENT_BEACON = 2,
+    REJECT_INSUFFICIENT_CAPABITY = 3,
+    REJECT_BSS_TERMINATION_UNDESIRED = 4,
+    REJECT_BSS_TERMINATION_DELAY_REQUEST = 5,
+    REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+    REJECT_NO_SUITABLE_CANDIDATES = 7,
+    REJECT_LEAVING_ESS = 8,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssidChangeReason.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssidChangeReason.aidl
new file mode 100644
index 0000000..8532bd7
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BssidChangeReason.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * BSSID change Reasons.
+ */
+@VintfStability
+@Backing(type="byte")
+enum BssidChangeReason {
+    /**
+     * Started association with new bssid.
+     */
+    ASSOC_START = 0,
+    /**
+     * Completed association with new bssid.
+     */
+    ASSOC_COMPLETE = 1,
+    /**
+     * Dis-association with current bssid.
+     */
+    DISASSOC = 2,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BtCoexistenceMode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BtCoexistenceMode.aidl
new file mode 100644
index 0000000..4972744
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/BtCoexistenceMode.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Enum describing the modes of BT coexistence supported
+ * via driver commands.
+ */
+@VintfStability
+@Backing(type="byte")
+enum BtCoexistenceMode {
+    ENABLED = 0,
+    DISABLED = 1,
+    SENSE = 2,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
new file mode 100644
index 0000000..1718413
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.LegacyMode;
+import android.hardware.wifi.supplicant.WifiTechnology;
+
+/**
+ * Connection Capabilities supported by current network and device
+ */
+@VintfStability
+parcelable ConnectionCapabilities {
+    /**
+     * Wifi Technology
+     */
+    WifiTechnology technology;
+    /**
+     * channel bandwidth
+     */
+    int channelBandwidth;
+    /**
+     * max number of Tx spatial streams
+     */
+    int maxNumberTxSpatialStreams;
+    /**
+     * max number of Rx spatial streams
+     */
+    int maxNumberRxSpatialStreams;
+    /**
+     * detailed network mode for legacy network
+     */
+    LegacyMode legacyMode;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DebugLevel.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DebugLevel.aidl
new file mode 100644
index 0000000..7caa406
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DebugLevel.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Debug levels for the supplicant.
+ * Only log messages with a level greater than the set level
+ * (via |setDebugParams|) will be logged.
+ */
+@VintfStability
+@Backing(type="int")
+enum DebugLevel {
+    EXCESSIVE = 0,
+    MSGDUMP = 1,
+    DEBUG = 2,
+    INFO = 3,
+    WARNING = 4,
+    ERROR = 5,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppAkm.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppAkm.aidl
new file mode 100644
index 0000000..63fff54
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppAkm.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppAkm: The various AKMs that can be provisioned using DPP.
+ */
+@VintfStability
+@Backing(type="int")
+enum DppAkm {
+    PSK,
+    PSK_SAE,
+    SAE,
+    DPP,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppCurve.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppCurve.aidl
new file mode 100644
index 0000000..ea57505
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppCurve.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppCurve: Elliptic curve cryptography type used to generate DPP
+ * public/private key pair.
+ */
+@VintfStability
+@Backing(type="int")
+enum DppCurve {
+    PRIME256V1,
+    SECP384R1,
+    SECP521R1,
+    BRAINPOOLP256R1,
+    BRAINPOOLP384R1,
+    BRAINPOOLP512R1,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppEventType.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppEventType.aidl
new file mode 100644
index 0000000..4b9b38b
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppEventType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppEventType: Major events for DPP (Easy Connect) Configurator
+ */
+@VintfStability
+@Backing(type="int")
+enum DppEventType {
+    CONFIGURATION_SENT,
+    CONFIGURATION_APPLIED,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppFailureCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppFailureCode.aidl
new file mode 100644
index 0000000..5c0c6e8
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppFailureCode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppFailureCode: Error codes for DPP (Easy Connect)
+ */
+@VintfStability
+@Backing(type="int")
+enum DppFailureCode {
+    INVALID_URI,
+    AUTHENTICATION,
+    NOT_COMPATIBLE,
+    CONFIGURATION,
+    BUSY,
+    TIMEOUT,
+    FAILURE,
+    NOT_SUPPORTED,
+    CONFIGURATION_REJECTED,
+    CANNOT_FIND_NETWORK,
+    ENROLLEE_AUTHENTICATION,
+    /**
+     * Failure to generate a DPP URI.
+     */
+    URI_GENERATION,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppNetRole.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppNetRole.aidl
new file mode 100644
index 0000000..d92cfa3
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppNetRole.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppNetRole: The network role that the configurator offers the enrollee.
+ */
+@VintfStability
+@Backing(type="int")
+enum DppNetRole {
+    STA,
+    AP,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppProgressCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppProgressCode.aidl
new file mode 100644
index 0000000..f8b35c0
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppProgressCode.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppProgressCode: Progress codes for DPP (Easy Connect)
+ */
+@VintfStability
+@Backing(type="int")
+enum DppProgressCode {
+    AUTHENTICATION_SUCCESS,
+    RESPONSE_PENDING,
+    CONFIGURATION_SENT_WAITING_RESPONSE,
+    CONFIGURATION_ACCEPTED,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppResponderBootstrapInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppResponderBootstrapInfo.aidl
new file mode 100644
index 0000000..4f4778d
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppResponderBootstrapInfo.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DPP bootstrap info generated for responder mode operation
+ */
+@VintfStability
+parcelable DppResponderBootstrapInfo {
+    /**
+     * Generated bootstrap identifier
+     */
+    int bootstrapId;
+    /**
+     * The Wi-Fi channel that the DPP responder is listening on.
+     */
+    int listenChannel;
+    /**
+     * Bootstrapping URI per DPP specification, "section 5.2 Bootstrapping
+     * information", may contain listen channel, MAC address, public key, or other information.
+     */
+    String uri;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapErrorCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapErrorCode.aidl
new file mode 100644
index 0000000..49f9e34
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapErrorCode.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/*
+ * EapErrorCode: Error code for EAP or EAP Method as per RFC-4186
+ */
+@VintfStability
+@Backing(type="int")
+enum EapErrorCode {
+    SIM_GENERAL_FAILURE_AFTER_AUTH = 0,
+    SIM_TEMPORARILY_DENIED = 1026,
+    SIM_NOT_SUBSCRIBED = 1031,
+    SIM_GENERAL_FAILURE_BEFORE_AUTH = 16384,
+    SIM_VENDOR_SPECIFIC_EXPIRED_CERT = 16385,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapMethod.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapMethod.aidl
new file mode 100644
index 0000000..351fb6c
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapMethod.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possble values for EapMethod param.
+ */
+@VintfStability
+@Backing(type="int")
+enum EapMethod {
+    PEAP = 0,
+    TLS = 1,
+    TTLS = 2,
+    PWD = 3,
+    SIM = 4,
+    AKA = 5,
+    AKA_PRIME = 6,
+    WFA_UNAUTH_TLS = 7,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapPhase2Method.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapPhase2Method.aidl
new file mode 100644
index 0000000..a7eeca8
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/EapPhase2Method.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possble values for Phase2Method param.
+ */
+@VintfStability
+@Backing(type="int")
+enum EapPhase2Method {
+    NONE = 0,
+    PAP = 1,
+    MSPAP = 2,
+    MSPAPV2 = 3,
+    GTC = 4,
+    SIM = 5,
+    AKA = 6,
+    AKA_PRIME = 7,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ExtRadioWorkDefaults.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ExtRadioWorkDefaults.aidl
new file mode 100644
index 0000000..7325ba2
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ExtRadioWorkDefaults.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+@VintfStability
+@Backing(type="int")
+enum ExtRadioWorkDefaults {
+    TIMEOUT_IN_SECS = 10,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/FreqRange.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/FreqRange.aidl
new file mode 100644
index 0000000..a88c011
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/FreqRange.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Use to specify a range of frequencies.
+ * For example: 2412-2432,2462,5000-6000, etc.
+ */
+@VintfStability
+parcelable FreqRange {
+    int min;
+    int max;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GroupCipherMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GroupCipherMask.aidl
new file mode 100644
index 0000000..99e9da0
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GroupCipherMask.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possible mask of values for GroupCipher param.
+ * See /external/wpa_supplicant_8/src/common/defs.h for
+ * the historical values (starting at WPA_CIPHER_WEP40).
+ */
+@VintfStability
+@Backing(type="int")
+enum GroupCipherMask {
+    WEP40 = 1 << 1,
+    WEP104 = 1 << 2,
+    TKIP = 1 << 3,
+    CCMP = 1 << 4,
+    GTK_NOT_USED = 1 << 14,
+    /**
+     * GCMP-256 Group Cipher
+     */
+    GCMP_256 = 1 << 8,
+    /**
+     * SMS4 Group Cipher
+     */
+    SMS4 = 1 << 7,
+    /**
+     * GCMP-128 Group Cipher
+     */
+    GCMP_128 = 1 << 6,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl
new file mode 100644
index 0000000..07544f0
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possble mask of values for GroupMgmtCipher param.
+ * See /external/wpa_supplicant_8/src/common/defs.h for
+ * all possible values (starting at WPA_CIPHER_BIP_GMAC_128).
+ */
+@VintfStability
+@Backing(type="int")
+enum GroupMgmtCipherMask {
+    /**
+     * BIP_GMAC-128 Group Management Cipher
+     */
+    BIP_GMAC_128 = 1 << 11,
+    /**
+     * BIP_GMAC-256 Group Management Cipher
+     */
+    BIP_GMAC_256 = 1 << 12,
+    /**
+     * BIP_CMAC-256 Group Management Cipher
+     */
+    BIP_CMAC_256 = 1 << 13,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GsmRand.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GsmRand.aidl
new file mode 100644
index 0000000..4e31323
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/GsmRand.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Byte array with expected length 16. Used by NetworkRequestEapSimGsmAuthParams
+ * to pass an array of byte arrays, as 2D arrays are not supported in AIDL.
+ *
+ * TODO (b/210705533): Replace this type with a 2D byte array.
+ */
+@VintfStability
+parcelable GsmRand {
+    byte[/* 16 */] data;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/Hs20AnqpData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/Hs20AnqpData.aidl
new file mode 100644
index 0000000..bdb9ec6
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/Hs20AnqpData.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * ANQP data for Hotspot 2.0.
+ * The format of the data within these elements follows the Hotspot 2.0
+ * standard.
+ */
+@VintfStability
+parcelable Hs20AnqpData {
+    byte[] operatorFriendlyName;
+    byte[] wanMetrics;
+    byte[] connectionCapability;
+    byte[] osuProvidersList;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/Hs20AnqpSubtypes.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/Hs20AnqpSubtypes.aidl
new file mode 100644
index 0000000..e08411d
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/Hs20AnqpSubtypes.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Access Network Query Protocol subtype elements
+ * for Hotspot 2.0.
+ */
+@VintfStability
+@Backing(type="int")
+enum Hs20AnqpSubtypes {
+    OPERATOR_FRIENDLY_NAME = 3,
+    WAN_METRICS = 4,
+    CONNECTION_CAPABILITY = 5,
+    OSU_PROVIDERS_LIST = 8,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
new file mode 100644
index 0000000..2ac1db7
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.DebugLevel;
+import android.hardware.wifi.supplicant.ISupplicantCallback;
+import android.hardware.wifi.supplicant.ISupplicantP2pIface;
+import android.hardware.wifi.supplicant.ISupplicantStaIface;
+import android.hardware.wifi.supplicant.IfaceInfo;
+import android.hardware.wifi.supplicant.IfaceType;
+
+/**
+ * Interface exposed by the supplicant AIDL service registered
+ * with the service manager. This is the root level object for
+ * any of the supplicant interactions.
+ */
+@VintfStability
+interface ISupplicant {
+    /**
+     * Default timeout (in seconds) for external radio work.
+     */
+    const int EXT_RADIO_WORK_TIMEOUT_IN_SECS = 10;
+
+    /**
+     * Registers a wireless interface in supplicant.
+     *
+     * @param ifName Name of the interface (e.g wlan0).
+     * @return AIDL interface object representing the interface if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_EXISTS|
+     */
+    ISupplicantP2pIface addP2pInterface(in String ifName);
+    ISupplicantStaIface addStaInterface(in String ifName);
+
+    /**
+     * Get the debug level set.
+     *
+     * @return one of |DebugLevel| values.
+     */
+    DebugLevel getDebugLevel();
+
+    /**
+     * Gets an AIDL interface object for the interface corresponding
+     * to an iface name which the supplicant already controls.
+     *
+     * @param ifName Name of the interface retrieved
+     *        using |listInterfaces|.
+     * @return AIDL interface object representing the interface if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_UNKNOWN|
+     */
+    ISupplicantP2pIface getP2pInterface(in String ifName);
+    ISupplicantStaIface getStaInterface(in String ifName);
+
+    /**
+     * Get whether the keys are shown in the debug logs or not.
+     *
+     * @return true if set, false otherwise.
+     */
+    boolean isDebugShowKeysEnabled();
+
+    /**
+     * Get whether the timestamps are shown in the debug logs or not.
+     *
+     * @return true if set, false otherwise.
+     */
+    boolean isDebugShowTimestampEnabled();
+
+    /**
+     * Retrieve a list of all interfaces controlled by the supplicant.
+     *
+     * The corresponding |ISupplicantIface| object for any interface can be
+     * retrieved using the proper |getInterface| method.
+     *
+     * @return List of all interfaces controlled by the supplicant.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    IfaceInfo[] listInterfaces();
+
+    /**
+     * Register for callbacks from the supplicant service.
+     *
+     * These callbacks are invoked for global events that are not specific
+     * to any interface or network. Registration of multiple callback
+     * objects is supported. These objects must be deleted when the corresponding
+     * client process is dead.
+     *
+     * @param callback An instance of the |ISupplicantCallback| AIDL interface
+     *        object.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void registerCallback(in ISupplicantCallback callback);
+
+    /**
+     * Deregisters a wireless interface from supplicant.
+     *
+     * @param ifaceInfo Combination of the interface type and name (e.g wlan0).
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_UNKNOWN|
+     */
+    void removeInterface(in IfaceInfo ifaceInfo);
+
+    /**
+     * Set concurrency priority.
+     *
+     * When both P2P and STA mode ifaces are active, this must be used
+     * to prioritize either STA or P2P connection to resolve conflicts
+     * arising during single channel concurrency.
+     *
+     * @param type The type of iface to prioritize.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setConcurrencyPriority(in IfaceType type);
+
+    /**
+     * Set debug parameters for the supplicant.
+     *
+     * @param level Debug logging level for the supplicant.
+     *        (one of |DebugLevel| values).
+     * @param timestamp Determines whether to show timestamps in logs or
+     *        not.
+     * @param showKeys Determines whether to show keys in debug logs or
+     *        not.
+     *        CAUTION: Do not set this param in production code!
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setDebugParams(in DebugLevel level, in boolean showTimestamp, in boolean showKeys);
+
+    /**
+     * Terminate the service.
+     * This must de-register the service and clear all state. If this HAL
+     * supports the lazy HAL protocol, then this may trigger daemon to exit and
+     * wait to be restarted.
+     */
+    oneway void terminate();
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
new file mode 100644
index 0000000..6f15900
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Callback Interface exposed by the supplicant service (ISupplicant).
+ *
+ * Clients need to host an instance of this AIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * |ISupplicant.registerCallback| method.
+ */
+@VintfStability
+interface ISupplicantCallback {
+    /**
+     * Used to indicate that a new interface has been created.
+     *
+     * @param ifaceName Name of the network interface, e.g., wlan0
+     */
+    oneway void onInterfaceCreated(in String ifaceName);
+
+    /**
+     * Used to indicate that an interface has been removed.
+     *
+     * @param ifaceName Name of the network interface, e.g., wlan0
+     */
+    oneway void onInterfaceRemoved(in String ifaceName);
+
+    /**
+     * Used to indicate that the supplicant daemon is terminating.
+     */
+    oneway void onTerminating();
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
new file mode 100644
index 0000000..64839e7
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.FreqRange;
+import android.hardware.wifi.supplicant.ISupplicantP2pIfaceCallback;
+import android.hardware.wifi.supplicant.ISupplicantP2pNetwork;
+import android.hardware.wifi.supplicant.IfaceType;
+import android.hardware.wifi.supplicant.MiracastMode;
+import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
+import android.hardware.wifi.supplicant.WpsConfigMethods;
+import android.hardware.wifi.supplicant.WpsProvisionMethod;
+
+/**
+ * Interface exposed by the supplicant for each P2P mode network
+ * interface (e.g p2p0) it controls.
+ */
+@VintfStability
+interface ISupplicantP2pIface {
+    /**
+     * This command can be used to add a bonjour service.
+     *
+     * @param query Hex dump of the query data.
+     * @param return Hex dump of the response data.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void addBonjourService(in byte[] query, in byte[] response);
+
+    /**
+     * Set up a P2P group owner manually (i.e., without group owner
+     * negotiation with a specific peer). This is also known as autonomous
+     * group owner. Optional |persistentNetworkId| may be used to specify
+     * restart of a persistent group.
+     *
+     * @param persistent Used to request a persistent group to be formed.
+     * @param persistentNetworkId Used to specify the restart of a persistent
+     *        group. Set to UINT32_MAX for a non-persistent group.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void addGroup(in boolean persistent, in int persistentNetworkId);
+
+    /**
+     * Set up a P2P group owner or join a group as a group client
+     * with the specified configuration.
+     *
+     * If joinExistingGroup is false, this device sets up a P2P group owner manually (i.e.,
+     * without group owner negotiation with a specific peer) with the specified SSID,
+     * passphrase, persistent mode, and frequency/band.
+     *
+     * If joinExistingGroup is true, this device acts as a group client and joins the group
+     * whose network name and group owner's MAC address matches the specified SSID
+     * and peer address without WPS process. If peerAddress is 00:00:00:00:00:00, the first found
+     * group whose network name matches the specified SSID is joined.
+     *
+     * @param ssid The SSID of this group.
+     * @param pskPassphrase The passphrase of this group.
+     * @param persistent Used to request a persistent group to be formed,
+     *        only applied for the group owner.
+     * @param freq The required frequency or band for this group.
+     *        only applied for the group owner.
+     *        The following values are supported:
+     *        0: automatic channel selection,
+     *        2: for 2.4GHz channels
+     *        5: for 5GHz channels
+     *        specific frequency, i.e., 2412, 5500, etc.
+     *        If an invalid band or unsupported frequency are specified, it fails.
+     * @param peerAddress the group owner's MAC address, only applied for the group client.
+     *        If the MAC is "00:00:00:00:00:00", the device must try to find a peer
+     *        whose network name matches the specified SSID.
+     * @param joinExistingGroup if true, join a group as a group client; otherwise,
+     *        create a group as a group owner.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void addGroupWithConfig(in byte[] ssid, in String pskPassphrase, in boolean persistent,
+            in int freq, in byte[] peerAddress, in boolean joinExistingGroup);
+
+    /**
+     * Add a new network to the interface.
+     *
+     * @return AIDL interface object representing the new network if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    ISupplicantP2pNetwork addNetwork();
+
+    /**
+     * This command can be used to add a UPNP service.
+     *
+     * @param version Version to be used.
+     * @package serviceName Service name to be used.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void addUpnpService(in int version, in String serviceName);
+
+    /**
+     * Cancel an ongoing P2P group formation and joining-a-group related
+     * operation. This operation unauthorizes the specific peer device (if any
+     * had been authorized to start group formation), stops P2P find (if in
+     * progress), stops pending operations for join-a-group, and removes the
+     * P2P group interface (if one was used) that is in the WPS provisioning
+     * step. If the WPS provisioning step has been completed, the group is not
+     * terminated.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NOT_STARTED|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void cancelConnect();
+
+    /**
+     * Cancel a previous service discovery request.
+     *
+     * @param identifier Identifier for the request to cancel.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NOT_STARTED|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void cancelServiceDiscovery(in long identifier);
+
+    /**
+     * Cancel any ongoing WPS operations.
+     *
+     * @param groupIfName Group interface name to use.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void cancelWps(in String groupIfName);
+
+    /**
+     * Configure Extended Listen Timing.
+     *
+     * If enabled, listen state must be entered every |intervalInMillis| for at
+     * least |periodInMillis|. Both values have acceptable range of 1-65535
+     * (with interval obviously having to be larger than or equal to duration).
+     * If the P2P module is not idle at the time the Extended Listen Timing
+     * timeout occurs, the Listen State operation must be skipped.
+     *
+     * @param periodInMillis Period in milliseconds.
+     * @param intervalInMillis Interval in milliseconds.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void configureExtListen(in int periodInMillis, in int intervalInMillis);
+
+    /**
+     * Start P2P group formation with a discovered P2P peer. This includes
+     * optional group owner negotiation, group interface setup, provisioning,
+     * and establishing data connection.
+     *
+     * @param peerAddress MAC address of the device to connect to.
+     * @param provisionMethod Provisioning method to use.
+     * @param preSelectedPin Pin to be used, if |provisionMethod| uses one of the
+     *        preselected |PIN*| methods.
+     * @param joinExistingGroup Indicates that this is a command to join an
+     *        existing group as a client. It skips the group owner negotiation
+     *        part. This must send a Provision Discovery Request message to the
+     *        target group owner before associating for WPS provisioning.
+     * @param persistent Used to request a persistent group to be formed.
+     * @param goIntent Used to override the default Intent for this group owner
+     *        negotiation (Values from 1-15). Refer to section 4.1.6 in
+     *        Wi-Fi Peer-to-Peer (P2P) Technical Specification Version 1.7.
+     * @return Pin generated, if |provisionMethod| uses one of the
+     *         generated |PIN*| methods.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    String connect(in byte[] peerAddress, in WpsProvisionMethod provisionMethod,
+            in String preSelectedPin, in boolean joinExistingGroup, in boolean persistent,
+            in int goIntent);
+
+    /**
+     * Creates a NFC handover request message.
+     *
+     * @return Bytes representing the handover request as specified in
+     *         section 3.1.1 of NFC Connection Handover 1.2 Technical
+     *         Specification.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    byte[] createNfcHandoverRequestMessage();
+
+    /**
+     * Creates a NFC handover select message.
+     *
+     * @return Bytes representing the handover select as specified in
+     *         section 3.1.2 of NFC Connection Handover 1.2 Technical
+     *         Specification.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    byte[] createNfcHandoverSelectMessage();
+
+    /**
+     * Enable/Disable Wifi Display.
+     *
+     * @param enable true to enable, false to disable.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void enableWfd(in boolean enable);
+
+    /**
+     * Initiate a P2P service discovery with an optional timeout.
+     *
+     * @param timeoutInSec Max time to be spent is performing discovery.
+     *        Set to 0 to indefinely continue discovery until an explicit
+     *        |stopFind| is sent.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void find(in int timeoutInSec);
+
+    /**
+     * Flush P2P peer table and state.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void flush();
+
+    /**
+     * This command can be used to flush all services from the
+     * device.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void flushServices();
+
+    /**
+     * Gets the MAC address of the device.
+     *
+     * @return MAC address of the device.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    byte[] getDeviceAddress();
+
+    /**
+     * Get whether EDMG(802.11ay) is enabled for this network.
+     *
+     * @return true if set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean getEdmg();
+
+    /**
+     * Gets the capability of the group which the device is a
+     * member of.
+     *
+     * @param peerAddress MAC address of the peer.
+     * @return Combination of |P2pGroupCapabilityMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    P2pGroupCapabilityMask getGroupCapability(in byte[] peerAddress);
+
+    /**
+     * Retrieves the name of the network interface.
+     *
+     * @return Name of the network interface, e.g., wlan0
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    String getName();
+
+    /**
+     * Gets an AIDL interface object for the network corresponding to the
+     * network id.
+     *
+     * Use |ISupplicantP2pNetwork.getId()| on the corresponding network AIDL
+     * interface object to retrieve the ID.
+     *
+     * @param id Network ID allocated to the corresponding network.
+     * @return AIDL interface object representing the new network if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_UNKNOWN|
+     */
+    ISupplicantP2pNetwork getNetwork(in int id);
+
+    /**
+     * Gets the operational SSID of the device.
+     *
+     * @param peerAddress MAC address of the peer.
+     * @return SSID of the device
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    byte[] getSsid(in byte[] peerAddress);
+
+    /**
+     * Retrieves the type of the network interface.
+     *
+     * @return Type of the network interface, e.g., STA.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    IfaceType getType();
+
+    /**
+     * Invite a device to a persistent group.
+     * If the peer device is the group owner of the persistent group, the peer
+     * parameter is not needed. Otherwise it is used to specify which
+     * device to invite. |goDeviceAddress| parameter may be used to override
+     * the group owner device address for Invitation Request should it not be
+     * known for some reason (this should not be needed in most cases).
+     *
+     * @param groupIfName Group interface name to use.
+     * @param goDeviceAddress MAC address of the group owner device.
+     * @param peerAddress MAC address of the device to invite.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void invite(in String groupIfName, in byte[] goDeviceAddress, in byte[] peerAddress);
+
+    /**
+     * Retrieve a list of all the network Id's controlled by the supplicant.
+     *
+     * The corresponding |ISupplicantP2pNetwork| object for any network can be
+     * retrieved using the |getNetwork| method.
+     *
+     * @return List of all network Id's controlled by the supplicant.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    int[] listNetworks();
+
+    /**
+     * Send P2P provision discovery request to the specified peer. The
+     * parameters for this command are the P2P device address of the peer and the
+     * desired configuration method.
+     *
+     * @param peerAddress MAC address of the device to send discovery.
+     * @method provisionMethod Provisioning method to use.
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void provisionDiscovery(in byte[] peerAddress, in WpsProvisionMethod provisionMethod);
+
+    /**
+     * Register for callbacks from this interface.
+     *
+     * These callbacks are invoked for events that are specific to this interface.
+     * Registration of multiple callback objects is supported. These objects must
+     * be automatically deleted when the corresponding client process is dead or
+     * if this interface is removed.
+     *
+     * @param callback An instance of the |ISupplicantP2pIfaceCallback| AIDL
+     *        interface object.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void registerCallback(in ISupplicantP2pIfaceCallback callback);
+
+    /**
+     * Reinvoke a device from a persistent group.
+     *
+     * @param persistentNetworkId Used to specify the persistent group.
+     * @param peerAddress MAC address of the device to reinvoke.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void reinvoke(in int persistentNetworkId, in byte[] peerAddress);
+
+    /**
+     * Reject connection attempt from a peer (specified with a device
+     * address). This is a mechanism to reject a pending group owner negotiation
+     * with a peer and request to automatically block any further connection or
+     * discovery of the peer.
+     *
+     * @param peerAddress MAC address of the device to reject.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void reject(in byte[] peerAddress);
+
+    /**
+     * This command can be used to remove a bonjour service.
+     *
+     * @param query Hex dump of the query data.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NOT_STARTED|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void removeBonjourService(in byte[] query);
+
+    /**
+     * Terminate a P2P group. If a new virtual network interface was used for
+     * the group, it must also be removed. The network interface name of the
+     * group interface is used as a parameter for this command.
+     *
+     * @param groupIfName Group interface name to use.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void removeGroup(in String groupIfName);
+
+    /**
+     * Remove a network from the interface.
+     *
+     * Use |ISupplicantP2pNetwork.getId()| on the corresponding network AIDL
+     * interface object to retrieve the ID.
+     *
+     * @param id Network ID allocated to the corresponding network.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_UNKNOWN|
+     */
+    void removeNetwork(in int id);
+
+    /**
+     * This command can be used to remove a UPNP service.
+     *
+     * @param version Version to be used.
+     * @package serviceName Service name to be used.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NOT_STARTED|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void removeUpnpService(in int version, in String serviceName);
+
+    /**
+     * Report the initiation of the NFC handover select.
+     *
+     * @param select Bytes representing the handover select as specified in
+     *        section 3.1.2 of NFC Connection Handover 1.2 Technical
+     *        Specification.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void reportNfcHandoverInitiation(in byte[] select);
+
+    /**
+     * Report the response of the NFC handover request.
+     *
+     * @param request Bytes representing the handover request as specified in
+     *        section 3.1.1 of NFC Connection Handover 1.2 Technical
+     *        Specification.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void reportNfcHandoverResponse(in byte[] request);
+
+    /**
+     * Schedule a P2P service discovery request. The parameters for this command
+     * are the device address of the peer device (or 00:00:00:00:00:00 for
+     * wildcard query that is sent to every discovered P2P peer that supports
+     * service discovery) and P2P Service Query TLV(s) as hexdump.
+     *
+     * @param peerAddress MAC address of the device to discover.
+     * @param query Hex dump of the query data.
+     * @return Identifier for the request. Can be used to cancel the
+     *         request.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    long requestServiceDiscovery(in byte[] peerAddress, in byte[] query);
+
+    /**
+     * Persist the current configuration to disk.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void saveConfig();
+
+    /**
+     * Set P2P disallowed frequency ranges.
+     *
+     * Specify ranges of frequencies that are disallowed for any P2P operations.
+     *
+     * @param ranges List of ranges which needs to be disallowed.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setDisallowedFrequencies(in FreqRange[] ranges);
+
+    /**
+     * Set whether to enable EDMG(802.11ay). Only allowed if hw mode is |HOSTAPD_MODE_IEEE80211AD|
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEdmg(in boolean enable);
+
+    /**
+     * Set the Maximum idle time in seconds for P2P groups.
+     * This value controls how long a P2P group is maintained after there
+     * is no other members in the group. As a group owner, this means no
+     * associated stations in the group. As a P2P client, this means no
+     * group owner seen in scan results.
+     *
+     * @param groupIfName Group interface name to use.
+     * @param timeoutInSec Timeout value in seconds.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setGroupIdle(in String groupIfName, in int timeoutInSec);
+
+    /**
+     * Set P2P Listen channel.
+     *
+     * When specifying a social channel on the 2.4 GHz band (1/6/11) there is no
+     * need to specify the operating class since it defaults to 81. When
+     * specifying a social channel on the 60 GHz band (2), specify the 60 GHz
+     * operating class (180).
+     *
+     * @param channel Wifi channel. eg, 1, 6, 11.
+     * @param operatingClass Operating Class indicates the channel set of the AP
+     *        indicated by this BSSID
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setListenChannel(in int channel, in int operatingClass);
+
+    /**
+     * Set MAC randomization enabled/disabled.
+     *
+     * @param enable true to enable, false to disable.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setMacRandomization(in boolean enable);
+
+    /**
+     * Send driver command to set Miracast mode.
+     *
+     * @param mode Mode of Miracast.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setMiracastMode(in MiracastMode mode);
+
+    /**
+     * Turn on/off power save mode for the interface.
+     *
+     * @param groupIfName Group interface name to use.
+     * @param enable Indicate if power save is to be turned on/off.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void setPowerSave(in String groupIfName, in boolean enable);
+
+    /**
+     * Set the postfix to be used for P2P SSID's.
+     *
+     * @param postfix String to be appended to SSID.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setSsidPostfix(in byte[] postfix);
+
+    /**
+     * Set Wifi Display device info.
+     *
+     * @param info WFD device info as described in section 5.1.2 of WFD technical
+     *        specification v1.0.0.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setWfdDeviceInfo(in byte[] info);
+
+    /**
+     * Set Wifi Display R2 device info.
+     *
+     * @param info WFD R2 device info as described in section 5.1.12 of WFD technical
+     *        specification v2.1.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setWfdR2DeviceInfo(in byte[] info);
+
+    /**
+     * Set the list of supported config methods for WPS operations.
+     *
+     * @param configMethods Mask of WPS configuration methods supported by the
+     *        device.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsConfigMethods(in WpsConfigMethods configMethods);
+
+    /**
+     * Set the device name for WPS operations.
+     * User-friendly description of device (up to |WPS_DEVICE_NAME_MAX_LEN|
+     * octets encoded in UTF-8).
+     *
+     * @param name Name to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsDeviceName(in String name);
+
+    /**
+     * Set the device type for WPS operations.
+     *
+     * @param type Type of device. Refer to section B.1 of Wifi P2P
+     *       Technical specification v1.2.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsDeviceType(in byte[] type);
+
+    /**
+     * Set the manufacturer for WPS operations.
+     * The manufacturer of the device (up to |WPS_MANUFACTURER_MAX_LEN| ASCII
+     * characters).
+     *
+     * @param manufacturer Manufacture to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsManufacturer(in String manufacturer);
+
+    /**
+     * Set the model name for WPS operations.
+     * Model of the device (up to |WPS_MODEL_NAME_MAX_LEN| ASCII characters).
+     *
+     * @param modelName Model name to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsModelName(in String modelName);
+
+    /**
+     * Set the model number for WPS operations.
+     * Additional device description (up to |WPS_MODEL_NUMBER_MAX_LEN| ASCII
+     * characters).
+     *
+     * @param modelNumber Model number to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsModelNumber(in String modelNumber);
+
+    /**
+     * Set the serial number for WPS operations.
+     * Serial number of the device (up to |WPS_SERIAL_NUMBER_MAX_LEN| characters)
+     *
+     * @param serialNumber Serial number to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsSerialNumber(in String serialNumber);
+
+    /**
+     * Initiate WPS Push Button setup.
+     * The PBC operation requires that a button is also pressed at the
+     * AP/Registrar at about the same time (2 minute window).
+     *
+     * @param groupIfName Group interface name to use.
+     * @param bssid BSSID of the AP. Use zero'ed bssid to indicate wildcard.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void startWpsPbc(in String groupIfName, in byte[] bssid);
+
+    /**
+     * Initiate WPS Pin Display setup.
+     *
+     * @param groupIfName Group interface name to use.
+     * @param bssid BSSID of the AP. Use zero'ed bssid to indicate wildcard.
+     * @return 8 digit pin generated.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    String startWpsPinDisplay(in String groupIfName, in byte[] bssid);
+
+    /**
+     * Initiate WPS Pin Keypad setup.
+     *
+     * @param groupIfName Group interface name to use.
+     * @param pin 8 digit pin to be used.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void startWpsPinKeypad(in String groupIfName, in String pin);
+
+    /**
+     * Stop an ongoing P2P service discovery.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void stopFind();
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
new file mode 100644
index 0000000..2b58cc2
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
+import android.hardware.wifi.supplicant.P2pProvDiscStatusCode;
+import android.hardware.wifi.supplicant.P2pStatusCode;
+import android.hardware.wifi.supplicant.WpsConfigMethods;
+import android.hardware.wifi.supplicant.WpsDevPasswordId;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each P2P mode interface (ISupplicantP2pIface).
+ *
+ * Clients need to host an instance of this AIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantP2pIface.registerCallback| method.
+ */
+@VintfStability
+interface ISupplicantP2pIfaceCallback {
+    /**
+     * Used to indicate that a P2P device has been found.
+     *
+     * @param srcAddress MAC address of the device found. This must either
+     *        be the P2P device address or the P2P interface address.
+     * @param p2pDeviceAddress P2P device address.
+     * @param primaryDeviceType Type of device. Refer to section B.1 of Wifi P2P
+     *        Technical specification v1.2.
+     * @param deviceName Name of the device.
+     * @param configMethods Mask of WPS configuration methods supported by the
+     *        device.
+     * @param deviceCapabilities Refer to section 4.1.4 of Wifi P2P Technical
+     *        specification v1.2.
+     * @param groupCapabilites Refer to section 4.1.4 of Wifi P2P Technical
+     *        specification v1.2.
+     * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD
+     *        technical specification v1.0.0.
+     */
+    oneway void onDeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress,
+            in byte[] primaryDeviceType, in String deviceName, in WpsConfigMethods configMethods,
+            in byte deviceCapabilities, in P2pGroupCapabilityMask groupCapabilities,
+            in byte[] wfdDeviceInfo);
+
+    /**
+     * Used to indicate that a P2P device has been lost.
+     *
+     * @param p2pDeviceAddress P2P device address.
+     */
+    oneway void onDeviceLost(in byte[] p2pDeviceAddress);
+
+    /**
+     * Used to indicate the termination of P2P find operation.
+     */
+    oneway void onFindStopped();
+
+    /**
+     * Used to indicate the completion of a P2P Group Owner negotiation request.
+     *
+     * @param status Status of the GO negotiation.
+     */
+    oneway void onGoNegotiationCompleted(in P2pStatusCode status);
+
+    /**
+     * Used to indicate the reception of a P2P Group Owner negotiation request.
+     *
+     * @param srcAddress MAC address of the device that initiated the GO
+     *        negotiation request.
+     * @param passwordId Type of password.
+     */
+    oneway void onGoNegotiationRequest(in byte[] srcAddress, in WpsDevPasswordId passwordId);
+
+    /**
+     * Used to indicate a failure to form a P2P group.
+     *
+     * @param failureReason Failure reason string for debug purposes.
+     */
+    oneway void onGroupFormationFailure(in String failureReason);
+
+    /**
+     * Used to indicate a successful formation of a P2P group.
+     */
+    oneway void onGroupFormationSuccess();
+
+    /**
+     * Used to indicate the removal of a P2P group.
+     *
+     * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1)
+     * @param isGroupOwner Whether this device is owner of the group.
+     */
+    oneway void onGroupRemoved(in String groupIfname, in boolean isGroupOwner);
+
+    /**
+     * Used to indicate the start of a P2P group.
+     *
+     * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1)
+     * @param isGroupOwner Whether this device is owner of the group.
+     * @param ssid SSID of the group.
+     * @param frequency Frequency on which this group is created.
+     * @param psk PSK used to secure the group.
+     * @param passphrase PSK passphrase used to secure the group.
+     * @param goDeviceAddress MAC Address of the owner of this group.
+     * @param isPersistent Whether this group is persisted or not.
+     */
+    oneway void onGroupStarted(in String groupIfname, in boolean isGroupOwner, in byte[] ssid,
+            in int frequency, in byte[] psk, in String passphrase, in byte[] goDeviceAddress,
+            in boolean isPersistent);
+
+    /**
+     * Used to indicate the reception of a P2P invitation.
+     *
+     * @param srcAddress MAC address of the device that sent the invitation.
+     * @param goDeviceAddress MAC Address of the owner of this group.
+     * @param bssid Bssid of the group.
+     * @param persistentNetworkId Persistent network Id of the group.
+     * @param operatingFrequency Frequency on which the invitation was received.
+     */
+    oneway void onInvitationReceived(in byte[] srcAddress, in byte[] goDeviceAddress,
+            in byte[] bssid, in int persistentNetworkId, in int operatingFrequency);
+
+    /**
+     * Used to indicate the result of the P2P invitation request.
+     *
+     * @param bssid Bssid of the group.
+     * @param status Status of the invitation.
+     */
+    oneway void onInvitationResult(in byte[] bssid, in P2pStatusCode status);
+
+    /**
+     * Used to indicate the completion of a P2P provision discovery request.
+     *
+     * @param p2pDeviceAddress P2P device address.
+     * @param isRequest Whether we received or sent the provision discovery.
+     * @param status Status of the provision discovery.
+     * @param configMethods Mask of WPS configuration methods supported.
+     * @param generatedPin 8 digit pin generated.
+     */
+    oneway void onProvisionDiscoveryCompleted(in byte[] p2pDeviceAddress, in boolean isRequest,
+            in P2pProvDiscStatusCode status, in WpsConfigMethods configMethods,
+            in String generatedPin);
+
+    /**
+     * Used to indicate that a P2P Wi-Fi Display R2 device has been found. Refer to
+     * Wi-Fi Display Technical Specification Version 2.0.
+     *
+     * @param srcAddress MAC address of the device found. This must either
+     *        be the P2P device address for a peer which is not in a group,
+     *        or the P2P interface address for a peer which is a Group Owner.
+     * @param p2pDeviceAddress P2P device address.
+     * @param primaryDeviceType Type of device. Refer to section B.1 of Wifi P2P
+     *        Technical specification v1.2.
+     * @param deviceName Name of the device.
+     * @param configMethods Mask of WPS configuration methods supported by the
+     *        device.
+     * @param deviceCapabilities Refer to section 4.1.4 of Wifi P2P Technical
+     *        specification v1.2.
+     * @param groupCapabilites Refer to section 4.1.4 of Wifi P2P Technical
+     *        specification v1.2.
+     * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD
+     *        technical specification v1.0.0.
+     * @param wfdR2DeviceInfo WFD R2 device info as described in section 5.1.12 of WFD
+     *        technical specification v2.1.
+     */
+    oneway void onR2DeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress,
+            in byte[] primaryDeviceType, in String deviceName, in WpsConfigMethods configMethods,
+            in byte deviceCapabilities, in P2pGroupCapabilityMask groupCapabilities,
+            in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo);
+
+    /**
+     * Used to indicate the reception of a P2P service discovery response.
+     *
+     * @param srcAddress MAC address of the device that sent the service discovery.
+     * @param updateIndicator Service update indicator. Refer to section 3.1.3 of
+     *        Wifi P2P Technical specification v1.2.
+     * @parm tlvs Refer to section 3.1.3.1 of Wifi P2P Technical specification v1.2.
+     */
+    oneway void onServiceDiscoveryResponse(
+            in byte[] srcAddress, in char updateIndicator, in byte[] tlvs);
+
+    /**
+     * Used to indicate when a STA device is connected to this device.
+     *
+     * @param srcAddress MAC address of the device that was authorized.
+     * @param p2pDeviceAddress P2P device address.
+     */
+    oneway void onStaAuthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
+
+    /**
+     * Used to indicate when a STA device is disconnected from this device.
+     *
+     * @param srcAddress MAC address of the device that was deauthorized.
+     * @param p2pDeviceAddress P2P device address.
+     */
+    oneway void onStaDeauthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
+
+    /**
+     * Used to indicate that operating frequency has changed for this P2P group interface.
+     *
+     * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1)
+     * @param frequency New operating frequency in MHz.
+     */
+    oneway void onGroupFrequencyChanged(in String groupIfname, in int frequency);
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pNetwork.aidl
new file mode 100644
index 0000000..f037252
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pNetwork.aidl
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.IfaceType;
+import android.hardware.wifi.supplicant.MacAddress;
+
+/**
+ * Interface exposed by the supplicant for each P2P mode network
+ * configuration it controls.
+ */
+@VintfStability
+interface ISupplicantP2pNetwork {
+    /**
+     * Get the BSSID set for this network.
+     *
+     * @return bssid Value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getBssid();
+
+    /**
+     * Get the list of P2P Clients in a persistent group (GO).
+     * This is a list of P2P Clients (P2P Device Address) that have joined
+     * the persistent group. This is maintained on the GO for persistent
+     * group entries (disabled == 2).
+     *
+     * @return MAC addresses of the clients.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantP2ptusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    MacAddress[] getClientList();
+
+    /**
+     * Retrieves the ID allocated to this network by the supplicant.
+     *
+     * This is not the |SSID| of the network, but an internal identifier for
+     * this network used by the supplicant.
+     *
+     * @return Network ID.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    int getId();
+
+    /**
+     * Retrieves the name of the interface this network belongs to.
+     *
+     * @return Name of the network interface, e.g., wlan0
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getInterfaceName();
+
+    /**
+     * Getters for the various network params.
+     *
+     *
+     * Get SSID for this network.
+     *
+     * @return ssid value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getSsid();
+
+    /**
+     * Retrieves the type of the interface this network belongs to.
+     *
+     * @return Type of the network interface, e.g., STA.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    IfaceType getType();
+
+    /**
+     * Check if the network is currently active one.
+     *
+     * @return true if current, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean isCurrent();
+
+    /**
+     * Check if the device is the group owner of the network.
+     *
+     * @return true if group owner, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean isGroupOwner();
+
+    /**
+     * Check if the network is marked persistent.
+     *
+     * @return true if persistent, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean isPersistent();
+
+    /**
+     * Set the list of P2P Clients in a persistent group (GO).
+     * This is a list of P2P Clients (P2P Device Address) that have joined
+     * the persistent group. This is maintained on the GO for persistent
+     * group entries (disabled == 2).
+     *
+     * @param clients MAC address of the clients.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantP2ptusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setClientList(in MacAddress[] clients);
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
new file mode 100644
index 0000000..b48fa04
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.AnqpInfoId;
+import android.hardware.wifi.supplicant.BtCoexistenceMode;
+import android.hardware.wifi.supplicant.ConnectionCapabilities;
+import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppCurve;
+import android.hardware.wifi.supplicant.DppNetRole;
+import android.hardware.wifi.supplicant.DppResponderBootstrapInfo;
+import android.hardware.wifi.supplicant.Hs20AnqpSubtypes;
+import android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback;
+import android.hardware.wifi.supplicant.ISupplicantStaNetwork;
+import android.hardware.wifi.supplicant.IfaceType;
+import android.hardware.wifi.supplicant.KeyMgmtMask;
+import android.hardware.wifi.supplicant.RxFilterType;
+import android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask;
+import android.hardware.wifi.supplicant.WpsConfigMethods;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+@VintfStability
+interface ISupplicantStaIface {
+    /**
+     * Add a DPP peer URI. URI is acquired externally, e.g. by scanning a QR code
+     *
+     * @param uri Peer's DPP URI.
+     * @return ID for the URI
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    int addDppPeerUri(in String uri);
+
+    /**
+     * External programs can request supplicant to not start offchannel
+     * operations during other tasks that may need exclusive control of the
+     * radio.
+     *
+     * This method can be used to reserve a slot for radio access. If freq is
+     * specified, other radio work items on the same channel can be completed in
+     * parallel. Otherwise, all other radio work items are blocked during
+     * execution. Timeout must be set to |ExtRadioWorkDefaults.TIMEOUT_IN_SECS|
+     * seconds by default to avoid blocking supplicant operations on the iface
+     * for excessive time. If a longer (or shorter) safety timeout is needed,
+     * that may be specified with the optional timeout parameter. This command
+     * returns an identifier for the radio work item.
+     *
+     * Once the radio work item has been started,
+     * |ISupplicant.onExtRadioWorkStart| callback is indicated that the external
+     * processing can start.
+     *
+     * @param name Name for the radio work being added.
+     * @param freqInMhz Frequency to specify. Set to 0 for all channels.
+     * @param timeoutInSec Timeout to specify. Set to 0 for default timeout.
+     * @return Identifier for this radio work.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    int addExtRadioWork(in String name, in int freqInMhz, in int timeoutInSec);
+
+    /**
+     * Add a new network to the interface.
+     *
+     * @return AIDL interface object representing the new network if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    ISupplicantStaNetwork addNetwork();
+
+    /**
+     * Send driver command to add the specified RX filter.
+     *
+     * @param type Type of filter.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void addRxFilter(in RxFilterType type);
+
+    /**
+     * Cancel any ongoing WPS operations.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void cancelWps();
+
+    /**
+     * Disconnect from the current active network.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void disconnect();
+
+    /**
+     * Enable/Disable auto reconnect to networks.
+     * Use this to prevent wpa_supplicant from trying to connect to networks
+     * on its own.
+     *
+     * @param enable true to enable, false to disable.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void enableAutoReconnect(in boolean enable);
+
+    /**
+     * Add fast initial link setup (IEEE 802.11ai FILS) HLP packets.
+     * Use this to add higher layer protocol (HLP) packet in FILS (Re)Association Request frame
+     * (Eg: DHCP discover packet).
+     *
+     * @param dst_mac MAC address of the destination
+     * @param pkt The contents of the HLP packet starting from ethertype
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void filsHlpAddRequest(in byte[] dst_mac, in byte[] pkt);
+
+    /**
+     * Flush fast initial link setup (IEEE 802.11ai FILS) HLP packets.
+     * Use this to flush all the higher layer protocol (HLP) packets added in
+     * wpa_supplicant to send in FILS (Re)Association Request frame
+     * (Eg: DHCP discover packet).
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void filsHlpFlushRequest();
+
+    /**
+     * Generates DPP bootstrap information: Bootstrap ID, DPP URI and listen
+     * channel for responder mode.
+     *
+     * @param macAddress MAC address of the interface for the DPP operation.
+     * @param deviceInfo Device specific information.
+     *        As per DPP Specification V1.0 section 5.2,
+     *        allowed Range of ASCII characters in deviceInfo - %x20-7E
+     *        semicolon is not allowed.
+     * @param curve Elliptic curve cryptography type used to generate DPP
+     *        public/private key pair.
+     * @return Bootstrap info.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     *         |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+     */
+    DppResponderBootstrapInfo generateDppBootstrapInfoForResponder(
+            in byte[] macAddress, in String deviceInfo, in DppCurve curve);
+
+    /**
+     * Get Connection capabilities
+     *
+     * @return Connection capabilities.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    ConnectionCapabilities getConnectionCapabilities();
+
+    /**
+     * Get Key management capabilities of the device
+     *
+     * @return Bitmap of key management mask.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    KeyMgmtMask getKeyMgmtCapabilities();
+
+    /**
+     * Send driver command to get MAC address of the device.
+     *
+     * @return MAC address of the device.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    byte[] getMacAddress();
+
+    /**
+     * Retrieves the name of the network interface.
+     *
+     * @return Name of the network interface, e.g., wlan0
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    String getName();
+
+    /**
+     * Gets an AIDL interface object for the network corresponding to the
+     * network id.
+     *
+     * Use |ISupplicantStaNetwork.getId()| on the corresponding network AIDL
+     * interface object to retrieve the ID.
+     *
+     * @param id Network ID allocated to the corresponding network.
+     * @return AIDL interface object representing the new network if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_UNKNOWN|
+     */
+    ISupplicantStaNetwork getNetwork(in int id);
+
+    /**
+     * Retrieves the type of the network interface.
+     *
+     * @return Type of the network interface, e.g., STA.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    IfaceType getType();
+
+    /**
+     * Get wpa driver capabilities.
+     *
+     * @return Bitmap of wpa driver features.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    WpaDriverCapabilitiesMask getWpaDriverCapabilities();
+
+    /**
+     * Initiate ANQP (for IEEE 802.11u Interworking/Hotspot 2.0) queries with the
+     * specified access point.
+     * The ANQP data fetched must be returned in the
+     * |ISupplicantStaIfaceCallback.onAnqpQueryDone| callback.
+     *
+     * @param macAddress MAC address of the access point.
+     * @param infoElements List of information elements to query for.
+     * @param subtypes List of HS20 subtypes to query for.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void initiateAnqpQuery(
+            in byte[] macAddress, in AnqpInfoId[] infoElements, in Hs20AnqpSubtypes[] subTypes);
+
+    /**
+     * Initiate the Hotspot 2.0 icon query with the specified accesss point.
+     * The icon data fetched must be returned in the
+     * |ISupplicantStaIfaceCallback.onHs20IconQueryDone| callback.
+     *
+     * @param macAddress MAC address of the access point.
+     * @param fileName Name of the file to request from the access point.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void initiateHs20IconQuery(in byte[] macAddress, in String fileName);
+
+    /**
+     * Initiate TDLS discover with the provided peer MAC address.
+     *
+     * @param macAddress MAC address of the peer.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void initiateTdlsDiscover(in byte[] macAddress);
+
+    /**
+     * Initiate TDLS setup with the provided peer MAC address.
+     *
+     * @param macAddress MAC address of the peer.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void initiateTdlsSetup(in byte[] macAddress);
+
+    /**
+     * Initiate TDLS teardown with the provided peer MAC address.
+     *
+     * @param macAddress MAC address of the peer.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void initiateTdlsTeardown(in byte[] macAddress);
+
+    /**
+     * Initiate Venue URL ANQP (for IEEE 802.11u Interworking/Hotspot 2.0) query with the
+     * specified access point. This specific query can be used only post connection, once security
+     * is established and PMF is enabled, to avoid spoofing preassociation ANQP responses.
+     * The ANQP data fetched must be returned in the
+     * |ISupplicantStaIfaceCallback.onAnqpQueryDone| callback.
+     *
+     * @param macAddress MAC address of the access point.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void initiateVenueUrlAnqpQuery(in byte[] macAddress);
+
+    /**
+     * Retrieve a list of all the network Id's controlled by the supplicant.
+     *
+     * The corresponding |ISupplicantStaNetwork| object for any network can be
+     * retrieved using |getNetwork| method.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return List of all network Id's controlled by the supplicant.
+     */
+    int[] listNetworks();
+
+    /**
+     * Reconnect to the currently active network, even if we are already
+     * connected.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void reassociate();
+
+    /**
+     * Reconnect to the currently active network, if we are currently
+     * disconnected.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_NOT_DISCONNECTED|
+     */
+    void reconnect();
+
+    /**
+     * Register for callbacks from this interface.
+     *
+     * These callbacks are invoked for events that are specific to this interface.
+     * Registration of multiple callback objects is supported. These objects must
+     * be automatically deleted when the corresponding client process is dead or
+     * if this interface is removed.
+     *
+     * @param callback An instance of the |ISupplicantStaIfaceCallback| AIDL
+     *        interface object.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void registerCallback(in ISupplicantStaIfaceCallback callback);
+
+    /**
+     * Remove a DPP peer URI.
+     *
+     * @param id The ID of the URI, as returned by |addDppPeerUri|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void removeDppUri(in int id);
+
+    /**
+     * Indicates to supplicant that the external radio work has completed.
+     * This allows other radio works to be performed. If this method is not
+     * invoked (e.g., due to the external program terminating), supplicant
+     * must time out the radio work item on the iface and send
+     * |ISupplicantCallback.onExtRadioWorkTimeout| event to indicate
+     * that this has happened.
+     *
+     * This method may also be used to cancel items that have been scheduled
+     * via |addExtRadioWork|, but have not yet been started (notified via
+     * |ISupplicantCallback.onExtRadioWorkStart|).
+     *
+     * @param id Identifier generated for the radio work addition
+     *         (using |addExtRadioWork|).
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void removeExtRadioWork(in int id);
+
+    /**
+     * Remove a network from the interface.
+     *
+     * Use |ISupplicantStaNetwork.getId()| on the corresponding network AIDL
+     * interface object to retrieve the ID.
+     *
+     * @param id Network ID allocated to the corresponding network.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_UNKNOWN|
+     */
+    void removeNetwork(in int id);
+
+    /**
+     * Send driver command to remove the specified RX filter.
+     *
+     * @param type Type of filter.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void removeRxFilter(in RxFilterType type);
+
+    /**
+     * Send driver command to set Bluetooth coexistence mode.
+     *
+     * @param mode Mode of Bluetooth coexistence.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setBtCoexistenceMode(in BtCoexistenceMode mode);
+
+    /**
+     * Send driver command to set Bluetooth coexistence scan mode.
+     * When this mode is on, some of the low-level scan parameters
+     * used by the driver are changed to reduce interference
+     * with A2DP streaming.
+     *
+     * @param enable true to enable, false to disable.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setBtCoexistenceScanModeEnabled(in boolean enable);
+
+    /**
+     * Send driver command to set country code.
+     *
+     * @param code 2 byte country code (as defined in ISO 3166) to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setCountryCode(in byte[] code);
+
+    /**
+     * Use external processing for SIM/USIM operations
+     *
+     * @param useExternalSim true to use external, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setExternalSim(in boolean useExternalSim);
+
+    /**
+     * Set Wi-Fi Alliance Agile Multiband (MBO) cellular data status.
+     *
+     * @param available true means cellular data available, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setMboCellularDataStatus(in boolean available);
+
+    /**
+     * Turn on/off power save mode for the interface.
+     *
+     * @param enable Indicate if power save is to be turned on/off.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void setPowerSave(in boolean enable);
+
+    /**
+     * Send driver command to set suspend optimizations for power save.
+     *
+     * @param enable true to enable, false to disable.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void setSuspendModeEnabled(in boolean enable);
+
+    /**
+     * Set the list of supported config methods for WPS operations.
+     *
+     * @param configMethods Mask of WPS configuration methods supported by the
+     *        device.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsConfigMethods(in WpsConfigMethods configMethods);
+
+    /**
+     * Set the device name for WPS operations.
+     * User-friendly description of device (up to |WPS_DEVICE_NAME_MAX_LEN|
+     * octets encoded in UTF-8).
+     *
+     * @parm name Name to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsDeviceName(in String name);
+
+    /**
+     * Set the device type for WPS operations.
+     *
+     * @parm type Type of device. Refer to section B.1 of Wifi P2P
+     *       Technical specification v1.2.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsDeviceType(in byte[] type);
+
+    /**
+     * Set the manufacturer for WPS operations.
+     * The manufacturer of the device (up to |WPS_MANUFACTURER_MAX_LEN| ASCII
+     * characters).
+     *
+     * @parm manufacturer Manufacture to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsManufacturer(in String manufacturer);
+
+    /**
+     * Set the model name for WPS operations.
+     * Model of the device (up to |WPS_MODEL_NAME_MAX_LEN| ASCII characters).
+     *
+     * @parm modelName Model name to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsModelName(in String modelName);
+
+    /**
+     * Set the model number for WPS operations.
+     * Additional device description (up to |WPS_MODEL_NUMBER_MAX_LEN| ASCII
+     * characters).
+     *
+     * @parm modelNumber Model number to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsModelNumber(in String modelNumber);
+
+    /**
+     * Set the serial number for WPS operations.
+     * Serial number of the device (up to |WPS_SERIAL_NUMBER_MAX_LEN| characters)
+     *
+     * @parm serialNumber Serial number to be set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWpsSerialNumber(in String serialNumber);
+
+    /**
+     * Start DPP in Configurator-Initiator mode.
+     *
+     * @param peerBootstrapId Peer device's URI ID.
+     * @param ownBootstrapId Local device's URI ID (0 for none, optional).
+     * @param ssid Network SSID to send to peer (SAE/PSK mode).
+     * @param password Network password to send to peer (SAE/PSK mode).
+     * @param psk Network PSK to send to peer (PSK mode only). Either password or psk should be set.
+     * @param netRole Role to configure the peer, |DppNetRole.DPP_NET_ROLE_STA| or
+     *        |DppNetRole.DPP_NET_ROLE_AP|.
+     * @param securityAkm Security AKM to use (See DppAkm).
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void startDppConfiguratorInitiator(in int peerBootstrapId, in int ownBootstrapId,
+            in String ssid, in String password, in String psk, in DppNetRole netRole,
+            in DppAkm securityAkm);
+
+    /**
+     * Start DPP in Enrollee-Initiator mode.
+     *
+     * @param peerBootstrapId Peer device's URI ID.
+     * @param ownBootstrapId Local device's URI ID (0 for none, optional).
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void startDppEnrolleeInitiator(in int peerBootstrapId, in int ownBootstrapId);
+
+    /**
+     * Start DPP in Enrollee-Responder mode.
+     * Framework must first call |generateDppBootstrapInfoForResponder| to generate
+     * the bootstrapping information: Bootstrap ID, DPP URI and the listen channel.
+     * Then call this API with derived listen channel to start listening for
+     * authentication request from Peer initiator.
+     *
+     * @param listenChannel DPP listen channel.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+     */
+    void startDppEnrolleeResponder(in int listenChannel);
+
+    /**
+     * Send driver command to start RX filter.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void startRxFilter();
+
+    /**
+     * Initiate WPS Push Button setup.
+     * The PBC operation requires that a button is also pressed at the
+     * AP/Registrar at about the same time (2 minute window).
+     *
+     * @param bssid BSSID of the AP. Use zero'ed bssid to indicate wildcard.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void startWpsPbc(in byte[] bssid);
+
+    /**
+     * Initiate WPS Pin Display setup.
+     *
+     * @param bssid BSSID of the AP. Use zero'ed bssid to indicate wildcard.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     * @return 8 digit pin generated.
+     */
+    String startWpsPinDisplay(in byte[] bssid);
+
+    /**
+     * Initiate WPS Pin Keypad setup.
+     *
+     * @param pin 8 digit pin to be used.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void startWpsPinKeypad(in String pin);
+
+    /**
+     * Initiate WPS setup in registrar role to learn the current AP configuration.
+     *
+     * @param bssid BSSID of the AP.
+     * @param pin Pin of the AP.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void startWpsRegistrar(in byte[] bssid, in String pin);
+
+    /**
+     * Stop DPP Initiator operation.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void stopDppInitiator();
+
+    /**
+     * Stop DPP Responder operation - Remove the bootstrap code and stop listening.
+     *
+     * @param ownBootstrapId Local device's URI ID obtained through
+     *        |generateDppBootstrapInfoForResponder| call.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+     */
+    void stopDppResponder(in int ownBootstrapId);
+
+    /**
+     * Send driver command to stop RX filter.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void stopRxFilter();
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
new file mode 100644
index 0000000..594fef9
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.AnqpData;
+import android.hardware.wifi.supplicant.AssociationRejectionData;
+import android.hardware.wifi.supplicant.BssTmData;
+import android.hardware.wifi.supplicant.BssidChangeReason;
+import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppEventType;
+import android.hardware.wifi.supplicant.DppFailureCode;
+import android.hardware.wifi.supplicant.DppProgressCode;
+import android.hardware.wifi.supplicant.Hs20AnqpData;
+import android.hardware.wifi.supplicant.OsuMethod;
+import android.hardware.wifi.supplicant.StaIfaceCallbackState;
+import android.hardware.wifi.supplicant.StaIfaceReasonCode;
+import android.hardware.wifi.supplicant.WpsConfigError;
+import android.hardware.wifi.supplicant.WpsErrorIndication;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each station mode interface (ISupplicantStaIface).
+ *
+ * Clients need to host an instance of this AIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantStaIface.registerCallback| method.
+ */
+@VintfStability
+interface ISupplicantStaIfaceCallback {
+    /**
+     * Used to indicate the result of ANQP (either for IEEE 802.11u Interworking
+     * or Hotspot 2.0) query.
+     *
+     * @param bssid BSSID of the access point.
+     * @param data ANQP data fetched from the access point.
+     *        All the fields in this struct must be empty if the query failed.
+     * @param hs20Data ANQP data fetched from the Hotspot 2.0 access point.
+     *        All the fields in this struct must be empty if the query failed.
+     */
+    oneway void onAnqpQueryDone(in byte[] bssid, in AnqpData data, in Hs20AnqpData hs20Data);
+
+    /**
+     * Used to indicate an association rejection received from the AP
+     * to which the connection is being attempted.
+     *
+     * @param assocRejectData Association Rejection related information.
+     */
+    oneway void onAssociationRejected(in AssociationRejectionData assocRejectData);
+
+    /**
+     * Used to indicate the timeout of authentication to an AP.
+     *
+     * @param bssid BSSID of the corresponding AP.
+     */
+    oneway void onAuthenticationTimeout(in byte[] bssid);
+
+    /**
+     * Indicates BTM request frame handling status.
+     *
+     * @param tmData Data retrieved from received BSS transition management
+     * request frame.
+     */
+    oneway void onBssTmHandlingDone(in BssTmData tmData);
+
+    /**
+     * Used to indicate the change of active bssid.
+     * This is useful to figure out when the driver/firmware roams to a bssid
+     * on its own.
+     *
+     * @param reason Reason why the bssid changed.
+     * @param bssid BSSID of the corresponding AP.
+     */
+    oneway void onBssidChanged(in BssidChangeReason reason, in byte[] bssid);
+
+    /**
+     * Used to indicate the disconnection from the currently connected
+     * network on this iface.
+     *
+     * @param bssid BSSID of the AP from which we disconnected.
+     * @param locallyGenerated If the disconnect was triggered by
+     *        wpa_supplicant.
+     * @param reasonCode 802.11 code to indicate the disconnect reason
+     *        from access point. Refer to section 8.4.1.7 of IEEE802.11 spec.
+     */
+    oneway void onDisconnected(
+            in byte[] bssid, in boolean locallyGenerated, in StaIfaceReasonCode reasonCode);
+
+    /**
+     * Indicates a DPP failure event.
+     *
+     * ssid: A string indicating the SSID for the AP that the Enrollee attempted to connect.
+     * channelList: A string containing a list of operating channels and operating classes
+     *     indicating the channels that the Enrollee scanned in attempting to discover the AP.
+     *     The list conforms to the following ABNF syntax:
+     *         channel-list2 = class-and-channels *(“,” class-and-channels)
+     *         class-and-channels = class “/” channel *(“,” channel)
+     *         class = 1*3DIGIT
+     *         channel = 1*3DIGIT
+     * bandList: A list of band parameters that are supported by the Enrollee expressed as the
+     *     Operating Class.
+     */
+    oneway void onDppFailure(
+            in DppFailureCode code, in String ssid, in String channelList, in char[] bandList);
+
+    /**
+     * Indicates a DPP progress event.
+     */
+    oneway void onDppProgress(in DppProgressCode code);
+
+    /**
+     * Indicates a DPP success event.
+     */
+    oneway void onDppSuccess(in DppEventType event);
+
+    /**
+     * Indicates DPP configuration received success event (Enrolee mode).
+     */
+    oneway void onDppSuccessConfigReceived(
+            in byte[] ssid, in String password, in byte[] psk, in DppAkm securityAkm);
+
+    /**
+     * Indicates DPP configuration sent success event (Configurator mode).
+     */
+    oneway void onDppSuccessConfigSent();
+
+    /**
+     * Indicates an EAP authentication failure.
+     * @param errorCode Error code for EAP authentication failure.
+     *        Either standard error code (enum EapErrorCode) or
+     *        private error code defined by network provider.
+     */
+    oneway void onEapFailure(in int errorCode);
+
+    /**
+     * Used to indicate that the external radio work can start now.
+     *
+     * @param id Identifier generated for the radio work request.
+     */
+    oneway void onExtRadioWorkStart(in int id);
+
+    /**
+     * Used to indicate that the external radio work request has timed out.
+     *
+     * @param id Identifier generated for the radio work request.
+     */
+    oneway void onExtRadioWorkTimeout(in int id);
+
+    /**
+     * Used to indicate a Hotspot 2.0 imminent deauth notice.
+     *
+     * @param bssid BSSID of the access point.
+     * @param reasonCode Code to indicate the deauth reason.
+     *        Refer to section 3.2.1.2 of the Hotspot 2.0 spec.
+     * @param reAuthDelayInSec Delay before reauthenticating.
+     * @param url URL of the server.
+     */
+    oneway void onHs20DeauthImminentNotice(
+            in byte[] bssid, in int reasonCode, in int reAuthDelayInSec, in String url);
+
+    /**
+     * Used to indicate the result of Hotspot 2.0 Icon query.
+     *
+     * @param bssid BSSID of the access point.
+     * @param fileName Name of the file that was requested.
+     * @param data Icon data fetched from the access point.
+     *        Must be empty if the query failed.
+     */
+    oneway void onHs20IconQueryDone(in byte[] bssid, in String fileName, in byte[] data);
+
+    /**
+     * Used to indicate a Hotspot 2.0 subscription remediation event.
+     *
+     * @param bssid BSSID of the access point.
+     * @param osuMethod OSU method.
+     * @param url URL of the server.
+     */
+    oneway void onHs20SubscriptionRemediation(
+            in byte[] bssid, in OsuMethod osuMethod, in String url);
+
+    /**
+     * Used to indicate a Hotspot 2.0 terms and conditions acceptance is requested from the user
+     * before allowing the device to get internet access.
+     *
+     * @param bssid BSSID of the access point.
+     * @param url URL of the T&C server.
+     */
+    oneway void onHs20TermsAndConditionsAcceptanceRequestedNotification(
+            in byte[] bssid, in String url);
+
+    /**
+     * Used to indicate that a new network has been added.
+     *
+     * @param id Network ID allocated to the corresponding network.
+     */
+    oneway void onNetworkAdded(in int id);
+
+    /**
+     * Used to indicate that the supplicant failed to find a network in scan result
+     * which matches with the network capabilities requested by upper layer
+     * for connection.
+     *
+     * @param ssid network name supplicant tried to connect.
+     */
+    oneway void onNetworkNotFound(in byte[] ssid);
+
+    /**
+     * Used to indicate that a network has been removed.
+     *
+     * @param id Network ID allocated to the corresponding network.
+     */
+    oneway void onNetworkRemoved(in int id);
+
+    /**
+     * Indicates pairwise master key (PMK) cache added event.
+     *
+     * @param expirationTimeInSec expiration time in seconds
+     * @param serializedEntry is serialized PMK cache entry, the content is
+     *              opaque for the framework and depends on the native implementation.
+     */
+    oneway void onPmkCacheAdded(in long expirationTimeInSec, in byte[] serializedEntry);
+
+    /**
+     * Used to indicate a state change event on this particular iface. If this
+     * event is triggered by a particular network, the |SupplicantNetworkId|,
+     * |ssid|, |bssid| parameters must indicate the parameters of the network/AP
+     * which caused this state transition.
+     *
+     * @param newState New State of the interface. This must be one of the |State|
+     *        values above.
+     * @param bssid BSSID of the corresponding AP which caused this state
+     *        change event. This must be zero'ed if this event is not
+     *        specific to a particular network.
+     * @param id ID of the corresponding network which caused this
+     *        state change event. This must be invalid (UINT32_MAX) if this
+     *        event is not specific to a particular network.
+     * @param ssid SSID of the corresponding network which caused this state
+     *        change event. This must be empty if this event is not specific
+     *        to a particular network.
+     * @param filsHlpSent If FILS HLP IEs were included in this association.
+     */
+    oneway void onStateChanged(in StaIfaceCallbackState newState, in byte[] bssid, in int id,
+            in byte[] ssid, in boolean filsHlpSent);
+
+    /**
+     * Used to indicate the failure of a WPS connection attempt.
+     *
+     * @param bssid BSSID of the AP to which we initiated WPS
+     *        connection.
+     * @param configError Configuration error code.
+     * @param errorInd Error indication code.
+     */
+    oneway void onWpsEventFail(
+            in byte[] bssid, in WpsConfigError configError, in WpsErrorIndication errorInd);
+
+    /**
+     * Used to indicate the overlap of a WPS PBC connection attempt.
+     */
+    oneway void onWpsEventPbcOverlap();
+
+    /**
+     * Used to indicate the success of a WPS connection attempt.
+     */
+    oneway void onWpsEventSuccess();
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
new file mode 100644
index 0000000..1a2087d
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -0,0 +1,1108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.AuthAlgMask;
+import android.hardware.wifi.supplicant.EapMethod;
+import android.hardware.wifi.supplicant.EapPhase2Method;
+import android.hardware.wifi.supplicant.GroupCipherMask;
+import android.hardware.wifi.supplicant.GroupMgmtCipherMask;
+import android.hardware.wifi.supplicant.ISupplicantStaNetworkCallback;
+import android.hardware.wifi.supplicant.IfaceType;
+import android.hardware.wifi.supplicant.KeyMgmtMask;
+import android.hardware.wifi.supplicant.NetworkResponseEapSimGsmAuthParams;
+import android.hardware.wifi.supplicant.NetworkResponseEapSimUmtsAuthParams;
+import android.hardware.wifi.supplicant.OcspType;
+import android.hardware.wifi.supplicant.PairwiseCipherMask;
+import android.hardware.wifi.supplicant.ProtoMask;
+import android.hardware.wifi.supplicant.SaeH2eMode;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+@VintfStability
+interface ISupplicantStaNetwork {
+    /**
+     * Max length of SSID param.
+     */
+    const int SSID_MAX_LEN_IN_BYTES = 32;
+
+    /**
+     * Min length of PSK passphrase param.
+     */
+    const int PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8;
+
+    /**
+     * Max length of PSK passphrase param.
+     */
+    const int PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63;
+
+    /**
+     * Max number of WEP keys param.
+     */
+    const int WEP_KEYS_MAX_NUM = 4;
+
+    /**
+     * Length of each WEP40 keys param.
+     */
+    const int WEP40_KEY_LEN_IN_BYTES = 5;
+
+    /**
+     * Length of each WEP104 keys param.
+     */
+    const int WEP104_KEY_LEN_IN_BYTES = 13;
+
+    /**
+     * Disable the network for connection purposes.
+     *
+     * This must trigger a disconnection from the network, if currently
+     * connected to this one.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void disable();
+
+    /**
+     * Enable the network for connection purposes.
+     *
+     * This must trigger a connection to the network if:
+     * a) |noConnect| is false, and
+     * b) This is the only network configured, and
+     * c) Is visible in the current scan results.
+     *
+     * @param noConnect Only enable the network, don't trigger a connect.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void enable(in boolean noConnect);
+
+    /**
+     * Set whether to enable SAE PK (Public Key) only mode to enable public AP validation.
+     * When enabled, only SAE PK network is allowed; otherwise PK is optional.
+     * If this API is not called before connecting to an SAE
+     * network, SAE PK mode depends on SAE PK config in wpa_supplicant configuration.
+     * If SAE PK config of wpa_supplicant configuration is not set,
+     * the default mode is optional (support for both PK and standard mode).
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+     */
+    void enableSaePkOnlyMode(in boolean enable);
+
+    /**
+     * Set EAP OpenSSL Suite-B-192 ciphers for WPA3-Enterprise
+     *        Supported option:
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void enableSuiteBEapOpenSslCiphers();
+
+    /**
+     * Enable TLS Suite-B in EAP Phase1
+     *
+     * @param enable Set to true to enable TLS Suite-B in EAP phase1
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void enableTlsSuiteBEapPhase1Param(in boolean enable);
+
+    /**
+     * Get the auth alg mask set for the network.
+     *
+     * @return Combination of |AuthAlgMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    AuthAlgMask getAuthAlg();
+
+    /**
+     * Get the BSSID set for this network.
+     *
+     * @return bssid Value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getBssid();
+
+    /**
+     * Get EAP Alt subject match set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getEapAltSubjectMatch();
+
+    /**
+     * Get EAP Anonymous Identity set for this network.
+     *
+     * @return identity value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getEapAnonymousIdentity();
+
+    /**
+     * Get EAP CA certificate file path set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getEapCACert();
+
+    /**
+     * Get EAP CA certificate directory path set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getEapCAPath();
+
+    /**
+     * Get EAP Client certificate file path set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getEapClientCert();
+
+    /**
+     * Get EAP Domain suffix match set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getEapDomainSuffixMatch();
+
+    /**
+     * Get whether EAP Open SSL Engine is enabled for this network.
+     *
+     * @return true if set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean getEapEngine();
+
+    /**
+     * Get EAP Open SSL Engine ID set for this network.
+     *
+     * @return value set.
+     * throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getEapEngineId();
+
+    /**
+     * Get EAP Identity set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getEapIdentity();
+
+    /**
+     * Get EAP Method set for this network.
+     *
+     * @return value set.
+     *        Must be one of |EapMethod| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    EapMethod getEapMethod();
+
+    /**
+     * Get EAP Password set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getEapPassword();
+
+    /**
+     * Get EAP Phase2 Method set for this network.
+     *
+     * @return value set.
+     *        Must be one of |EapPhase2Method| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    EapPhase2Method getEapPhase2Method();
+
+    /**
+     * Get EAP private key Id set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|)
+     */
+    String getEapPrivateKeyId();
+
+    /**
+     * Get EAP subject match set for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getEapSubjectMatch();
+
+    /**
+     * Get whether enhanced directional multi-gigabit (802.11ay EDMG) is enabled for this network.
+     *
+     * @return true if set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean getEdmg();
+
+    /**
+     * Get the group cipher mask set for the network.
+     *
+     * @return Combination of |GroupCipherMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    GroupCipherMask getGroupCipher();
+
+    /**
+     * Get the group management cipher mask set for the network.
+     *
+     * @return Combination of |GroupMgmtCipherMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    GroupMgmtCipherMask getGroupMgmtCipher();
+
+    /**
+     * Retrieves the ID allocated to this network by the supplicant.
+     *
+     * This is not the |SSID| of the network, but an internal identifier for
+     * this network used by the supplicant.
+     *
+     * @return Network ID.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    int getId();
+
+    /**
+     * Get ID string set for this network.
+     * Network identifier string for external scripts.
+     *
+     * @return ID string set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getIdStr();
+
+    /**
+     * Retrieves the name of the interface this network belongs to.
+     *
+     * @return Name of the network interface, e.g., wlan0
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getInterfaceName();
+
+    /**
+     * Get the key mgmt mask set for the network.
+     *
+     * @return Combination of |KeyMgmtMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    KeyMgmtMask getKeyMgmt();
+
+    /**
+     * Get OCSP (Online Certificate Status Protocol) type for this network.
+     *
+     * @return ocsp type.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    OcspType getOcsp();
+
+    /**
+     * Get the pairwise cipher mask set for the network.
+     *
+     * @return Combination of |PairwiseCipherMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    PairwiseCipherMask getPairwiseCipher();
+
+    /**
+     * Get the proto mask set for the network.
+     *
+     * @return Combination of |ProtoMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    ProtoMask getProto();
+
+    /**
+     * Get raw psk for WPA_PSK network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getPsk();
+
+    /**
+     * Get passphrase for WPA_PSK network.
+     * Must return a failure if network has no passphrase set (use |getPsk| if
+     * network was configured with raw psk instead).
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getPskPassphrase();
+
+    /**
+     * Get whether RequirePmf is enabled for this network.
+     *
+     * @return true if set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean getRequirePmf();
+
+    /**
+     * Get SAE password for WPA3-Personal
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getSaePassword();
+
+    /**
+     * Get SAE password ID for WPA3-Personal
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    String getSaePasswordId();
+
+    /**
+     * Get whether Probe Requests are being sent for this network (hidden).
+     *
+     * @return true if set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    boolean getScanSsid();
+
+    /**
+     *
+     * Getters for the various network params.
+     *
+     */
+
+    /**
+     * Get SSID for this network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getSsid();
+
+    /**
+     * Retrieves the type of the interface this network belongs to.
+     *
+     * @return Type of the network interface, e.g., STA.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    IfaceType getType();
+
+    /**
+     * Get WAPI certificate suite name set for this network.
+     *
+     * @return The name of a suite.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    String getWapiCertSuite();
+
+    /**
+     * Get WEP key for WEP network.
+     *
+     * @param keyIdx Index of wep key to be fetched.
+     *        Max of |WEP_KEYS_MAX_NUM|.
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getWepKey(in int keyIdx);
+
+    /**
+     * Get default Tx key index for WEP network.
+     *
+     * @return value set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    int getWepTxKeyIdx();
+
+    /**
+     * Retrieves a WPS-NFC configuration token for this network.
+     *
+     * @return Bytes representing WPS-NFC configuration token.
+     *         This is a dump of all the WPS atrributes of the AP configuration
+     *         as specified in the Wi-Fi Protected Setup Specification.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    byte[] getWpsNfcConfigurationToken();
+
+    /**
+     * Register for callbacks from this network.
+     *
+     * These callbacks are invoked for events that are specific to this network.
+     * Registration of multiple callback objects is supported. These objects must
+     * be automatically deleted when the corresponding client process is dead or
+     * if this network is removed.
+     *
+     * @param callback An instance of the |ISupplicantStaNetworkCallback| AIDL
+     *        interface object.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void registerCallback(in ISupplicantStaNetworkCallback callback);
+
+    /**
+     * Initiate connection to this network.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void select();
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapIdentityRequest| request.
+     *
+     * @param identity Identity string containing the IMSI.
+     * @param encryptedIdentity Identity string containing the encrypted IMSI.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void sendNetworkEapIdentityResponse(in byte[] identity, in byte[] encryptedIdentity);
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapSimGsmAuthRequest| request.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void sendNetworkEapSimGsmAuthFailure();
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapSimGsmAuthRequest| request.
+     *
+     * @param params Params to be used for EAP GSM authentication.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void sendNetworkEapSimGsmAuthResponse(in NetworkResponseEapSimGsmAuthParams[] params);
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapSimUmtsAuthRequest| request.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void sendNetworkEapSimUmtsAuthFailure();
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapSimUmtsAuthRequest| request.
+     *
+     * @param params Params to be used for EAP UMTS authentication.
+     * @throws ServiceSpecificException with one of the following values:
+
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void sendNetworkEapSimUmtsAuthResponse(in NetworkResponseEapSimUmtsAuthParams params);
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapSimUmtsAuthRequest| request.
+     *
+     * @param auts Params to be used for EAP UMTS authentication.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void sendNetworkEapSimUmtsAutsResponse(in byte[] auts);
+
+    /**
+     * Set auth alg mask for the network.
+     *
+     * @param authAlgMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setAuthAlg(in AuthAlgMask authAlgMask);
+
+    /**
+     * Set the network to only connect to an AP with provided BSSID.
+     *
+     * @param bssid value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setBssid(in byte[] bssid);
+
+    /**
+     * Set EAP Alt subject match for this network.
+     *
+     * @param match value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapAltSubjectMatch(in String match);
+
+    /**
+     * Set EAP Anonymous Identity for this network.
+     *
+     * @param identity value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapAnonymousIdentity(in byte[] identity);
+
+    /**
+     * Set EAP CA certificate file path for this network.
+     *
+     * @param path value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapCACert(in String path);
+
+    /**
+     * Set EAP CA certificate directory path for this network.
+     *
+     * @param path value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapCAPath(in String path);
+
+    /**
+     * Set EAP Client certificate file path for this network.
+     *
+     * @param path value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapClientCert(in String path);
+
+    /**
+     * Set EAP Domain suffix match for this network.
+     *
+     * @param match value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapDomainSuffixMatch(in String match);
+
+    /**
+     * Set EAP encrypted IMSI Identity for this network.
+     *
+     * @param identity Identity string built from the encrypted IMSI.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapEncryptedImsiIdentity(in byte[] identity);
+
+    /**
+     * Enable EAP Open SSL Engine for this network.
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapEngine(in boolean enable);
+
+    /**
+     * Set EAP Open SSL Engine ID for this network.
+     *
+     * @param id value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapEngineID(in String id);
+
+    /**
+     * Enable Extensible Authentication (EAP) - Re-authentication Protocol (ERP) for this network.
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapErp(in boolean enable);
+
+    /**
+     * Set EAP Identity for this network.
+     *
+     * @param identity value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapIdentity(in byte[] identity);
+
+    /**
+     * Set EAP Method for this network.
+     *
+     * @param method value to be set.
+     *        Must be one of |EapMethod| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapMethod(in EapMethod method);
+
+    /**
+     * Set EAP Password for this network.
+     *
+     * @param password value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapPassword(in byte[] password);
+
+    /**
+     * Set EAP Phase2 Method for this network.
+     *
+     * EAP method needs to be set for this to work.
+     *
+     * @param method value to set.
+     *        Must be one of |EapPhase2Method| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapPhase2Method(in EapPhase2Method method);
+
+    /**
+     * Set EAP private key Id for this network.
+     * This is used if private key operations for EAP-TLS are performed
+     * using a smartcard.
+     *
+     * @param id value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapPrivateKeyId(in String id);
+
+    /**
+     * Set EAP subject match for this network.
+     *
+     * @param match value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEapSubjectMatch(in String match);
+
+    /**
+     * Set whether to enable enhanced directional multi-gigabit (802.11ay EDMG).
+     * Only allowed if hw mode is |HOSTAPD_MODE_IEEE80211AD|
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setEdmg(in boolean enable);
+
+    /**
+     * Set group cipher mask for the network.
+     *
+     * @param groupCipherMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setGroupCipher(in GroupCipherMask groupCipherMask);
+
+    /**
+     * Set group management cipher mask for the network.
+     *
+     * @param groupMgmtCipherMask value to set.
+     *        Combination of |GroupMgmtCipherMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setGroupMgmtCipher(in GroupMgmtCipherMask groupMgmtCipherMask);
+
+    /**
+     * Set ID string for this network.
+     * Network identifier string for external scripts.
+     *
+     * @param idStr ID string value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setIdStr(in String idStr);
+
+    /**
+     * Set key management mask for the network.
+     *
+     * @param keyMgmtMask value to set.
+     *        Combination of |KeyMgmtMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setKeyMgmt(in KeyMgmtMask keyMgmtMask);
+
+    /**
+     * Set OCSP (Online Certificate Status Protocol) type for this network.
+     *
+     * @param ocspType value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setOcsp(in OcspType ocspType);
+
+    /**
+     * Set pairwise cipher mask for the network.
+     *
+     * @param pairwiseCipherMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setPairwiseCipher(in PairwiseCipherMask pairwiseCipherMask);
+
+    /**
+     * Add a pairwise master key (PMK) into supplicant PMK cache.
+     *
+     * @param serializedEntry is serialized PMK cache entry, the content is
+     *              opaque for the framework and depends on the native implementation.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setPmkCache(in byte[] serializedEntry);
+
+    /**
+     * This field can be used to enable proactive key caching which is also
+     * known as opportunistic PMKSA caching for WPA2. This is disabled (0)
+     * by default unless default value is changed with the global okc=1
+     * parameter.
+     *
+     * Proactive key caching is used to make supplicant assume that the APs
+     * are using the same PMK and generate PMKSA cache entries without
+     * doing RSN pre-authentication. This requires support from the AP side
+     * and is normally used with wireless switches that co-locate the
+     * authenticator.
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setProactiveKeyCaching(in boolean enable);
+
+    /**
+     * Set proto mask for the network.
+     *
+     * @param protoMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setProto(in ProtoMask protoMask);
+
+    /**
+     * Set raw psk for WPA_PSK network.
+     *
+     * @param psk value to set as specified in IEEE 802.11i-2004 standard.
+     *        This is the calculated using 'wpa_passphrase <ssid> [passphrase]'
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setPsk(in byte[] psk);
+
+    /**
+     * Set passphrase for WPA_PSK network.
+     *
+     * @param psk value to set.
+     *        Length of value must be between
+     *        |PSK_PASSPHRASE_MIN_LEN_IN_BYTES| and
+     *        |PSK_PASSPHRASE_MAX_LEN_IN_BYTES|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setPskPassphrase(in String psk);
+
+    /**
+     * Set whether RequirePmf is enabled for this network.
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setRequirePmf(in boolean enable);
+
+    /**
+     * Set SAE H2E (Hash-to-Element) mode.
+     *
+     * @param mode SAE H2E supporting mode.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setSaeH2eMode(in SaeH2eMode mode);
+
+    /**
+     * Set SAE password for WPA3-Personal
+     *
+     * @param saePassword string with the above option
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setSaePassword(in String saePassword);
+
+    /**
+     * Set SAE password ID for WPA3-Personal
+     *
+     * @param sae_password_id string with the above option
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setSaePasswordId(in String saePasswordId);
+
+    /**
+     * Set whether to send probe requests for this network (hidden).
+     *
+     * @param enable true to set, false otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setScanSsid(in boolean enable);
+
+    /**
+     *
+     * Setters for the various network params.
+     * These correspond to elements of |wpa_sssid| struct used internally by
+     * the supplicant to represent each network.
+     *
+     */
+
+    /**
+     * Set SSID for this network.
+     *
+     * @param ssid value to set.
+     *        Max length of |SSID_MAX_LEN_IN_BYTES|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setSsid(in byte[] ssid);
+
+    /**
+     * Set PPS MO ID for this network.
+     * (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+     *
+     * @param id ID value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setUpdateIdentifier(in int id);
+
+    /**
+     * Set WAPI certificate suite name for this network.
+     *
+     * @param suite value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void setWapiCertSuite(in String suite);
+
+    /**
+     * Set WEP key for WEP network.
+     *
+     * @param keyIdx Index of wep key to set.
+     *        Max of |WEP_KEYS_MAX_NUM|.
+     * @param wepKey value to set.
+     *        Length of each key must be either
+     *        |WEP40_KEY_LEN_IN_BYTES| or
+     *        |WEP104_KEY_LEN_IN_BYTES|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setWepKey(in int keyIdx, in byte[] wepKey);
+
+    /**
+     * Set default Tx key index for WEP network.
+     *
+     * @param keyIdx Value to set.
+     *        Max of |WEP_KEYS_MAX_NUM|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setWepTxKeyIdx(in int keyIdx);
+
+    /**
+     * Set the roaming consortium selection.
+     *
+     * @param selectedRcoi Indicates the roaming consortium selection. This is a
+     *            3 or 5-octet long byte array that indicates the selected RCOI
+     *            used for a Passpoint connection.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setRoamingConsortiumSelection(in byte[] selectedRcoi);
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
new file mode 100644
index 0000000..4024c35
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.NetworkRequestEapSimGsmAuthParams;
+import android.hardware.wifi.supplicant.NetworkRequestEapSimUmtsAuthParams;
+import android.hardware.wifi.supplicant.TransitionDisableIndication;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each network (ISupplicantStaNetwork).
+ *
+ * Clients need to host an instance of this AIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantStaNetwork.registerCallback| method.
+ */
+@VintfStability
+interface ISupplicantStaNetworkCallback {
+    /**
+     * Used to request EAP Identity for this particular network.
+     *
+     * The response for the request must be sent using the corresponding
+     * |ISupplicantNetwork.sendNetworkEapIdentityResponse| call.
+     */
+    oneway void onNetworkEapIdentityRequest();
+
+    /**
+     * Used to request EAP GSM SIM authentication for this particular network.
+     *
+     * The response for the request must be sent using the corresponding
+     * |ISupplicantNetwork.sendNetworkEapSimGsmAuthResponse| call.
+     *
+     * @param params Params associated with the request.
+     */
+    oneway void onNetworkEapSimGsmAuthRequest(in NetworkRequestEapSimGsmAuthParams params);
+
+    /**
+     * Used to request EAP UMTS SIM authentication for this particular network.
+     *
+     * The response for the request must be sent using the corresponding
+     * |ISupplicantNetwork.sendNetworkEapSimUmtsAuthResponse| call.
+     *
+     * @param params Params associated with the request.
+     */
+    oneway void onNetworkEapSimUmtsAuthRequest(in NetworkRequestEapSimUmtsAuthParams params);
+
+    /**
+     * Used to notify WPA3 transition disable.
+     */
+    oneway void onTransitionDisable(in TransitionDisableIndication ind);
+
+    /**
+     * Used to notify EAP certificate event.
+     *
+     * On receiving a server certifidate from TLS handshake, send this certificate
+     * to the framework for Trust On First Use.
+     */
+    oneway void onServerCertificateAvailable(
+            in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/IfaceInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/IfaceInfo.aidl
new file mode 100644
index 0000000..7792142
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/IfaceInfo.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.IfaceType;
+
+/**
+ * Structure describing the type and name of an iface
+ * controlled by the supplicant.
+ */
+@VintfStability
+parcelable IfaceInfo {
+    /**
+     * Type of the network interface.
+     */
+    IfaceType type;
+    /**
+     * Name of the network interface, e.g., wlan0
+     */
+    String name;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/IfaceType.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/IfaceType.aidl
new file mode 100644
index 0000000..e39dcd1
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/IfaceType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * List of Iface types supported.
+ */
+@VintfStability
+@Backing(type="int")
+enum IfaceType {
+    STA,
+    P2P,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/KeyMgmtMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
new file mode 100644
index 0000000..f0c3345
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possible mask of values for KeyMgmt param.
+ * See /external/wpa_supplicant_8/src/common/defs.h for
+ * the historical values (starting at WPA_KEY_MGMT_IEEE8021X).
+ */
+@VintfStability
+@Backing(type="int")
+enum KeyMgmtMask {
+    WPA_EAP = 1 << 0,
+    WPA_PSK = 1 << 1,
+    NONE = 1 << 2,
+    IEEE8021X = 1 << 3,
+    FT_EAP = 1 << 5,
+    FT_PSK = 1 << 6,
+    OSEN = 1 << 15,
+    /**
+     * WPA using EAP authentication with stronger SHA256-based algorithms
+     */
+    WPA_EAP_SHA256 = 1 << 7,
+    /**
+     * WPA pre-shared key with stronger SHA256-based algorithms
+     */
+    WPA_PSK_SHA256 = 1 << 8,
+    /**
+     * WPA3-Personal SAE Key management
+     */
+    SAE = 1 << 10,
+    /**
+     * WPA3-Enterprise Suite-B Key management
+     */
+    SUITE_B_192 = 1 << 17,
+    /**
+     * Enhacned Open (OWE) Key management
+     */
+    OWE = 1 << 22,
+    /**
+     * Easy Connect (DPP) Key management
+     */
+    DPP = 1 << 23,
+    /*
+     * WAPI Psk
+     */
+    WAPI_PSK = 1 << 12,
+    /**
+     * WAPI Cert
+     */
+    WAPI_CERT = 1 << 13,
+    /**
+     * FILS shared key authentication with sha-256
+     */
+    FILS_SHA256 = 1 << 18,
+    /**
+     * FILS shared key authentication with sha-384
+     */
+    FILS_SHA384 = 1 << 19,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/LegacyMode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/LegacyMode.aidl
new file mode 100644
index 0000000..f933f6c
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/LegacyMode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Detailed network mode for legacy network
+ */
+@VintfStability
+@Backing(type="int")
+enum LegacyMode {
+    UNKNOWN = 0,
+    /**
+     * For 802.11a
+     */
+    A_MODE = 1,
+    /**
+     * For 802.11b
+     */
+    B_MODE = 2,
+    /**
+     * For 802.11g
+     */
+    G_MODE = 3,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MacAddress.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MacAddress.aidl
new file mode 100644
index 0000000..40ad22a
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MacAddress.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Byte array representing a Mac Address. Use when we need
+ * to pass an array of Mac Addresses to a method, as 2D
+ * arrays are not supported in AIDL.
+ *
+ * TODO (b/210705533): Replace this type with a 2D byte array.
+ */
+@VintfStability
+parcelable MacAddress {
+    byte[/* 6 */] data;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboAssocDisallowedReasonCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboAssocDisallowedReasonCode.aidl
new file mode 100644
index 0000000..41868aa
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboAssocDisallowedReasonCode.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ *  MBO spec v1.2, 4.2.4 Table 14: MBO Association disallowed reason code attribute
+ *  values.
+ */
+@VintfStability
+@Backing(type="byte")
+enum MboAssocDisallowedReasonCode {
+    RESERVED = 0,
+    UNSPECIFIED = 1,
+    MAX_NUM_STA_ASSOCIATED = 2,
+    AIR_INTERFACE_OVERLOADED = 3,
+    AUTH_SERVER_OVERLOADED = 4,
+    INSUFFICIENT_RSSI = 5,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboCellularDataConnectionPrefValue.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboCellularDataConnectionPrefValue.aidl
new file mode 100644
index 0000000..98f707e
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboCellularDataConnectionPrefValue.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ *  MBO spec v1.2, 4.2.5 Table 16: MBO Cellular Data connection preference
+ *  attribute values. AP use this to indicate STA, its preference for the
+ *  STA to move from BSS to cellular network.
+ */
+@VintfStability
+@Backing(type="int")
+enum MboCellularDataConnectionPrefValue {
+    EXCLUDED = 0,
+    NOT_PREFERRED = 1,
+    /*
+     * 2-254 Reserved.
+     */
+    PREFERRED = 255,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboTransitionReasonCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboTransitionReasonCode.aidl
new file mode 100644
index 0000000..66ad9ee
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MboTransitionReasonCode.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ *  MBO spec v1.2, 4.2.6 Table 18: MBO transition reason code attribute
+ *  values.
+ */
+@VintfStability
+@Backing(type="byte")
+enum MboTransitionReasonCode {
+    UNSPECIFIED = 0,
+    EXCESSIVE_FRAME_LOSS = 1,
+    EXCESSIVE_TRAFFIC_DELAY = 2,
+    INSUFFICIENT_BANDWIDTH = 3,
+    LOAD_BALANCING = 4,
+    LOW_RSSI = 5,
+    RX_EXCESSIVE_RETRIES = 6,
+    HIGH_INTERFERENCE = 7,
+    GRAY_ZONE = 8,
+    TRANSITION_TO_PREMIUM_AP = 9,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MiracastMode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MiracastMode.aidl
new file mode 100644
index 0000000..4eaaf1d
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MiracastMode.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Enum describing the modes of Miracast supported
+ * via driver commands.
+ */
+@VintfStability
+@Backing(type="byte")
+enum MiracastMode {
+    DISABLED = 0,
+    /**
+     * Operating as source.
+     */
+    SOURCE = 1,
+    /**
+     * Operating as sink.
+     */
+    SINK = 2,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkRequestEapSimGsmAuthParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkRequestEapSimGsmAuthParams.aidl
new file mode 100644
index 0000000..c706c81
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkRequestEapSimGsmAuthParams.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.GsmRand;
+
+/**
+ * Params of |onNetworkEapSimGsmAuthRequest| request. (Refer RFC 4186)
+ */
+@VintfStability
+parcelable NetworkRequestEapSimGsmAuthParams {
+    GsmRand[] rands;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkRequestEapSimUmtsAuthParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkRequestEapSimUmtsAuthParams.aidl
new file mode 100644
index 0000000..2f5e7fa
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkRequestEapSimUmtsAuthParams.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Params of |onNetworkEapSimUmtsAuthRequest| request. (Refer RFC 4187)
+ */
+@VintfStability
+parcelable NetworkRequestEapSimUmtsAuthParams {
+    byte[/* 16 */] rand;
+    byte[/* 16 */] autn;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimGsmAuthParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimGsmAuthParams.aidl
new file mode 100644
index 0000000..38929a2
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimGsmAuthParams.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Params of |sendNetworkEapSimGsmAuthResponse| request. (Refer RFC 4186)
+ */
+@VintfStability
+parcelable NetworkResponseEapSimGsmAuthParams {
+    byte[/* 8 */] kc;
+    byte[/* 4 */] sres;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.aidl
new file mode 100644
index 0000000..5311016
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Params of |sendNetworkEapSimUmtsAuthResponse| request. (Refer RFC 4187)
+ */
+@VintfStability
+parcelable NetworkResponseEapSimUmtsAuthParams {
+    byte[] res;
+    byte[/* 16 */] ik;
+    byte[/* 16 */] ck;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OceRssiBasedAssocRejectAttr.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OceRssiBasedAssocRejectAttr.aidl
new file mode 100644
index 0000000..09ec09c
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OceRssiBasedAssocRejectAttr.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * OceRssiBasedAssocRejectAttr is extracted from (Re-)Association response
+ * frame from an OCE AP to indicate that the AP has rejected the
+ * (Re-)Association request on the basis of insufficient RSSI.
+ * Refer OCE spec v1.0 section 4.2.2 Table 7.
+ */
+@VintfStability
+parcelable OceRssiBasedAssocRejectAttr {
+    /*
+     * Delta RSSI - The difference in dB between the minimum RSSI at which
+     * the AP would accept a (Re-)Association request from the STA before
+     * Retry Delay expires and the AP's measurement of the RSSI at which the
+     * (Re-)Association request was received.
+     */
+    int deltaRssi;
+    /*
+     * Retry Delay - The time period in seconds for which the AP will not
+     * accept any subsequent (Re-)Association requests from the STA, unless
+     * the received RSSI has improved by Delta RSSI.
+     */
+    int retryDelayS;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OcspType.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OcspType.aidl
new file mode 100644
index 0000000..876fb11
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OcspType.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * OcspType: The type of OCSP request.
+ */
+@VintfStability
+@Backing(type="int")
+enum OcspType {
+    NONE,
+    REQUEST_CERT_STATUS,
+    REQUIRE_CERT_STATUS,
+    REQUIRE_ALL_CERTS_STATUS,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OsuMethod.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OsuMethod.aidl
new file mode 100644
index 0000000..a060365
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/OsuMethod.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * OSU Method. Refer to section 4.8.1.3 of the Hotspot 2.0 spec.
+ */
+@VintfStability
+@Backing(type="byte")
+enum OsuMethod {
+    OMA_DM = 0,
+    SOAP_XML_SPP = 1,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl
new file mode 100644
index 0000000..bda3c34
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * P2P group capability.
+ * See /external/wpa_supplicant_8/src/common/ieee802_11_defs.h
+ * for all possible values (starting at P2P_GROUP_CAPAB_GROUP_OWNER).
+ */
+@VintfStability
+@Backing(type="int")
+enum P2pGroupCapabilityMask {
+    GROUP_OWNER = 1 << 0,
+    PERSISTENT_GROUP = 1 << 1,
+    GROUP_LIMIT = 1 << 2,
+    INTRA_BSS_DIST = 1 << 3,
+    CROSS_CONN = 1 << 4,
+    PERSISTENT_RECONN = 1 << 5,
+    GROUP_FORMATION = 1 << 6,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvDiscStatusCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvDiscStatusCode.aidl
new file mode 100644
index 0000000..9effd0a
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvDiscStatusCode.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Status codes for P2P discovery.
+ */
+@VintfStability
+@Backing(type="byte")
+enum P2pProvDiscStatusCode {
+    SUCCESS = 0,
+    TIMEOUT = 1,
+    REJECTED = 2,
+    TIMEOUT_JOIN = 3,
+    INFO_UNAVAILABLE = 4,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pStatusCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pStatusCode.aidl
new file mode 100644
index 0000000..4020f9e
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pStatusCode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Status codes for P2P operations.
+ */
+@VintfStability
+@Backing(type="int")
+enum P2pStatusCode {
+    SUCCESS = 0,
+    FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
+    FAIL_INCOMPATIBLE_PARAMS = 2,
+    FAIL_LIMIT_REACHED = 3,
+    FAIL_INVALID_PARAMS = 4,
+    FAIL_UNABLE_TO_ACCOMMODATE = 5,
+    FAIL_PREV_PROTOCOL_ERROR = 6,
+    FAIL_NO_COMMON_CHANNELS = 7,
+    FAIL_UNKNOWN_GROUP = 8,
+    FAIL_BOTH_GO_INTENT_15 = 9,
+    FAIL_INCOMPATIBLE_PROV_METHOD = 10,
+    FAIL_REJECTED_BY_USER = 11,
+    SUCCESS_DEFERRED = 12,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl
new file mode 100644
index 0000000..7179fea
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possible mask of values for PairwiseCipher param.
+ * See /external/wpa_supplicant_8/src/common/defs.h for
+ * the historical values (starting at WPA_CIPHER_NONE).
+ */
+@VintfStability
+@Backing(type="int")
+enum PairwiseCipherMask {
+    NONE = 1 << 0,
+    TKIP = 1 << 3,
+    CCMP = 1 << 4,
+    /**
+     * GCMP-128 Pairwise Cipher
+     */
+    GCMP_128 = 1 << 6,
+    /**
+     * SMS4 Pairwise Cipher
+     */
+    SMS4 = 1 << 7,
+    /**
+     * GCMP-256 Pairwise Cipher
+     */
+    GCMP_256 = 1 << 8,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ProtoMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ProtoMask.aidl
new file mode 100644
index 0000000..dc3d80b
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ProtoMask.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Possible mask of values for Proto param.
+ * See /external/wpa_supplicant_8/src/common/defs.h for
+ * the historical values (starting at WPA_PROTO_WPA).
+ */
+@VintfStability
+@Backing(type="int")
+enum ProtoMask {
+    WPA = 1 << 0,
+    RSN = 1 << 1,
+    WAPI = 1 << 2,
+    OSEN = 1 << 3,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/RxFilterType.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/RxFilterType.aidl
new file mode 100644
index 0000000..5dfb73e
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/RxFilterType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Enum describing the types of RX filter supported
+ * via driver commands.
+ */
+@VintfStability
+@Backing(type="byte")
+enum RxFilterType {
+    V4_MULTICAST = 0,
+    V6_MULTICAST = 1,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SaeH2eMode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SaeH2eMode.aidl
new file mode 100644
index 0000000..48a879b
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SaeH2eMode.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * SAE Hash-to-Element mode.
+ */
+@VintfStability
+@Backing(type="byte")
+enum SaeH2eMode {
+    /**
+     * Hash-to-Element is disabled, only Hunting & Pecking is allowed.
+     */
+    DISABLED,
+    /**
+     * Both Hash-to-Element and Hunting & Pecking are allowed.
+     */
+    H2E_OPTIONAL,
+    /**
+     * Only Hash-to-Element is allowed.
+     */
+    H2E_MANDATORY,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceCallbackState.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceCallbackState.aidl
new file mode 100644
index 0000000..19f6f88
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceCallbackState.aidl
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Various states of the interface reported by |onStateChanged|.
+ */
+@VintfStability
+@Backing(type="int")
+enum StaIfaceCallbackState {
+    /**
+     * This state indicates that client is not associated, but is likely to
+     * start looking for an access point. This state is entered when a
+     * connection is lost.
+     */
+    DISCONNECTED = 0,
+    /**
+     * This state is entered if the network interface is disabled, e.g.,
+     * due to rfkill. the supplicant refuses any new operations that would
+     * use the radio until the interface has been enabled.
+     */
+    IFACE_DISABLED = 1,
+    /**
+     * This state is entered if there are no enabled networks in the
+     * configuration. the supplicant is not trying to associate with a new
+     * network and external interaction (e.g., ctrl_iface call to add or
+     * enable a network) is needed to start association.
+     */
+    INACTIVE = 2,
+    /**
+     * This state is entered when the supplicant starts scanning for a
+     * network.
+     */
+    SCANNING = 3,
+    /**
+     * This state is entered when the supplicant has found a suitable BSS
+     * to authenticate with and the driver is configured to try to
+     * authenticate with this BSS. This state is used only with drivers
+     * that use the supplicant as the SME.
+     */
+    AUTHENTICATING = 4,
+    /**
+     * This state is entered when the supplicant has found a suitable BSS
+     * to associate with and the driver is configured to try to associate
+     * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
+     * state is entered when the driver is configured to try to associate
+     * with a network using the configured SSID and security policy.
+     */
+    ASSOCIATING = 5,
+    /**
+     * This state is entered when the driver reports that association has
+     * been successfully completed with an AP. If IEEE 802.1X is used
+     * (with or without WPA/WPA2), the supplicant remains in this state
+     * until the IEEE 802.1X/EAPOL authentication has been completed.
+     */
+    ASSOCIATED = 6,
+    /**
+     * This state is entered when WPA/WPA2 4-Way Handshake is started. In
+     * case of WPA-PSK, this happens when receiving the first EAPOL-Key
+     * frame after association. In case of WPA-EAP, this state is entered
+     * when the IEEE 802.1X/EAPOL authentication has been completed.
+     */
+    FOURWAY_HANDSHAKE = 7,
+    /**
+     * This state is entered when 4-Way Key Handshake has been completed
+     * (i.e., when the supplicant sends out message 4/4) and when Group
+     * Key rekeying is started by the AP (i.e., when supplicant receives
+     * message 1/2).
+     */
+    GROUP_HANDSHAKE = 8,
+    /**
+     * This state is entered when the full authentication process is
+     * completed. In case of WPA2, this happens when the 4-Way Handshake is
+     * successfully completed. With WPA, this state is entered after the
+     * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
+     * completed after dynamic keys are received (or if not used, after
+     * the EAP authentication has been completed). With static WEP keys and
+     * plaintext connections, this state is entered when an association
+     * has been completed.
+     *
+     * This state indicates that the supplicant has completed its
+     * processing for the association phase and that data connection is
+     * fully configured.
+     */
+    COMPLETED = 9,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceReasonCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceReasonCode.aidl
new file mode 100644
index 0000000..6b05c07
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceReasonCode.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45).
+ */
+@VintfStability
+@Backing(type="int")
+enum StaIfaceReasonCode {
+    UNSPECIFIED = 1,
+    PREV_AUTH_NOT_VALID = 2,
+    DEAUTH_LEAVING = 3,
+    DISASSOC_DUE_TO_INACTIVITY = 4,
+    DISASSOC_AP_BUSY = 5,
+    CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+    CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+    DISASSOC_STA_HAS_LEFT = 8,
+    STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+    PWR_CAPABILITY_NOT_VALID = 10,
+    SUPPORTED_CHANNEL_NOT_VALID = 11,
+    BSS_TRANSITION_DISASSOC = 12,
+    INVALID_IE = 13,
+    MICHAEL_MIC_FAILURE = 14,
+    FOURWAY_HANDSHAKE_TIMEOUT = 15,
+    GROUP_KEY_UPDATE_TIMEOUT = 16,
+    IE_IN_4WAY_DIFFERS = 17,
+    GROUP_CIPHER_NOT_VALID = 18,
+    PAIRWISE_CIPHER_NOT_VALID = 19,
+    AKMP_NOT_VALID = 20,
+    UNSUPPORTED_RSN_IE_VERSION = 21,
+    INVALID_RSN_IE_CAPAB = 22,
+    IEEE_802_1X_AUTH_FAILED = 23,
+    CIPHER_SUITE_REJECTED = 24,
+    TDLS_TEARDOWN_UNREACHABLE = 25,
+    TDLS_TEARDOWN_UNSPECIFIED = 26,
+    SSP_REQUESTED_DISASSOC = 27,
+    NO_SSP_ROAMING_AGREEMENT = 28,
+    BAD_CIPHER_OR_AKM = 29,
+    NOT_AUTHORIZED_THIS_LOCATION = 30,
+    SERVICE_CHANGE_PRECLUDES_TS = 31,
+    UNSPECIFIED_QOS_REASON = 32,
+    NOT_ENOUGH_BANDWIDTH = 33,
+    DISASSOC_LOW_ACK = 34,
+    EXCEEDED_TXOP = 35,
+    STA_LEAVING = 36,
+    END_TS_BA_DLS = 37,
+    UNKNOWN_TS_BA = 38,
+    TIMEOUT = 39,
+    PEERKEY_MISMATCH = 45,
+    AUTHORIZED_ACCESS_LIMIT_REACHED = 46,
+    EXTERNAL_SERVICE_REQUIREMENTS = 47,
+    INVALID_FT_ACTION_FRAME_COUNT = 48,
+    INVALID_PMKID = 49,
+    INVALID_MDE = 50,
+    INVALID_FTE = 51,
+    MESH_PEERING_CANCELLED = 52,
+    MESH_MAX_PEERS = 53,
+    MESH_CONFIG_POLICY_VIOLATION = 54,
+    MESH_CLOSE_RCVD = 55,
+    MESH_MAX_RETRIES = 56,
+    MESH_CONFIRM_TIMEOUT = 57,
+    MESH_INVALID_GTK = 58,
+    MESH_INCONSISTENT_PARAMS = 59,
+    MESH_INVALID_SECURITY_CAP = 60,
+    MESH_PATH_ERROR_NO_PROXY_INFO = 61,
+    MESH_PATH_ERROR_NO_FORWARDING_INFO = 62,
+    MESH_PATH_ERROR_DEST_UNREACHABLE = 63,
+    MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64,
+    MESH_CHANNEL_SWITCH_REGULATORY_REQ = 65,
+    MESH_CHANNEL_SWITCH_UNSPECIFIED = 66,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceStatusCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceStatusCode.aidl
new file mode 100644
index 0000000..75e7f68
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/StaIfaceStatusCode.aidl
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Status codes (IEEE Std 802.11-2016, 9.4.1.9, Table 9-46).
+ */
+@VintfStability
+@Backing(type="int")
+enum StaIfaceStatusCode {
+    SUCCESS = 0,
+    UNSPECIFIED_FAILURE = 1,
+    TDLS_WAKEUP_ALTERNATE = 2,
+    TDLS_WAKEUP_REJECT = 3,
+    SECURITY_DISABLED = 5,
+    UNACCEPTABLE_LIFETIME = 6,
+    NOT_IN_SAME_BSS = 7,
+    CAPS_UNSUPPORTED = 10,
+    REASSOC_NO_ASSOC = 11,
+    ASSOC_DENIED_UNSPEC = 12,
+    NOT_SUPPORTED_AUTH_ALG = 13,
+    UNKNOWN_AUTH_TRANSACTION = 14,
+    CHALLENGE_FAIL = 15,
+    AUTH_TIMEOUT = 16,
+    AP_UNABLE_TO_HANDLE_NEW_STA = 17,
+    ASSOC_DENIED_RATES = 18,
+    ASSOC_DENIED_NOSHORT = 19,
+    SPEC_MGMT_REQUIRED = 22,
+    PWR_CAPABILITY_NOT_VALID = 23,
+    SUPPORTED_CHANNEL_NOT_VALID = 24,
+    ASSOC_DENIED_NO_SHORT_SLOT_TIME = 25,
+    ASSOC_DENIED_NO_HT = 27,
+    R0KH_UNREACHABLE = 28,
+    ASSOC_DENIED_NO_PCO = 29,
+    ASSOC_REJECTED_TEMPORARILY = 30,
+    ROBUST_MGMT_FRAME_POLICY_VIOLATION = 31,
+    UNSPECIFIED_QOS_FAILURE = 32,
+    DENIED_INSUFFICIENT_BANDWIDTH = 33,
+    DENIED_POOR_CHANNEL_CONDITIONS = 34,
+    DENIED_QOS_NOT_SUPPORTED = 35,
+    REQUEST_DECLINED = 37,
+    INVALID_PARAMETERS = 38,
+    REJECTED_WITH_SUGGESTED_CHANGES = 39,
+    INVALID_IE = 40,
+    GROUP_CIPHER_NOT_VALID = 41,
+    PAIRWISE_CIPHER_NOT_VALID = 42,
+    AKMP_NOT_VALID = 43,
+    UNSUPPORTED_RSN_IE_VERSION = 44,
+    INVALID_RSN_IE_CAPAB = 45,
+    CIPHER_REJECTED_PER_POLICY = 46,
+    TS_NOT_CREATED = 47,
+    DIRECT_LINK_NOT_ALLOWED = 48,
+    DEST_STA_NOT_PRESENT = 49,
+    DEST_STA_NOT_QOS_STA = 50,
+    ASSOC_DENIED_LISTEN_INT_TOO_LARGE = 51,
+    INVALID_FT_ACTION_FRAME_COUNT = 52,
+    INVALID_PMKID = 53,
+    INVALID_MDIE = 54,
+    INVALID_FTIE = 55,
+    REQUESTED_TCLAS_NOT_SUPPORTED = 56,
+    INSUFFICIENT_TCLAS_PROCESSING_RESOURCES = 57,
+    TRY_ANOTHER_BSS = 58,
+    GAS_ADV_PROTO_NOT_SUPPORTED = 59,
+    NO_OUTSTANDING_GAS_REQ = 60,
+    GAS_RESP_NOT_RECEIVED = 61,
+    STA_TIMED_OUT_WAITING_FOR_GAS_RESP = 62,
+    GAS_RESP_LARGER_THAN_LIMIT = 63,
+    REQ_REFUSED_HOME = 64,
+    ADV_SRV_UNREACHABLE = 65,
+    REQ_REFUSED_SSPN = 67,
+    REQ_REFUSED_UNAUTH_ACCESS = 68,
+    INVALID_RSNIE = 72,
+    U_APSD_COEX_NOT_SUPPORTED = 73,
+    U_APSD_COEX_MODE_NOT_SUPPORTED = 74,
+    BAD_INTERVAL_WITH_U_APSD_COEX = 75,
+    ANTI_CLOGGING_TOKEN_REQ = 76,
+    FINITE_CYCLIC_GROUP_NOT_SUPPORTED = 77,
+    CANNOT_FIND_ALT_TBTT = 78,
+    TRANSMISSION_FAILURE = 79,
+    REQ_TCLAS_NOT_SUPPORTED = 80,
+    TCLAS_RESOURCES_EXCHAUSTED = 81,
+    REJECTED_WITH_SUGGESTED_BSS_TRANSITION = 82,
+    REJECT_WITH_SCHEDULE = 83,
+    REJECT_NO_WAKEUP_SPECIFIED = 84,
+    SUCCESS_POWER_SAVE_MODE = 85,
+    PENDING_ADMITTING_FST_SESSION = 86,
+    PERFORMING_FST_NOW = 87,
+    PENDING_GAP_IN_BA_WINDOW = 88,
+    REJECT_U_PID_SETTING = 89,
+    REFUSED_EXTERNAL_REASON = 92,
+    REFUSED_AP_OUT_OF_MEMORY = 93,
+    REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED = 94,
+    QUERY_RESP_OUTSTANDING = 95,
+    REJECT_DSE_BAND = 96,
+    TCLAS_PROCESSING_TERMINATED = 97,
+    TS_SCHEDULE_CONFLICT = 98,
+    DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
+    MCCAOP_RESERVATION_CONFLICT = 100,
+    MAF_LIMIT_EXCEEDED = 101,
+    MCCA_TRACK_LIMIT_EXCEEDED = 102,
+    DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
+    ASSOC_DENIED_NO_VHT = 104,
+    ENABLEMENT_DENIED = 105,
+    RESTRICTION_FROM_AUTHORIZED_GDB = 106,
+    AUTHORIZATION_DEENABLED = 107,
+    FILS_AUTHENTICATION_FAILURE = 112,
+    UNKNOWN_AUTHENTICATION_SERVER = 113,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl
new file mode 100644
index 0000000..c7b7ffd
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Enum values indicating the status of any supplicant operation.
+ */
+@VintfStability
+@Backing(type="int")
+enum SupplicantStatusCode {
+    /**
+     * No errors.
+     */
+    SUCCESS,
+    /**
+     * Unknown failure occurred.
+     */
+    FAILURE_UNKNOWN,
+    /**
+     * One of the incoming args is invalid.
+     */
+    FAILURE_ARGS_INVALID,
+    /**
+     * |ISupplicantIface| AIDL interface object is no longer valid.
+     */
+    FAILURE_IFACE_INVALID,
+    /**
+     * Iface with the provided name does not exist.
+     */
+    FAILURE_IFACE_UNKNOWN,
+    /**
+     * Iface with the provided name already exists.
+     */
+    FAILURE_IFACE_EXISTS,
+    /**
+     * Iface is disabled and cannot be used.
+     */
+    FAILURE_IFACE_DISABLED,
+    /**
+     * Iface is not currently disconnected, so cannot reconnect.
+     */
+    FAILURE_IFACE_NOT_DISCONNECTED,
+    /**
+     * |ISupplicantNetwork| AIDL interface object is no longer valid.
+     */
+    FAILURE_NETWORK_INVALID,
+    /**
+     * Network with the provided id does not exist.
+     */
+    FAILURE_NETWORK_UNKNOWN,
+    FAILURE_UNSUPPORTED,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl
new file mode 100644
index 0000000..baf20a8
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * WPA3™ Specification Addendum for WPA3 R3 - Table 3.
+ * Transition Disable Indication filled in the third
+ * 4-way handshake message.
+ * See /external/wpa_supplicant_8/src/common/wpa_common.h for
+ * all possible values (starting at TRANSITION_DISABLE_WPA3_PERSONAL).
+ */
+@VintfStability
+@Backing(type="int")
+enum TransitionDisableIndication {
+    USE_WPA3_PERSONAL = 1 << 0,
+    USE_SAE_PK = 1 << 1,
+    USE_WPA3_ENTERPRISE = 1 << 2,
+    USE_ENHANCED_OPEN = 1 << 3,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WifiTechnology.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WifiTechnology.aidl
new file mode 100644
index 0000000..d364c75
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WifiTechnology.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Wifi Technologies
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiTechnology {
+    UNKNOWN = 0,
+    /**
+     * For 802.11a/b/g
+     */
+    LEGACY = 1,
+    /**
+     * For 802.11n
+     */
+    HT = 2,
+    /**
+     * For 802.11ac
+     */
+    VHT = 3,
+    /**
+     * For 802.11ax
+     */
+    HE = 4,
+    /**
+     * For 802.11be
+     */
+    EHT = 5,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
new file mode 100644
index 0000000..08006cf
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * WPA Driver capability.
+ */
+@VintfStability
+@Backing(type="int")
+enum WpaDriverCapabilitiesMask {
+    /**
+     * Multi Band Operation.
+     */
+    MBO = 1 << 0,
+    /**
+     * Optimized Connectivity Experience.
+     */
+    OCE = 1 << 1,
+    /**
+     * WPA3 SAE Public-Key.
+     */
+    SAE_PK = 1 << 2,
+    /**
+     * Wi-Fi Display R2
+     */
+    WFD_R2 = 1 << 3,
+    /**
+     * Trust On First Use
+     */
+    TRUST_ON_FIRST_USE = 1 << 4,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsConfigError.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsConfigError.aidl
new file mode 100644
index 0000000..926946c
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsConfigError.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * WPS Configuration Error.
+ */
+@VintfStability
+@Backing(type="int")
+enum WpsConfigError {
+    NO_ERROR = 0,
+    OOB_IFACE_READ_ERROR = 1,
+    DECRYPTION_CRC_FAILURE = 2,
+    CHAN_24_NOT_SUPPORTED = 3,
+    CHAN_50_NOT_SUPPORTED = 4,
+    SIGNAL_TOO_WEAK = 5,
+    NETWORK_AUTH_FAILURE = 6,
+    NETWORK_ASSOC_FAILURE = 7,
+    NO_DHCP_RESPONSE = 8,
+    FAILED_DHCP_CONFIG = 9,
+    IP_ADDR_CONFLICT = 10,
+    NO_CONN_TO_REGISTRAR = 11,
+    MULTIPLE_PBC_DETECTED = 12,
+    ROGUE_SUSPECTED = 13,
+    DEVICE_BUSY = 14,
+    SETUP_LOCKED = 15,
+    MSG_TIMEOUT = 16,
+    REG_SESS_TIMEOUT = 17,
+    DEV_PASSWORD_AUTH_FAILURE = 18,
+    CHAN_60G_NOT_SUPPORTED = 19,
+    PUBLIC_KEY_HASH_MISMATCH = 20,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsConfigMethods.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsConfigMethods.aidl
new file mode 100644
index 0000000..ec08a45
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsConfigMethods.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * WPS config methods.
+ * Refer to section 3 of IBSS with Wi-Fi Protected Setup
+ * Technical Specification Version 1.0.0.
+ */
+@VintfStability
+@Backing(type="int")
+enum WpsConfigMethods {
+    USBA = 0x0001,
+    ETHERNET = 0x0002,
+    LABEL = 0x0004,
+    DISPLAY = 0x0008,
+    EXT_NFC_TOKEN = 0x0010,
+    INT_NFC_TOKEN = 0x0020,
+    NFC_INTERFACE = 0x0040,
+    PUSHBUTTON = 0x0080,
+    KEYPAD = 0x0100,
+    VIRT_PUSHBUTTON = 0x0280,
+    PHY_PUSHBUTTON = 0x0480,
+    P2PS = 0x1000,
+    VIRT_DISPLAY = 0x2008,
+    PHY_DISPLAY = 0x4008,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl
new file mode 100644
index 0000000..ca5a533
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * WPS Device Password ID
+ */
+@VintfStability
+@Backing(type="int")
+enum WpsDevPasswordId {
+    DEFAULT = 0x0000,
+    USER_SPECIFIED = 0x0001,
+    MACHINE_SPECIFIED = 0x0002,
+    REKEY = 0x0003,
+    PUSHBUTTON = 0x0004,
+    REGISTRAR_SPECIFIED = 0x0005,
+    NFC_CONNECTION_HANDOVER = 0x0007,
+    P2PS_DEFAULT = 0x0008,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsErrorIndication.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsErrorIndication.aidl
new file mode 100644
index 0000000..4866acc
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsErrorIndication.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Vendor specific Error Indication for WPS event messages.
+ */
+@VintfStability
+@Backing(type="int")
+enum WpsErrorIndication {
+    NO_ERROR = 0,
+    SECURITY_TKIP_ONLY_PROHIBITED = 1,
+    SECURITY_WEP_PROHIBITED = 2,
+    AUTH_FAILURE = 3,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
new file mode 100644
index 0000000..5b59392
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+@VintfStability
+@Backing(type="int")
+enum WpsProvisionMethod {
+    /**
+     * Push button method.
+     */
+    PBC,
+    /**
+     * Display pin method configuration - pin is generated and displayed on
+     * device.
+     */
+    DISPLAY,
+    /**
+     * Keypad pin method configuration - pin is entered on device.
+     */
+    KEYPAD,
+}
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..65f9652
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -0,0 +1,90 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalWifiSupplicantStaIfaceTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["supplicant_sta_iface_aidl_test.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.wifi.supplicant-V1-ndk",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiSupplicantStaNetworkTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["supplicant_sta_network_aidl_test.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.wifi.supplicant-V1-ndk",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiSupplicantP2pIfaceTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["supplicant_p2p_iface_aidl_test.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.wifi.supplicant-V1-ndk",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
new file mode 100644
index 0000000..10aab4d
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicant.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicantP2pIfaceCallback.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/properties.h>
+
+#include "supplicant_test_utils.h"
+
+using aidl::android::hardware::wifi::supplicant::BnSupplicantP2pIfaceCallback;
+using aidl::android::hardware::wifi::supplicant::DebugLevel;
+using aidl::android::hardware::wifi::supplicant::FreqRange;
+using aidl::android::hardware::wifi::supplicant::IfaceType;
+using aidl::android::hardware::wifi::supplicant::ISupplicant;
+using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
+using aidl::android::hardware::wifi::supplicant::MiracastMode;
+using aidl::android::hardware::wifi::supplicant::P2pGroupCapabilityMask;
+using aidl::android::hardware::wifi::supplicant::P2pProvDiscStatusCode;
+using aidl::android::hardware::wifi::supplicant::P2pStatusCode;
+using aidl::android::hardware::wifi::supplicant::WpsConfigMethods;
+using aidl::android::hardware::wifi::supplicant::WpsDevPasswordId;
+using aidl::android::hardware::wifi::supplicant::WpsProvisionMethod;
+using android::ProcessState;
+
+namespace {
+const std::string kTestSsidStr = "TestSsid1234";
+const std::vector<uint8_t> kTestSsid =
+    std::vector<uint8_t>(kTestSsidStr.begin(), kTestSsidStr.end());
+const std::vector<uint8_t> kTestMacAddr = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
+const std::vector<uint8_t> kTestPeerMacAddr = {0x56, 0x67, 0x55,
+                                               0xf4, 0x56, 0x92};
+const std::vector<uint8_t> kTestZeroMacAddr = std::vector<uint8_t>(6, 0);
+const std::string kTestPassphrase = "P2pWorld1234";
+const std::string kTestConnectPin = "34556665";
+const std::string kTestGroupIfName = "TestGroup";
+const uint32_t kTestFindTimeout = 5;
+const uint32_t kTestConnectGoIntent = 6;
+const uint32_t kTestNetworkId = 7;
+const uint32_t kTestGroupFreq = 0;
+const bool kTestGroupPersistent = false;
+const bool kTestGroupIsJoin = false;
+
+}  // namespace
+
+class SupplicantP2pIfaceCallback : public BnSupplicantP2pIfaceCallback {
+   public:
+    SupplicantP2pIfaceCallback() = default;
+
+    ::ndk::ScopedAStatus onDeviceFound(
+        const std::vector<uint8_t>& /* srcAddress */,
+        const std::vector<uint8_t>& /* p2pDeviceAddress */,
+        const std::vector<uint8_t>& /* primaryDeviceType */,
+        const std::string& /* deviceName */,
+        WpsConfigMethods /* configMethods */, int8_t /* deviceCapabilities */,
+        P2pGroupCapabilityMask /* groupCapabilities */,
+        const std::vector<uint8_t>& /* wfdDeviceInfo */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDeviceLost(
+        const std::vector<uint8_t>& /* p2pDeviceAddress */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onFindStopped() override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGoNegotiationCompleted(
+        P2pStatusCode /* status */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGoNegotiationRequest(
+        const std::vector<uint8_t>& /* srcAddress */,
+        WpsDevPasswordId /* passwordId */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGroupFormationFailure(
+        const std::string& /* failureReason */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGroupFormationSuccess() override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGroupRemoved(const std::string& /* groupIfname */,
+                                        bool /* isGroupOwner */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGroupStarted(
+        const std::string& /* groupIfname */, bool /* isGroupOwner */,
+        const std::vector<uint8_t>& /* ssid */, int32_t /* frequency */,
+        const std::vector<uint8_t>& /* psk */,
+        const std::string& /* passphrase */,
+        const std::vector<uint8_t>& /* goDeviceAddress */,
+        bool /* isPersistent */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onInvitationReceived(
+        const std::vector<uint8_t>& /* srcAddress */,
+        const std::vector<uint8_t>& /* goDeviceAddress */,
+        const std::vector<uint8_t>& /* bssid */,
+        int32_t /* persistentNetworkId */,
+        int32_t /* operatingFrequency */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onInvitationResult(
+        const std::vector<uint8_t>& /* bssid */,
+        P2pStatusCode /* status */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onProvisionDiscoveryCompleted(
+        const std::vector<uint8_t>& /* p2pDeviceAddress */,
+        bool /* isRequest */, P2pProvDiscStatusCode /* status */,
+        WpsConfigMethods /* configMethods */,
+        const std::string& /* generatedPin */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onR2DeviceFound(
+        const std::vector<uint8_t>& /* srcAddress */,
+        const std::vector<uint8_t>& /* p2pDeviceAddress */,
+        const std::vector<uint8_t>& /* primaryDeviceType */,
+        const std::string& /* deviceName */,
+        WpsConfigMethods /* configMethods */, int8_t /* deviceCapabilities */,
+        P2pGroupCapabilityMask /* groupCapabilities */,
+        const std::vector<uint8_t>& /* wfdDeviceInfo */,
+        const std::vector<uint8_t>& /* wfdR2DeviceInfo */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onServiceDiscoveryResponse(
+        const std::vector<uint8_t>& /* srcAddress */,
+        char16_t /* updateIndicator */,
+        const std::vector<uint8_t>& /* tlvs */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onStaAuthorized(
+        const std::vector<uint8_t>& /* srcAddress */,
+        const std::vector<uint8_t>& /* p2pDeviceAddress */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onStaDeauthorized(
+        const std::vector<uint8_t>& /* srcAddress */,
+        const std::vector<uint8_t>& /* p2pDeviceAddress */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGroupFrequencyChanged(const std::string& /* groupIfname */,
+                                                 int32_t /* frequency */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+class SupplicantP2pIfaceAidlTest : public testing::TestWithParam<std::string> {
+   public:
+    void SetUp() override {
+        initializeService();
+        supplicant_ = ISupplicant::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(supplicant_, nullptr);
+        ASSERT_TRUE(supplicant_
+                        ->setDebugParams(DebugLevel::EXCESSIVE,
+                                         true,  // show timestamps
+                                         true)
+                        .isOk());
+
+        bool p2pEnabled =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        if (!p2pEnabled) {
+            GTEST_SKIP() << "Wi-Fi Direct is not supported, skip this test.";
+        }
+
+        EXPECT_TRUE(supplicant_->addP2pInterface(getP2pIfaceName(), &p2p_iface_)
+                        .isOk());
+        ASSERT_NE(p2p_iface_, nullptr);
+    }
+
+    void TearDown() override {
+        stopSupplicant();
+        startWifiFramework();
+    }
+
+   protected:
+    std::shared_ptr<ISupplicant> supplicant_;
+    std::shared_ptr<ISupplicantP2pIface> p2p_iface_;
+};
+
+/*
+ * RegisterCallback
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, RegisterCallback) {
+    std::shared_ptr<SupplicantP2pIfaceCallback> callback =
+        ndk::SharedRefBase::make<SupplicantP2pIfaceCallback>();
+    ASSERT_NE(callback, nullptr);
+    EXPECT_TRUE(p2p_iface_->registerCallback(callback).isOk());
+}
+
+/*
+ * GetName
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, GetName) {
+    std::string name;
+    EXPECT_TRUE(p2p_iface_->getName(&name).isOk());
+    EXPECT_NE(name.size(), 0);
+}
+
+/*
+ * GetType
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, GetType) {
+    IfaceType type;
+    EXPECT_TRUE(p2p_iface_->getType(&type).isOk());
+    EXPECT_EQ(type, IfaceType::P2P);
+}
+
+/*
+ * GetDeviceAddress
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, GetDeviceAddress) {
+    std::vector<uint8_t> macAddr;
+    EXPECT_TRUE(p2p_iface_->getDeviceAddress(&macAddr).isOk());
+    EXPECT_EQ(macAddr.size(), 6);
+}
+
+/*
+ * GetSsid
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, GetSsid) {
+    // This will fail with fake values.
+    std::vector<uint8_t> ssid;
+    EXPECT_FALSE(p2p_iface_->getSsid(kTestMacAddr, &ssid).isOk());
+}
+
+/*
+ * GetGroupCapability
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, GetGroupCapability) {
+    // This will fail with fake values.
+    P2pGroupCapabilityMask cap;
+    EXPECT_FALSE(p2p_iface_->getGroupCapability(kTestMacAddr, &cap).isOk());
+}
+
+/*
+ * Set/Get Edmg
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetGetEdmg) {
+    bool emdg = false;
+    EXPECT_TRUE(p2p_iface_->setEdmg(true).isOk());
+    EXPECT_TRUE(p2p_iface_->getEdmg(&emdg).isOk());
+    EXPECT_EQ(emdg, true);
+
+    EXPECT_TRUE(p2p_iface_->setEdmg(false).isOk());
+    EXPECT_TRUE(p2p_iface_->getEdmg(&emdg).isOk());
+    EXPECT_EQ(emdg, false);
+}
+
+/*
+ * SetWpsDeviceName
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWpsDeviceName) {
+    const std::string deviceName = "TestWpsDeviceName";
+    EXPECT_TRUE(p2p_iface_->setWpsDeviceName(deviceName).isOk());
+}
+
+/*
+ * SetWpsDeviceType
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWpsDeviceType) {
+    const std::vector<uint8_t> deviceType = std::vector<uint8_t>(8, 0x01);
+    EXPECT_TRUE(p2p_iface_->setWpsDeviceType(deviceType).isOk());
+}
+
+/*
+ * SetWpsManufacturer
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWpsManufacturer) {
+    const std::string deviceManufacturer = "TestManufacturer";
+    EXPECT_TRUE(p2p_iface_->setWpsManufacturer(deviceManufacturer).isOk());
+}
+
+/*
+ * SetWpsModelName
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWpsModelName) {
+    const std::string modelName = "TestModelName";
+    EXPECT_TRUE(p2p_iface_->setWpsModelName(modelName).isOk());
+}
+
+/*
+ * SetWpsModelNumber
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWpsModelNumber) {
+    const std::string modelNumber = "TestModelNumber";
+    EXPECT_TRUE(p2p_iface_->setWpsModelName(modelNumber).isOk());
+}
+
+/*
+ * SetWpsSerialNumber
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWpsSerialNumber) {
+    const std::string serialNumber = "TestSerialNumber";
+    EXPECT_TRUE(p2p_iface_->setWpsSerialNumber(serialNumber).isOk());
+}
+
+/*
+ * SetWpsConfigMethods
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWpsConfigMethods) {
+    const WpsConfigMethods config = WpsConfigMethods::DISPLAY;
+    EXPECT_TRUE(p2p_iface_->setWpsConfigMethods(config).isOk());
+}
+
+/*
+ * SetSsidPostfix
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetSsidPostfix) {
+    const std::vector<uint8_t> ssidPostfix = {'t', 'e', 's', 't'};
+    EXPECT_TRUE(p2p_iface_->setSsidPostfix(ssidPostfix).isOk());
+}
+
+/*
+ * SetWfdDeviceInfo
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWfdDeviceInfo) {
+    const std::vector<uint8_t> wfdDeviceInfo = std::vector<uint8_t>(6, 0x01);
+    EXPECT_TRUE(p2p_iface_->setWfdDeviceInfo(wfdDeviceInfo).isOk());
+}
+
+/*
+ * SetWfdR2DeviceInfo
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetWfdR2DeviceInfo) {
+    const std::vector<uint8_t> wfdR2DeviceInfo = std::vector<uint8_t>(4, 0x01);
+    EXPECT_TRUE(p2p_iface_->setWfdR2DeviceInfo(wfdR2DeviceInfo).isOk());
+}
+
+/*
+ * SetGroupIdle
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetGroupIdle) {
+    // This will fail with fake values.
+    const uint32_t groupIdleTimeout = 8;
+    EXPECT_FALSE(
+        p2p_iface_->setGroupIdle(kTestGroupIfName, groupIdleTimeout).isOk());
+}
+
+/*
+ * SetPowerSave
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetPowerSave) {
+    // This will fail with fake values.
+    EXPECT_FALSE(p2p_iface_->setPowerSave(kTestGroupIfName, true).isOk());
+    EXPECT_FALSE(p2p_iface_->setPowerSave(kTestGroupIfName, false).isOk());
+}
+
+/*
+ * SetMiracastMode
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetMiracastMode) {
+    EXPECT_TRUE(p2p_iface_->setMiracastMode(MiracastMode::DISABLED).isOk());
+    EXPECT_TRUE(p2p_iface_->setMiracastMode(MiracastMode::SOURCE).isOk());
+    EXPECT_TRUE(p2p_iface_->setMiracastMode(MiracastMode::SINK).isOk());
+}
+
+/*
+ * SetDisallowedFrequencies
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetDisallowedFrequencies) {
+    FreqRange range1;
+    range1.min = 2412;
+    range1.max = 2432;
+    const std::vector<FreqRange> ranges = {range1};
+    EXPECT_TRUE(p2p_iface_->setDisallowedFrequencies(ranges).isOk());
+}
+
+/*
+ * SetListenChannel
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, SetListenChannel) {
+    const uint32_t testChannel = 1;
+    const uint32_t testOperatingClass = 81;
+    EXPECT_TRUE(
+        p2p_iface_->setListenChannel(testChannel, testOperatingClass).isOk());
+}
+
+/*
+ * SetMacRandomization
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, EnableMacRandomization) {
+    // Enable twice
+    EXPECT_TRUE(p2p_iface_->setMacRandomization(true).isOk());
+    EXPECT_TRUE(p2p_iface_->setMacRandomization(true).isOk());
+
+    // Disable twice
+    EXPECT_TRUE(p2p_iface_->setMacRandomization(false).isOk());
+    EXPECT_TRUE(p2p_iface_->setMacRandomization(false).isOk());
+}
+
+/*
+ * AddGroup
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, AddGroup) {
+    EXPECT_TRUE(p2p_iface_->addGroup(false, kTestNetworkId).isOk());
+}
+
+/*
+ * RemoveGroup
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, RemoveGroup) {
+    // This will fail with fake values.
+    EXPECT_FALSE(p2p_iface_->removeGroup(kTestGroupIfName).isOk());
+}
+
+/*
+ * AddGroupWithConfig - success.
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, AddGroupWithConfig_Success) {
+    EXPECT_TRUE(p2p_iface_
+                    ->addGroupWithConfig(kTestSsid, kTestPassphrase,
+                                         kTestGroupPersistent, kTestGroupFreq,
+                                         kTestZeroMacAddr, kTestGroupIsJoin)
+                    .isOk());
+}
+
+/*
+ * AddGroupWithConfig - failure due to invalid SSID.
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, AddGroupWithConfig_FailureInvalidSsid) {
+    const std::vector<uint8_t> ssid;
+    EXPECT_FALSE(p2p_iface_
+                     ->addGroupWithConfig(ssid, kTestPassphrase,
+                                          kTestGroupPersistent, kTestGroupFreq,
+                                          kTestZeroMacAddr, kTestGroupIsJoin)
+                     .isOk());
+}
+
+/*
+ * AddGroupWithConfig - failure due to invalid passphrase.
+ */
+TEST_P(SupplicantP2pIfaceAidlTest,
+       AddGroupWithConfig_FailureInvalidPassphrase) {
+    const std::string passphrase = "1234";
+    EXPECT_FALSE(p2p_iface_
+                     ->addGroupWithConfig(kTestSsid, passphrase,
+                                          kTestGroupPersistent, kTestGroupFreq,
+                                          kTestZeroMacAddr, kTestGroupIsJoin)
+                     .isOk());
+}
+
+/*
+ * AddGroupWithConfig - failure due to invalid frequency.
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, AddGroupWithConfig_FailureInvalidFrequency) {
+    const int freq = 9999;
+    EXPECT_FALSE(p2p_iface_
+                     ->addGroupWithConfig(kTestSsid, kTestPassphrase,
+                                          kTestGroupPersistent, freq,
+                                          kTestZeroMacAddr, kTestGroupIsJoin)
+                     .isOk());
+}
+
+/*
+ * Find
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, Find) {
+    EXPECT_TRUE(p2p_iface_->find(kTestFindTimeout).isOk());
+}
+
+/*
+ * StopFind
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, StopFind) {
+    EXPECT_TRUE(p2p_iface_->find(kTestFindTimeout).isOk());
+    EXPECT_TRUE(p2p_iface_->stopFind().isOk());
+}
+
+/*
+ * Flush
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, Flush) {
+    EXPECT_TRUE(p2p_iface_->flush().isOk());
+}
+
+/*
+ * Connect
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, Connect) {
+    /*
+     * Auto-join is not enabled before R. After enabling auto-join,
+     * this should always succeed.
+     */
+    std::string pin;
+    EXPECT_TRUE(p2p_iface_
+                    ->connect(kTestMacAddr, WpsProvisionMethod::PBC,
+                              kTestConnectPin, false, false,
+                              kTestConnectGoIntent, &pin)
+                    .isOk());
+}
+
+/*
+ * CancelConnect
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, CancelConnect) {
+    std::string pin;
+    EXPECT_TRUE(p2p_iface_
+                    ->connect(kTestMacAddr, WpsProvisionMethod::PBC,
+                              kTestConnectPin, false, false,
+                              kTestConnectGoIntent, &pin)
+                    .isOk());
+    EXPECT_TRUE(p2p_iface_->cancelConnect().isOk());
+}
+
+/*
+ * ProvisionDiscovery
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, ProvisionDiscovery) {
+    // This will fail with fake values.
+    EXPECT_FALSE(
+        p2p_iface_->provisionDiscovery(kTestMacAddr, WpsProvisionMethod::PBC)
+            .isOk());
+}
+
+/*
+ * Reject
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, Reject) {
+    // This will fail with fake values.
+    ASSERT_FALSE(p2p_iface_->reject(kTestMacAddr).isOk());
+}
+
+/*
+ * Invite
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, Invite) {
+    // This will fail with fake values.
+    EXPECT_FALSE(
+        p2p_iface_->invite(kTestGroupIfName, kTestMacAddr, kTestPeerMacAddr)
+            .isOk());
+}
+
+/*
+ * Reinvoke
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, Reinvoke) {
+    // This will fail with fake values.
+    EXPECT_FALSE(p2p_iface_->reinvoke(kTestNetworkId, kTestMacAddr).isOk());
+}
+
+/*
+ * ConfigureExtListen
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, ConfigureExtListen) {
+    const uint32_t extListenPeriod = 400;
+    const uint32_t extListenInterval = 400;
+    EXPECT_TRUE(
+        p2p_iface_->configureExtListen(extListenPeriod, extListenInterval)
+            .isOk());
+}
+
+/*
+ * FlushServices
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, FlushServices) {
+    EXPECT_TRUE(p2p_iface_->flushServices().isOk());
+}
+
+/*
+ * EnableWfd
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, EnableWfd) {
+    EXPECT_TRUE(p2p_iface_->enableWfd(true).isOk());
+    EXPECT_TRUE(p2p_iface_->enableWfd(false).isOk());
+}
+
+/*
+ * Add/Remove BonjourService
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, AddAndRemoveBonjourService) {
+    const std::string serviceQueryStr = "testquery";
+    const std::string serviceResponseStr = "testresponse";
+    const std::vector<uint8_t> bonjourServiceQuery =
+        std::vector<uint8_t>(serviceQueryStr.begin(), serviceQueryStr.end());
+    const std::vector<uint8_t> bonjourServiceResponse = std::vector<uint8_t>(
+        serviceResponseStr.begin(), serviceResponseStr.end());
+
+    EXPECT_TRUE(
+        p2p_iface_
+            ->addBonjourService(bonjourServiceQuery, bonjourServiceResponse)
+            .isOk());
+    EXPECT_TRUE(p2p_iface_->removeBonjourService(bonjourServiceQuery).isOk());
+
+    // This will fail because the boujour service with
+    // bonjourServiceQuery was already removed.
+    EXPECT_FALSE(p2p_iface_->removeBonjourService(bonjourServiceQuery).isOk());
+}
+
+/*
+ * Add/Remove UpnpService
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, AddAndRemoveUpnpService) {
+    const std::string upnpServiceName = "TestServiceName";
+    EXPECT_TRUE(
+        p2p_iface_->addUpnpService(0 /* version */, upnpServiceName).isOk());
+    EXPECT_TRUE(
+        p2p_iface_->removeUpnpService(0 /* version */, upnpServiceName).isOk());
+
+    // This will fail because Upnp service with
+    // upnpServiceName was already removed.
+    EXPECT_FALSE(
+        p2p_iface_->removeUpnpService(0 /* version */, upnpServiceName).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pIfaceAidlTest);
+INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantP2pIfaceAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             ISupplicant::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
new file mode 100644
index 0000000..6e6955f
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicant.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicantStaIfaceCallback.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/properties.h>
+
+#include "supplicant_test_utils.h"
+
+using aidl::android::hardware::wifi::supplicant::AnqpInfoId;
+using aidl::android::hardware::wifi::supplicant::BnSupplicantStaIfaceCallback;
+using aidl::android::hardware::wifi::supplicant::BtCoexistenceMode;
+using aidl::android::hardware::wifi::supplicant::ConnectionCapabilities;
+using aidl::android::hardware::wifi::supplicant::DebugLevel;
+using aidl::android::hardware::wifi::supplicant::DppAkm;
+using aidl::android::hardware::wifi::supplicant::DppCurve;
+using aidl::android::hardware::wifi::supplicant::DppNetRole;
+using aidl::android::hardware::wifi::supplicant::DppResponderBootstrapInfo;
+using aidl::android::hardware::wifi::supplicant::Hs20AnqpSubtypes;
+using aidl::android::hardware::wifi::supplicant::IfaceType;
+using aidl::android::hardware::wifi::supplicant::ISupplicant;
+using aidl::android::hardware::wifi::supplicant::ISupplicantStaIface;
+using aidl::android::hardware::wifi::supplicant::ISupplicantStaNetwork;
+using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
+using aidl::android::hardware::wifi::supplicant::RxFilterType;
+using aidl::android::hardware::wifi::supplicant::WpaDriverCapabilitiesMask;
+using aidl::android::hardware::wifi::supplicant::WpsConfigMethods;
+using android::ProcessState;
+
+static constexpr int TIMEOUT_PERIOD = 60;
+class IfaceDppCallback;
+
+namespace {
+const std::vector<uint8_t> kTestMacAddr = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
+const std::string kTestUri =
+    "DPP:C:81/1,117/"
+    "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+    "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
+}  // namespace
+
+class SupplicantStaIfaceCallback : public BnSupplicantStaIfaceCallback {
+   public:
+    SupplicantStaIfaceCallback() = default;
+
+    ::ndk::ScopedAStatus onAnqpQueryDone(
+        const std::vector<uint8_t>& /* bssid */,
+        const ::aidl::android::hardware::wifi::supplicant::AnqpData& /* data */,
+        const ::aidl::android::hardware::wifi::supplicant::
+            Hs20AnqpData& /* hs20Data */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onAssociationRejected(
+        const ::aidl::android::hardware::wifi::supplicant::
+            AssociationRejectionData& /* assocRejectData */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onAuthenticationTimeout(
+        const std::vector<uint8_t>& /* bssid */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onBssTmHandlingDone(
+        const ::aidl::android::hardware::wifi::supplicant::
+            BssTmData& /* tmData */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onBssidChanged(
+        ::aidl::android::hardware::wifi::supplicant::
+            BssidChangeReason /* reason */,
+        const std::vector<uint8_t>& /* bssid */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDisconnected(
+        const std::vector<uint8_t>& /* bssid */, bool /* locallyGenerated */,
+        ::aidl::android::hardware::wifi::supplicant::
+            StaIfaceReasonCode /* reasonCode */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppFailure(
+        ::aidl::android::hardware::wifi::supplicant::DppFailureCode /* code */,
+        const std::string& /* ssid */, const std::string& /* channelList */,
+        const std::vector<char16_t>& /* bandList */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppProgress(
+        ::aidl::android::hardware::wifi::supplicant::DppProgressCode /* code */)
+        override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppSuccess(
+        ::aidl::android::hardware::wifi::supplicant::DppEventType /* type */)
+        override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppSuccessConfigReceived(
+        const std::vector<uint8_t>& /* ssid */,
+        const std::string& /* password */,
+        const std::vector<uint8_t>& /* psk */,
+        ::aidl::android::hardware::wifi::supplicant::DppAkm /* securityAkm */)
+        override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppSuccessConfigSent() override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onEapFailure(int32_t /* errorCode */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onExtRadioWorkStart(int32_t /* id */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onExtRadioWorkTimeout(int32_t /* id */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onHs20DeauthImminentNotice(
+        const std::vector<uint8_t>& /* bssid */, int32_t /* reasonCode */,
+        int32_t /* reAuthDelayInSec */, const std::string& /* url */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onHs20IconQueryDone(
+        const std::vector<uint8_t>& /* bssid */,
+        const std::string& /* fileName */,
+        const std::vector<uint8_t>& /* data */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onHs20SubscriptionRemediation(
+        const std::vector<uint8_t>& /* bssid */,
+        ::aidl::android::hardware::wifi::supplicant::OsuMethod /* osuMethod */,
+        const std::string& /* url */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus
+    onHs20TermsAndConditionsAcceptanceRequestedNotification(
+        const std::vector<uint8_t>& /* bssid */,
+        const std::string& /* url */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onNetworkAdded(int32_t /* id */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onNetworkNotFound(
+        const std::vector<uint8_t>& /* ssid */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onNetworkRemoved(int32_t /* id */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onPmkCacheAdded(
+        int64_t /* expirationTimeInSec */,
+        const std::vector<uint8_t>& /* serializedEntry */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onStateChanged(
+        ::aidl::android::hardware::wifi::supplicant::
+            StaIfaceCallbackState /* newState */,
+        const std::vector<uint8_t>& /* bssid */, int32_t /* id */,
+        const std::vector<uint8_t>& /* ssid */,
+        bool /* filsHlpSent */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onWpsEventFail(
+        const std::vector<uint8_t>& /* bssid */,
+        ::aidl::android::hardware::wifi::supplicant::
+            WpsConfigError /* configError */,
+        ::aidl::android::hardware::wifi::supplicant::
+            WpsErrorIndication /* errorInd */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onWpsEventPbcOverlap() override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onWpsEventSuccess() override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+class SupplicantStaIfaceAidlTest : public testing::TestWithParam<std::string> {
+   public:
+    void SetUp() override {
+        initializeService();
+        supplicant_ = ISupplicant::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(supplicant_, nullptr);
+        ASSERT_TRUE(supplicant_
+                        ->setDebugParams(DebugLevel::EXCESSIVE,
+                                         true,  // show timestamps
+                                         true)
+                        .isOk());
+        EXPECT_TRUE(supplicant_->addStaInterface(getStaIfaceName(), &sta_iface_)
+                        .isOk());
+        ASSERT_NE(sta_iface_, nullptr);
+    }
+
+    void TearDown() override {
+        stopSupplicant();
+        startWifiFramework();
+    }
+
+    enum DppCallbackType {
+        ANY_CALLBACK = -2,
+        INVALID = -1,
+        EVENT_SUCCESS = 0,
+        EVENT_PROGRESS,
+        EVENT_FAILURE,
+    };
+
+    DppCallbackType dppCallbackType;
+    uint32_t code;
+
+    // Used as a mechanism to inform the test about data/event callback
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        cv_.notify_one();
+    }
+
+    // Test code calls this function to wait for data/event callback
+    inline std::cv_status wait(DppCallbackType waitForCallbackType) {
+        std::unique_lock<std::mutex> lock(mtx_);
+        EXPECT_NE(INVALID, waitForCallbackType);  // can't ASSERT in a
+                                                  // non-void-returning method
+        auto now = std::chrono::system_clock::now();
+        std::cv_status status =
+            cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        return status;
+    }
+
+   protected:
+    std::shared_ptr<ISupplicant> supplicant_;
+    std::shared_ptr<ISupplicantStaIface> sta_iface_;
+
+   private:
+    // synchronization objects
+    std::mutex mtx_;
+    std::condition_variable cv_;
+};
+
+/*
+ * RegisterCallback
+ */
+TEST_P(SupplicantStaIfaceAidlTest, RegisterCallback) {
+    std::shared_ptr<SupplicantStaIfaceCallback> callback =
+        ndk::SharedRefBase::make<SupplicantStaIfaceCallback>();
+    ASSERT_NE(callback, nullptr);
+    EXPECT_TRUE(sta_iface_->registerCallback(callback).isOk());
+}
+
+/*
+ * GetConnectionCapabilities
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetConnectionCapabilities) {
+    ConnectionCapabilities cap;
+    EXPECT_TRUE(sta_iface_->getConnectionCapabilities(&cap).isOk());
+}
+
+/*
+ * GetWpaDriverCapabilities
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetWpaDriverCapabilities) {
+    WpaDriverCapabilitiesMask cap;
+    EXPECT_TRUE(sta_iface_->getWpaDriverCapabilities(&cap).isOk());
+}
+
+/*
+ * GetKeyMgmtCapabilities
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetKeyMgmtCapabilities) {
+    KeyMgmtMask cap;
+    EXPECT_TRUE(sta_iface_->getKeyMgmtCapabilities(&cap).isOk());
+
+    // Even though capabilities vary, these two are always set.
+    EXPECT_TRUE(!!(static_cast<uint32_t>(cap) &
+                   static_cast<uint32_t>(KeyMgmtMask::NONE)));
+    EXPECT_TRUE(!!(static_cast<uint32_t>(cap) &
+                   static_cast<uint32_t>(KeyMgmtMask::IEEE8021X)));
+}
+
+/*
+ * GetName
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetName) {
+    std::string name;
+    EXPECT_TRUE(sta_iface_->getName(&name).isOk());
+    EXPECT_NE(name.size(), 0);
+}
+
+/*
+ * GetType
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetType) {
+    IfaceType type;
+    EXPECT_TRUE(sta_iface_->getType(&type).isOk());
+    EXPECT_EQ(type, IfaceType::STA);
+}
+
+/*
+ * GetMacAddress
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetMacAddress) {
+    std::vector<uint8_t> macAddr;
+    EXPECT_TRUE(sta_iface_->getMacAddress(&macAddr).isOk());
+    EXPECT_EQ(macAddr.size(), 6);
+}
+
+/*
+ * ListNetworks
+ */
+TEST_P(SupplicantStaIfaceAidlTest, ListNetworks) {
+    std::vector<int32_t> networks;
+    EXPECT_TRUE(sta_iface_->listNetworks(&networks).isOk());
+}
+
+/*
+ * SetBtCoexistenceMode
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetBtCoexistenceMode) {
+    EXPECT_TRUE(
+        sta_iface_->setBtCoexistenceMode(BtCoexistenceMode::ENABLED).isOk());
+    EXPECT_TRUE(
+        sta_iface_->setBtCoexistenceMode(BtCoexistenceMode::DISABLED).isOk());
+    EXPECT_TRUE(
+        sta_iface_->setBtCoexistenceMode(BtCoexistenceMode::SENSE).isOk());
+}
+
+/*
+ * SetBtCoexistenceScanModeEnabled
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetBtCoexistenceScanModeEnabled) {
+    EXPECT_TRUE(sta_iface_->setBtCoexistenceScanModeEnabled(true).isOk());
+    EXPECT_TRUE(sta_iface_->setBtCoexistenceScanModeEnabled(false).isOk());
+}
+
+/*
+ * SetSuspendModeEnabled
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetSuspendModeEnabled) {
+    EXPECT_TRUE(sta_iface_->setSuspendModeEnabled(true).isOk());
+    EXPECT_TRUE(sta_iface_->setSuspendModeEnabled(false).isOk());
+}
+
+/*
+ * SetCountryCode
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetCountryCode) {
+    const std::vector<uint8_t> countryCode = {'M', 'X'};
+    EXPECT_TRUE(sta_iface_->setCountryCode(countryCode).isOk());
+}
+
+/*
+ * SetWpsDeviceName
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetWpsDeviceName) {
+    const std::string deviceName = "TestWpsDeviceName";
+    EXPECT_TRUE(sta_iface_->setWpsDeviceName(deviceName).isOk());
+}
+
+/*
+ * SetWpsDeviceType
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetWpsDeviceType) {
+    const std::vector<uint8_t> deviceType = {8, 0x1};
+    EXPECT_TRUE(sta_iface_->setWpsDeviceType(deviceType).isOk());
+}
+
+/*
+ * SetWpsManufacturer
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetWpsManufacturer) {
+    const std::string wpsManufacturer = "TestManufacturer";
+    EXPECT_TRUE(sta_iface_->setWpsManufacturer(wpsManufacturer).isOk());
+}
+
+/*
+ * SetWpsModelName
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetWpsModelName) {
+    const std::string modelName = "TestModelName";
+    EXPECT_TRUE(sta_iface_->setWpsModelName(modelName).isOk());
+}
+
+/*
+ * SetWpsModelNumber
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetWpsModelNumber) {
+    const std::string modelNumber = "TestModelNumber";
+    EXPECT_TRUE(sta_iface_->setWpsModelNumber(modelNumber).isOk());
+}
+
+/*
+ * SetWpsSerialNumber
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetWpsSerialNumber) {
+    const std::string serialNumber = "TestSerialNumber";
+    EXPECT_TRUE(sta_iface_->setWpsSerialNumber(serialNumber).isOk());
+}
+
+/*
+ * SetWpsConfigMethods
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetWpsConfigMethods) {
+    const WpsConfigMethods configMethods = WpsConfigMethods::KEYPAD;
+    EXPECT_TRUE(sta_iface_->setWpsConfigMethods(configMethods).isOk());
+}
+
+/*
+ * SetExternalSim
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetExternalSim) {
+    EXPECT_TRUE(sta_iface_->setExternalSim(true).isOk());
+    EXPECT_TRUE(sta_iface_->setExternalSim(false).isOk());
+}
+
+/*
+ * SetMboCellularDataStatus
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetMboCellularDataStatus) {
+    WpaDriverCapabilitiesMask cap;
+    EXPECT_TRUE(sta_iface_->getWpaDriverCapabilities(&cap).isOk());
+
+    // Operation should succeed if MBO is supported, or fail if it's not.
+    bool mboSupported =
+        !!(static_cast<uint32_t>(cap) &
+           static_cast<uint32_t>(WpaDriverCapabilitiesMask::MBO));
+    EXPECT_EQ(mboSupported, sta_iface_->setMboCellularDataStatus(true).isOk());
+}
+
+/*
+ * InitiateTdlsDiscover
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InitiateTdlsDiscover) {
+    EXPECT_TRUE(sta_iface_->initiateTdlsDiscover(kTestMacAddr).isOk());
+}
+
+/*
+ * InitiateTdlsSetup
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InitiateTdlsSetup) {
+    EXPECT_TRUE(sta_iface_->initiateTdlsSetup(kTestMacAddr).isOk());
+}
+
+/*
+ * InitiateTdlsTeardown
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InitiateTdlsTeardown) {
+    EXPECT_TRUE(sta_iface_->initiateTdlsTeardown(kTestMacAddr).isOk());
+}
+
+/*
+ * InitiateAnqpQuery
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InitiateAnqpQuery) {
+    const std::vector<AnqpInfoId> anqpIds = {
+        AnqpInfoId::VENUE_NAME, AnqpInfoId::NAI_REALM, AnqpInfoId::DOMAIN_NAME};
+    const std::vector<Hs20AnqpSubtypes> hsTypes = {
+        Hs20AnqpSubtypes::WAN_METRICS,
+        Hs20AnqpSubtypes::OPERATOR_FRIENDLY_NAME};
+
+    // Request should fail since the BSSID mentioned
+    // is not present in the scan results
+    EXPECT_FALSE(
+        sta_iface_->initiateAnqpQuery(kTestMacAddr, anqpIds, hsTypes).isOk());
+}
+
+/*
+ * InitiateHs20IconQuery
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InitiateHs20IconQuery) {
+    // Request should fail since the BSSID mentioned
+    // is not present in the scan results
+    const std::string hs20IconFile = "TestFile";
+    EXPECT_FALSE(
+        sta_iface_->initiateHs20IconQuery(kTestMacAddr, hs20IconFile).isOk());
+}
+
+/*
+ * InitiateVenueUrlAnqpQuery.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InitiateVenueUrlAnqpQuery) {
+    // Request should fail since the BSSID mentioned
+    // is not present in the scan results
+    EXPECT_FALSE(sta_iface_->initiateVenueUrlAnqpQuery(kTestMacAddr).isOk());
+}
+
+/*
+ * Reassociate
+ */
+TEST_P(SupplicantStaIfaceAidlTest, Reassociate) {
+    EXPECT_TRUE(sta_iface_->reassociate().isOk());
+}
+
+/*
+ * Reconnect
+ */
+TEST_P(SupplicantStaIfaceAidlTest, Reconnect) {
+    EXPECT_FALSE(sta_iface_->reconnect().isOk());
+}
+
+/*
+ * Disconnect
+ */
+TEST_P(SupplicantStaIfaceAidlTest, Disconnect) {
+    EXPECT_TRUE(sta_iface_->disconnect().isOk());
+}
+
+/*
+ * SetPowerSave
+ */
+TEST_P(SupplicantStaIfaceAidlTest, SetPowerSave) {
+    EXPECT_TRUE(sta_iface_->setPowerSave(true).isOk());
+    EXPECT_TRUE(sta_iface_->setPowerSave(false).isOk());
+}
+
+/*
+ * StartRxFilter
+ */
+TEST_P(SupplicantStaIfaceAidlTest, StartRxFilter) {
+    EXPECT_TRUE(sta_iface_->startRxFilter().isOk());
+}
+
+/*
+ * StopRxFilter
+ */
+TEST_P(SupplicantStaIfaceAidlTest, StopRxFilter) {
+    EXPECT_TRUE(sta_iface_->stopRxFilter().isOk());
+}
+
+/*
+ * AddRxFilter
+ */
+TEST_P(SupplicantStaIfaceAidlTest, AddRxFilter) {
+    EXPECT_TRUE(sta_iface_->addRxFilter(RxFilterType::V4_MULTICAST).isOk());
+    EXPECT_TRUE(sta_iface_->addRxFilter(RxFilterType::V6_MULTICAST).isOk());
+}
+
+/*
+ * RemoveRxFilter
+ */
+TEST_P(SupplicantStaIfaceAidlTest, RemoveRxFilter) {
+    EXPECT_TRUE(sta_iface_->removeRxFilter(RxFilterType::V4_MULTICAST).isOk());
+    EXPECT_TRUE(sta_iface_->removeRxFilter(RxFilterType::V6_MULTICAST).isOk());
+}
+
+/*
+ * AddExtRadioWork
+ */
+TEST_P(SupplicantStaIfaceAidlTest, AddExtRadioWork) {
+    const std::string radioWorkName = "TestRadioWork";
+    const int32_t radioWorkFreq = 2412;
+    const int32_t radioWorkTimeout = 8;
+    int32_t radioWorkId;
+    EXPECT_TRUE(sta_iface_
+                    ->addExtRadioWork(radioWorkName, radioWorkFreq,
+                                      radioWorkTimeout, &radioWorkId)
+                    .isOk());
+    // removeExtRadio only succeeds if the added radio work hasn't started yet,
+    // so there is no guaranteed result from calling removeExtRadioWork here.
+    // Given that, we can't currently test removeExtRadioWork following
+    // a call to addExtRadioWork.
+}
+
+/*
+ * RemoveExtRadioWork
+ */
+TEST_P(SupplicantStaIfaceAidlTest, RemoveExtRadioWork) {
+    // This fails because there is no ongoing radio work with radioWorkId
+    const int32_t radioWorkId = 16;
+    EXPECT_FALSE(sta_iface_->removeExtRadioWork(radioWorkId).isOk());
+}
+
+/*
+ * Add/Remove DppPeerUri
+ */
+TEST_P(SupplicantStaIfaceAidlTest, AddRemoveDppPeerUri) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+        GTEST_SKIP() << "Missing DPP support";
+    }
+    // Add a peer URI and then remove it.
+    int32_t peerId;
+    EXPECT_TRUE(sta_iface_->addDppPeerUri(kTestUri, &peerId).isOk());
+    EXPECT_TRUE(sta_iface_->removeDppUri(peerId).isOk());
+}
+
+/*
+ * FilsHlpAddRequest
+ */
+TEST_P(SupplicantStaIfaceAidlTest, FilsHlpAddRequest) {
+    if (!isFilsSupported(sta_iface_)) {
+        GTEST_SKIP()
+            << "Skipping test since driver/supplicant doesn't support FILS";
+    }
+    const std::vector<uint8_t> destMacAddr = {0x00, 0x11, 0x22,
+                                              0x33, 0x44, 0x55};
+    const std::vector<uint8_t> pktBuffer = std::vector<uint8_t>(300, 0x3a);
+    EXPECT_TRUE(sta_iface_->filsHlpAddRequest(destMacAddr, pktBuffer).isOk());
+}
+
+/*
+ * FilsHlpFlushRequest
+ */
+TEST_P(SupplicantStaIfaceAidlTest, FilsHlpFlushRequest) {
+    if (!isFilsSupported(sta_iface_)) {
+        GTEST_SKIP()
+            << "Skipping test since driver/supplicant doesn't support FILS";
+    }
+    EXPECT_TRUE(sta_iface_->filsHlpFlushRequest().isOk());
+}
+
+/*
+ * StartDppEnrolleeResponder
+ */
+TEST_P(SupplicantStaIfaceAidlTest, StartDppEnrolleeResponder) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+        GTEST_SKIP() << "Missing DPP support";
+    }
+
+    const std::string deviceInfo = "DPP_Responder_Mode_VTS_Test";
+    const std::vector<uint8_t> mac_address = {0x22, 0x33, 0x44,
+                                              0x55, 0x66, 0x77};
+
+    // Generate DPP bootstrap information.
+    DppResponderBootstrapInfo bootstrapInfo;
+    EXPECT_TRUE(
+        sta_iface_
+            ->generateDppBootstrapInfoForResponder(
+                mac_address, deviceInfo, DppCurve::PRIME256V1, &bootstrapInfo)
+            .isOk());
+    EXPECT_NE(-1, bootstrapInfo.bootstrapId);
+    EXPECT_NE(0, bootstrapInfo.bootstrapId);
+    EXPECT_NE(0, bootstrapInfo.listenChannel);
+    const uint32_t bootstrap_id = bootstrapInfo.bootstrapId;
+    const uint32_t listen_channel = bootstrapInfo.listenChannel;
+
+    // Start DPP as Enrollee-Responder.
+    EXPECT_TRUE(sta_iface_->startDppEnrolleeResponder(listen_channel).isOk());
+
+    // Stop DPP Enrollee-Responder mode, ie remove the URI and stop listen.
+    EXPECT_TRUE(sta_iface_->stopDppResponder(bootstrap_id).isOk());
+}
+
+class IfaceDppCallback : public SupplicantStaIfaceCallback {
+    SupplicantStaIfaceAidlTest& parent_;
+    ::ndk::ScopedAStatus onDppSuccess(
+        ::aidl::android::hardware::wifi::supplicant::DppEventType event)
+        override {
+        parent_.code = (uint32_t)event;
+        parent_.dppCallbackType =
+            SupplicantStaIfaceAidlTest::DppCallbackType::EVENT_SUCCESS;
+        parent_.notify();
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppProgress(
+        aidl::android::hardware::wifi::supplicant::DppProgressCode code)
+        override {
+        parent_.code = (uint32_t)code;
+        parent_.dppCallbackType =
+            SupplicantStaIfaceAidlTest::DppCallbackType::EVENT_PROGRESS;
+        parent_.notify();
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppFailure(
+        aidl::android::hardware::wifi::supplicant::DppFailureCode code,
+        const std::string& ssid __attribute__((unused)),
+        const std::string& channelList __attribute__((unused)),
+        const std::vector<char16_t>& bandList
+        __attribute__((unused))) override {
+        parent_.code = (uint32_t)code;
+        parent_.dppCallbackType =
+            SupplicantStaIfaceAidlTest::DppCallbackType::EVENT_FAILURE;
+        parent_.notify();
+        return ndk::ScopedAStatus::ok();
+    }
+
+   public:
+    IfaceDppCallback(SupplicantStaIfaceAidlTest& parent) : parent_(parent){};
+};
+
+/*
+ * StartDppEnrolleeInitiator
+ */
+TEST_P(SupplicantStaIfaceAidlTest, StartDppEnrolleeInitiator) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+        GTEST_SKIP() << "Missing DPP support";
+    }
+
+    // Register callback
+    std::shared_ptr<IfaceDppCallback> callback =
+        ndk::SharedRefBase::make<IfaceDppCallback>(*this);
+    EXPECT_NE(callback, nullptr);
+    EXPECT_TRUE(sta_iface_->registerCallback(callback).isOk());
+
+    // Add a peer URI
+    int32_t peer_id = 0;
+    EXPECT_TRUE(sta_iface_->addDppPeerUri(kTestUri, &peer_id).isOk());
+    EXPECT_NE(0, peer_id);
+    EXPECT_NE(-1, peer_id);
+
+    // Start DPP as Enrollee-Initiator. Since this operation requires two
+    // devices, we start the operation and expect a timeout.
+    EXPECT_TRUE(sta_iface_->startDppEnrolleeInitiator(peer_id, 0).isOk());
+
+    // Wait for the timeout callback
+    EXPECT_EQ(std::cv_status::no_timeout,
+              wait(SupplicantStaIfaceAidlTest::DppCallbackType::EVENT_FAILURE));
+    EXPECT_EQ(SupplicantStaIfaceAidlTest::DppCallbackType::EVENT_FAILURE,
+              dppCallbackType);
+
+    // ...and then remove the peer URI.
+    EXPECT_TRUE(sta_iface_->removeDppUri(peer_id).isOk());
+}
+
+/*
+ * StartDppConfiguratorInitiator
+ */
+TEST_P(SupplicantStaIfaceAidlTest, StartDppConfiguratorInitiator) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+        GTEST_SKIP() << "Missing DPP support";
+    }
+
+    // Register callback
+    std::shared_ptr<IfaceDppCallback> callback =
+        ndk::SharedRefBase::make<IfaceDppCallback>(*this);
+    EXPECT_NE(callback, nullptr);
+    EXPECT_TRUE(sta_iface_->registerCallback(callback).isOk());
+
+    // Add a peer URI
+    int32_t peer_id = 0;
+    EXPECT_TRUE(sta_iface_->addDppPeerUri(kTestUri, &peer_id).isOk());
+    EXPECT_NE(0, peer_id);
+    EXPECT_NE(-1, peer_id);
+
+    const std::string ssid =
+        "6D795F746573745F73736964";  // 'my_test_ssid' encoded in hex
+    const std::string password =
+        "746F70736563726574";  // 'topsecret' encoded in hex
+
+    // Start DPP as Configurator-Initiator. Since this operation requires two
+    // devices, we start the operation and expect a timeout.
+    EXPECT_TRUE(sta_iface_
+                    ->startDppConfiguratorInitiator(peer_id, 0, ssid, password,
+                                                    "", DppNetRole::STA,
+                                                    DppAkm::PSK)
+                    .isOk());
+
+    // Wait for the timeout callback
+    ASSERT_EQ(std::cv_status::no_timeout,
+              wait(SupplicantStaIfaceAidlTest::DppCallbackType::EVENT_FAILURE));
+    ASSERT_EQ(SupplicantStaIfaceAidlTest::DppCallbackType::EVENT_FAILURE,
+              dppCallbackType);
+
+    // ...and then remove the peer URI.
+    EXPECT_TRUE(sta_iface_->removeDppUri(peer_id).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceAidlTest);
+INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantStaIfaceAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             ISupplicant::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
new file mode 100644
index 0000000..c6dd981
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicant.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicantStaNetworkCallback.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/properties.h>
+
+#include "supplicant_test_utils.h"
+
+using aidl::android::hardware::wifi::supplicant::AuthAlgMask;
+using aidl::android::hardware::wifi::supplicant::BnSupplicantStaNetworkCallback;
+using aidl::android::hardware::wifi::supplicant::DebugLevel;
+using aidl::android::hardware::wifi::supplicant::EapMethod;
+using aidl::android::hardware::wifi::supplicant::EapPhase2Method;
+using aidl::android::hardware::wifi::supplicant::GroupCipherMask;
+using aidl::android::hardware::wifi::supplicant::GroupMgmtCipherMask;
+using aidl::android::hardware::wifi::supplicant::IfaceType;
+using aidl::android::hardware::wifi::supplicant::ISupplicant;
+using aidl::android::hardware::wifi::supplicant::ISupplicantStaIface;
+using aidl::android::hardware::wifi::supplicant::ISupplicantStaNetwork;
+using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
+using aidl::android::hardware::wifi::supplicant::
+    NetworkRequestEapSimGsmAuthParams;
+using aidl::android::hardware::wifi::supplicant::
+    NetworkRequestEapSimUmtsAuthParams;
+using aidl::android::hardware::wifi::supplicant::
+    NetworkResponseEapSimGsmAuthParams;
+using aidl::android::hardware::wifi::supplicant::
+    NetworkResponseEapSimUmtsAuthParams;
+using aidl::android::hardware::wifi::supplicant::OcspType;
+using aidl::android::hardware::wifi::supplicant::PairwiseCipherMask;
+using aidl::android::hardware::wifi::supplicant::ProtoMask;
+using aidl::android::hardware::wifi::supplicant::SaeH2eMode;
+using aidl::android::hardware::wifi::supplicant::TransitionDisableIndication;
+using aidl::android::hardware::wifi::supplicant::WpaDriverCapabilitiesMask;
+using android::ProcessState;
+
+namespace {
+const std::vector<uint8_t> kTestIdentity = {0x45, 0x67, 0x98, 0x67, 0x56};
+const std::vector<uint8_t> kTestEncryptedIdentity = {0x35, 0x37, 0x58, 0x57,
+                                                     0x26};
+const std::string kTestSsidStr = "TestSsid1234";
+const std::vector<uint8_t> kTestSsid =
+    std::vector<uint8_t>(kTestSsidStr.begin(), kTestSsidStr.end());
+const std::vector<uint8_t> kTestBssid = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
+const std::string kTestPskPassphrase =
+    "\"123456780abcdef0123456780abcdef0deadbeef\"";
+const std::string kTestEapCert = "keystore://CERT";
+const std::string kTestEapMatch = "match";
+const KeyMgmtMask kTestKeyMgmt =
+    static_cast<KeyMgmtMask>(static_cast<uint32_t>(KeyMgmtMask::WPA_PSK) |
+                             static_cast<uint32_t>(KeyMgmtMask::WPA_EAP));
+
+}  // namespace
+
+class SupplicantStaNetworkCallback : public BnSupplicantStaNetworkCallback {
+   public:
+    SupplicantStaNetworkCallback() = default;
+
+    ::ndk::ScopedAStatus onNetworkEapIdentityRequest() override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onNetworkEapSimGsmAuthRequest(
+        const NetworkRequestEapSimGsmAuthParams& /* params */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onNetworkEapSimUmtsAuthRequest(
+        const NetworkRequestEapSimUmtsAuthParams& /* params */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onTransitionDisable(
+        TransitionDisableIndication /* ind */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onServerCertificateAvailable(
+            int32_t /* depth */, const std::vector<uint8_t>& /* subject */,
+            const std::vector<uint8_t>& /* certHash */,
+            const std::vector<uint8_t>& /* certBlob */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+class SupplicantStaNetworkAidlTest
+    : public testing::TestWithParam<std::string> {
+   public:
+    void SetUp() override {
+        initializeService();
+        supplicant_ = ISupplicant::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(supplicant_, nullptr);
+        ASSERT_TRUE(supplicant_
+                        ->setDebugParams(DebugLevel::EXCESSIVE,
+                                         true,  // show timestamps
+                                         true)
+                        .isOk());
+        EXPECT_TRUE(supplicant_->addStaInterface(getStaIfaceName(), &sta_iface_)
+                        .isOk());
+        ASSERT_NE(sta_iface_, nullptr);
+        EXPECT_TRUE(sta_iface_->addNetwork(&sta_network_).isOk());
+        ASSERT_NE(sta_network_, nullptr);
+    }
+
+    void TearDown() override {
+        stopSupplicant();
+        startWifiFramework();
+    }
+
+   protected:
+    std::shared_ptr<ISupplicant> supplicant_;
+    std::shared_ptr<ISupplicantStaIface> sta_iface_;
+    std::shared_ptr<ISupplicantStaNetwork> sta_network_;
+
+    void removeNetwork() {
+        ASSERT_NE(sta_iface_, nullptr);
+        int32_t net_id;
+        EXPECT_TRUE(sta_network_->getId(&net_id).isOk());
+        EXPECT_TRUE(sta_iface_->removeNetwork(net_id).isOk());
+    }
+};
+
+/*
+ * RegisterCallback
+ */
+TEST_P(SupplicantStaNetworkAidlTest, RegisterCallback) {
+    std::shared_ptr<SupplicantStaNetworkCallback> callback =
+        ndk::SharedRefBase::make<SupplicantStaNetworkCallback>();
+    ASSERT_NE(callback, nullptr);
+    EXPECT_TRUE(sta_network_->registerCallback(callback).isOk());
+}
+
+/*
+ * GetInterfaceName
+ */
+TEST_P(SupplicantStaNetworkAidlTest, GetInterfaceName) {
+    std::string name;
+    EXPECT_TRUE(sta_network_->getInterfaceName(&name).isOk());
+    EXPECT_NE(name.size(), 0);
+}
+
+/*
+ * GetType
+ */
+TEST_P(SupplicantStaNetworkAidlTest, GetType) {
+    IfaceType type;
+    EXPECT_TRUE(sta_network_->getType(&type).isOk());
+    EXPECT_EQ(type, IfaceType::STA);
+}
+
+/*
+ * Set/Get ScanSsid
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetScanSsid) {
+    bool scanSsid = false;
+    EXPECT_TRUE(sta_network_->setScanSsid(true).isOk());
+    EXPECT_TRUE(sta_network_->getScanSsid(&scanSsid).isOk());
+    EXPECT_TRUE(scanSsid);
+}
+
+/*
+ * Set/Get RequirePmf
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetRequirePmf) {
+    bool requirePmf = false;
+    EXPECT_TRUE(sta_network_->setRequirePmf(true).isOk());
+    EXPECT_TRUE(sta_network_->getRequirePmf(&requirePmf).isOk());
+    EXPECT_TRUE(requirePmf);
+}
+
+/*
+ * Set/Get IdStr
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetIdStr) {
+    const std::string savedIdStr = "TestIdstr";
+    EXPECT_TRUE(sta_network_->setIdStr(savedIdStr).isOk());
+
+    std::string retrievedIdStr;
+    EXPECT_TRUE(sta_network_->getIdStr(&retrievedIdStr).isOk());
+    EXPECT_EQ(retrievedIdStr, savedIdStr);
+}
+
+/*
+ * Set/Get EapMethod
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapMethod) {
+    const EapMethod savedMethod = EapMethod::PEAP;
+    EXPECT_TRUE(sta_network_->setEapMethod(savedMethod).isOk());
+
+    EapMethod retrievedMethod;
+    EXPECT_TRUE(sta_network_->getEapMethod(&retrievedMethod).isOk());
+    EXPECT_EQ(retrievedMethod, savedMethod);
+}
+
+/*
+ * Set/Get EapPhase2Method
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapPhase2Method) {
+    const EapMethod savedEapMethod = EapMethod::PEAP;
+    EXPECT_TRUE(sta_network_->setEapMethod(savedEapMethod).isOk());
+
+    const EapPhase2Method savedPhase2Method = EapPhase2Method::NONE;
+    EXPECT_TRUE(sta_network_->setEapPhase2Method(savedPhase2Method).isOk());
+
+    EapPhase2Method retrievedMethod;
+    EXPECT_TRUE(sta_network_->getEapPhase2Method(&retrievedMethod).isOk());
+    EXPECT_EQ(retrievedMethod, savedPhase2Method);
+}
+
+/*
+ * Set/Get EapIdentity
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapIdentity) {
+    EXPECT_TRUE(sta_network_->setEapIdentity(kTestIdentity).isOk());
+
+    std::vector<uint8_t> retrievedIdentity;
+    EXPECT_TRUE(sta_network_->getEapIdentity(&retrievedIdentity).isOk());
+    EXPECT_EQ(retrievedIdentity, kTestIdentity);
+}
+
+/*
+ * Set/Get EapAnonymousIdentity
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapAnonymousIdentity) {
+    EXPECT_TRUE(sta_network_->setEapAnonymousIdentity(kTestIdentity).isOk());
+
+    std::vector<uint8_t> retrievedIdentity;
+    EXPECT_TRUE(
+        sta_network_->getEapAnonymousIdentity(&retrievedIdentity).isOk());
+    EXPECT_EQ(retrievedIdentity, kTestIdentity);
+}
+
+/*
+ * Set/Get EapPassword
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapPassword) {
+    const std::string eapPasswdStr = "TestEapPasswd1234";
+    const std::vector<uint8_t> savedEapPasswd =
+        std::vector<uint8_t>(eapPasswdStr.begin(), eapPasswdStr.end());
+    ASSERT_TRUE(sta_network_->setEapPassword(savedEapPasswd).isOk());
+
+    std::vector<uint8_t> retrievedEapPasswd;
+    ASSERT_TRUE(sta_network_->getEapPassword(&retrievedEapPasswd).isOk());
+    ASSERT_EQ(retrievedEapPasswd, savedEapPasswd);
+}
+
+/*
+ * Set/Get EapCACert
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapCACert) {
+    EXPECT_TRUE(sta_network_->setEapCACert(kTestEapCert).isOk());
+
+    std::string retrievedCert;
+    EXPECT_TRUE(sta_network_->getEapCACert(&retrievedCert).isOk());
+    EXPECT_EQ(retrievedCert, kTestEapCert);
+}
+
+/*
+ * Set/Get EapCAPath
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapCAPath) {
+    EXPECT_TRUE(sta_network_->setEapCAPath(kTestEapCert).isOk());
+
+    std::string retrievedCert;
+    EXPECT_TRUE(sta_network_->getEapCAPath(&retrievedCert).isOk());
+    EXPECT_EQ(retrievedCert, kTestEapCert);
+}
+
+/*
+ * Set/Get EapClientCert
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapClientCert) {
+    EXPECT_TRUE(sta_network_->setEapClientCert(kTestEapCert).isOk());
+
+    std::string retrievedCert;
+    EXPECT_TRUE(sta_network_->getEapClientCert(&retrievedCert).isOk());
+    EXPECT_EQ(retrievedCert, kTestEapCert);
+}
+
+/*
+ * Set/Get EapPrivateKeyId
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapPrivateKeyId) {
+    std::string savedKeyId = "key_id";
+    EXPECT_TRUE(sta_network_->setEapPrivateKeyId(savedKeyId).isOk());
+
+    std::string retrievedKeyId;
+    EXPECT_TRUE(sta_network_->getEapPrivateKeyId(&retrievedKeyId).isOk());
+    EXPECT_EQ(retrievedKeyId, savedKeyId);
+}
+
+/*
+ * Set/Get EapAltSubjectMatch
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapAltSubjectMatch) {
+    EXPECT_TRUE(sta_network_->setEapAltSubjectMatch(kTestEapMatch).isOk());
+
+    std::string retrievedMatch;
+    EXPECT_TRUE(sta_network_->getEapAltSubjectMatch(&retrievedMatch).isOk());
+    EXPECT_EQ(retrievedMatch, kTestEapMatch);
+}
+
+/*
+ * Set/Get EapSubjectMatch
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapSubjectMatch) {
+    EXPECT_TRUE(sta_network_->setEapSubjectMatch(kTestEapMatch).isOk());
+
+    std::string retrievedMatch;
+    EXPECT_TRUE(sta_network_->getEapSubjectMatch(&retrievedMatch).isOk());
+    EXPECT_EQ(retrievedMatch, kTestEapMatch);
+}
+
+/*
+ * Set/Get EapDomainSuffixMatch
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapDomainSuffixMatch) {
+    EXPECT_TRUE(sta_network_->setEapDomainSuffixMatch(kTestEapMatch).isOk());
+
+    std::string retrievedMatch;
+    EXPECT_TRUE(sta_network_->getEapDomainSuffixMatch(&retrievedMatch).isOk());
+    EXPECT_EQ(retrievedMatch, kTestEapMatch);
+}
+
+/*
+ * Set/Get EapEngine
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapEngine) {
+    bool retrievedEapEngine = false;
+    EXPECT_TRUE(sta_network_->setEapEngine(true).isOk());
+    EXPECT_TRUE(sta_network_->getEapEngine(&retrievedEapEngine).isOk());
+    EXPECT_TRUE(retrievedEapEngine);
+}
+
+/*
+ * Set/Get EapEngineID
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetEapEngineId) {
+    const std::string savedEngineId = "engine_id";
+    EXPECT_TRUE(sta_network_->setEapEngineID(savedEngineId).isOk());
+
+    std::string retrievedId;
+    EXPECT_TRUE(sta_network_->getEapEngineId(&retrievedId).isOk());
+    EXPECT_EQ(retrievedId, savedEngineId);
+}
+
+/*
+ * Set/Get Ocsp
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetOcsp) {
+    const OcspType savedOcspType = OcspType::REQUEST_CERT_STATUS;
+    EXPECT_TRUE(sta_network_->setOcsp(savedOcspType).isOk());
+
+    const OcspType invalidOcspType = static_cast<OcspType>(-1);
+    EXPECT_FALSE(sta_network_->setOcsp(invalidOcspType).isOk());
+
+    OcspType retrievedOcspType;
+    EXPECT_TRUE(sta_network_->getOcsp(&retrievedOcspType).isOk());
+    EXPECT_EQ(retrievedOcspType, savedOcspType);
+}
+
+/*
+ * Set/Get KeyMgmt
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetKeyMgmt) {
+    KeyMgmtMask savedKeyMgmt = KeyMgmtMask::WAPI_PSK;
+    EXPECT_TRUE(sta_network_->setKeyMgmt(savedKeyMgmt).isOk());
+
+    KeyMgmtMask retrievedKeyMgmt;
+    EXPECT_TRUE(sta_network_->getKeyMgmt(&retrievedKeyMgmt).isOk());
+    EXPECT_EQ(retrievedKeyMgmt, savedKeyMgmt);
+
+    savedKeyMgmt = KeyMgmtMask::WAPI_CERT;
+    EXPECT_TRUE(sta_network_->setKeyMgmt(savedKeyMgmt).isOk());
+
+    EXPECT_TRUE(sta_network_->getKeyMgmt(&retrievedKeyMgmt).isOk());
+    EXPECT_EQ(retrievedKeyMgmt, savedKeyMgmt);
+}
+
+/*
+ * Set/Get Proto
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetProto) {
+    const ProtoMask savedProto = ProtoMask::WAPI;
+    EXPECT_TRUE(sta_network_->setProto(savedProto).isOk());
+
+    ProtoMask retrievedProto;
+    EXPECT_TRUE(sta_network_->getProto(&retrievedProto).isOk());
+    EXPECT_EQ(retrievedProto, savedProto);
+}
+
+/*
+ * Set/Get GroupCipher
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetGroupCipher) {
+    const GroupCipherMask savedCipher = GroupCipherMask::SMS4;
+    EXPECT_TRUE(sta_network_->setGroupCipher(savedCipher).isOk());
+
+    GroupCipherMask retrievedCipher;
+    EXPECT_TRUE(sta_network_->getGroupCipher(&retrievedCipher).isOk());
+    EXPECT_EQ(retrievedCipher, savedCipher);
+}
+
+/*
+ * Set/Get PairwiseCipher
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetPairwiseCipher) {
+    const PairwiseCipherMask savedCipher = PairwiseCipherMask::SMS4;
+    EXPECT_TRUE(sta_network_->setPairwiseCipher(savedCipher).isOk());
+
+    PairwiseCipherMask retrievedCipher;
+    EXPECT_TRUE(sta_network_->getPairwiseCipher(&retrievedCipher).isOk());
+    EXPECT_EQ(retrievedCipher, savedCipher);
+}
+
+/*
+ * Set/Get WapiCertSuite
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetWapiCertSuite) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::WAPI_PSK)) {
+        GTEST_SKIP() << "Skipping test since WAPI is not supported.";
+    }
+
+    const std::string savedCertSuite = "suite";
+    EXPECT_TRUE(sta_network_->setWapiCertSuite(savedCertSuite).isOk());
+
+    std::string retrievedCertSuite;
+    EXPECT_TRUE(sta_network_->getWapiCertSuite(&retrievedCertSuite).isOk());
+    EXPECT_EQ(retrievedCertSuite, savedCertSuite);
+}
+
+/*
+ * Set/Get WapiPsk
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetWapiPsk) {
+    if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::WAPI_PSK)) {
+        GTEST_SKIP() << "Skipping test since WAPI is not supported.";
+    }
+
+    EXPECT_TRUE(sta_network_->setKeyMgmt(KeyMgmtMask::WAPI_PSK).isOk());
+    EXPECT_TRUE(sta_network_->setPskPassphrase(kTestPskPassphrase).isOk());
+
+    std::string retrievedPassphrase;
+    EXPECT_TRUE(sta_network_->getPskPassphrase(&retrievedPassphrase).isOk());
+    EXPECT_EQ(retrievedPassphrase, kTestPskPassphrase);
+
+    const std::string pskHex = "12345678";
+    EXPECT_TRUE(sta_network_->setPskPassphrase(pskHex).isOk());
+
+    EXPECT_TRUE(sta_network_->getPskPassphrase(&retrievedPassphrase).isOk());
+    EXPECT_EQ(retrievedPassphrase, pskHex);
+}
+
+/*
+ * Set/Get SaePassword
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetSaePassword) {
+    const std::string savedPassword = "topsecret";
+    EXPECT_TRUE(sta_network_->setSaePassword(savedPassword).isOk());
+
+    std::string retrievedPassword;
+    EXPECT_TRUE(sta_network_->getSaePassword(&retrievedPassword).isOk());
+    EXPECT_EQ(retrievedPassword, savedPassword);
+}
+
+/*
+ * Set/Get SaePasswordId
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetSaePasswordId) {
+    const std::string savedPasswdId = "id1";
+    EXPECT_TRUE(sta_network_->setSaePasswordId(savedPasswdId).isOk());
+
+    std::string retrievedPasswdId;
+    EXPECT_TRUE(sta_network_->getSaePasswordId(&retrievedPasswdId).isOk());
+    EXPECT_EQ(retrievedPasswdId, savedPasswdId);
+}
+
+/*
+ * Set/Get GroupMgmtCipher
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetGroupMgmtCipher) {
+    const GroupMgmtCipherMask savedCipher = GroupMgmtCipherMask::BIP_GMAC_256;
+    EXPECT_TRUE(sta_network_->setGroupMgmtCipher(savedCipher).isOk());
+
+    GroupMgmtCipherMask retrievedCipher;
+    EXPECT_TRUE(sta_network_->getGroupMgmtCipher(&retrievedCipher).isOk());
+    EXPECT_EQ(retrievedCipher, savedCipher);
+}
+
+/*
+ * Set/Get Ssid
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetSsid) {
+    EXPECT_TRUE(sta_network_->setSsid(kTestSsid).isOk());
+
+    std::vector<uint8_t> retrievedSsid;
+    EXPECT_TRUE(sta_network_->getSsid(&retrievedSsid).isOk());
+    EXPECT_EQ(retrievedSsid, kTestSsid);
+}
+
+/*
+ * Set/Get Bssid
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetBssid) {
+    EXPECT_TRUE(sta_network_->setBssid(kTestBssid).isOk());
+
+    std::vector<uint8_t> retrievedBssid;
+    EXPECT_TRUE(sta_network_->getBssid(&retrievedBssid).isOk());
+    EXPECT_EQ(retrievedBssid, kTestBssid);
+}
+
+/*
+ * Set/Get KeyAuthAlg
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetAuthAlg) {
+    const AuthAlgMask savedAlg =
+        static_cast<AuthAlgMask>(static_cast<uint32_t>(AuthAlgMask::OPEN) |
+                                 static_cast<uint32_t>(AuthAlgMask::SHARED));
+    EXPECT_TRUE(sta_network_->setAuthAlg(savedAlg).isOk());
+
+    AuthAlgMask retrievedAlg;
+    EXPECT_TRUE(sta_network_->getAuthAlg(&retrievedAlg).isOk());
+    EXPECT_EQ(retrievedAlg, savedAlg);
+}
+
+/*
+ * Set/Get WepTxKeyIdx
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetWepTxKeyIdx) {
+    const int32_t savedKeyIdx = 2;
+    EXPECT_TRUE(sta_network_->setWepTxKeyIdx(savedKeyIdx).isOk());
+
+    int32_t retrievedKeyIdx;
+    EXPECT_TRUE(sta_network_->getWepTxKeyIdx(&retrievedKeyIdx).isOk());
+    EXPECT_EQ(retrievedKeyIdx, savedKeyIdx);
+}
+
+/*
+ * Set SAE H2E (Hash-to-Element) mode
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetSaeH2eMode) {
+    EXPECT_TRUE(sta_network_->setSaeH2eMode(SaeH2eMode::DISABLED).isOk());
+    EXPECT_TRUE(sta_network_->setSaeH2eMode(SaeH2eMode::H2E_MANDATORY).isOk());
+    EXPECT_TRUE(sta_network_->setSaeH2eMode(SaeH2eMode::H2E_OPTIONAL).isOk());
+}
+
+/*
+ * Set/Get Psk
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetPsk) {
+    const std::vector<uint8_t> savedPsk = std::vector<uint8_t>(32, 0x12);
+    EXPECT_TRUE(sta_network_->setPsk(savedPsk).isOk());
+
+    std::vector<uint8_t> retrievedPsk;
+    EXPECT_TRUE(sta_network_->getPsk(&retrievedPsk).isOk());
+    EXPECT_EQ(retrievedPsk, savedPsk);
+}
+
+/*
+ * Set/Get WepKeys
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetGetWepKeys) {
+    const uint32_t maxKeys = 4;
+    const std::vector<uint8_t> testWepKey = {0x56, 0x67, 0x67, 0xf4, 0x56};
+
+    for (uint32_t i = 0; i < maxKeys; i++) {
+        std::vector<uint8_t> retrievedKey;
+        EXPECT_TRUE(sta_network_->setWepKey(i, testWepKey).isOk());
+        EXPECT_TRUE(sta_network_->getWepKey(i, &retrievedKey).isOk());
+        EXPECT_EQ(retrievedKey, testWepKey);
+    }
+}
+
+/*
+ * SetPmkCacheEntry
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetPmkCache) {
+    const std::vector<uint8_t> serializedEntry(128, 0);
+    EXPECT_TRUE(sta_network_->setPmkCache(serializedEntry).isOk());
+}
+
+/*
+ * SetEapErp
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetEapErp) {
+    if (!isFilsSupported(sta_iface_)) {
+        GTEST_SKIP()
+            << "Skipping test since driver/supplicant doesn't support FILS";
+    }
+    EXPECT_TRUE(sta_network_->setEapErp(true).isOk());
+}
+
+/*
+ * SetUpdateIdentifier
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetUpdateIdentifier) {
+    const uint32_t updateIdentifier = 21;
+    EXPECT_TRUE(sta_network_->setUpdateIdentifier(updateIdentifier).isOk());
+}
+
+/*
+ * SetProactiveKeyCaching
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetProactiveKeyCaching) {
+    EXPECT_TRUE(sta_network_->setProactiveKeyCaching(true).isOk());
+    EXPECT_TRUE(sta_network_->setProactiveKeyCaching(false).isOk());
+}
+
+/*
+ * EnableSuiteBEapOpenSslCiphers
+ */
+TEST_P(SupplicantStaNetworkAidlTest, EnableSuiteBEapOpenSslCiphers) {
+    EXPECT_TRUE(sta_network_->enableSuiteBEapOpenSslCiphers().isOk());
+}
+
+/*
+ * EnableTlsSuiteBEapPhase1Param
+ */
+TEST_P(SupplicantStaNetworkAidlTest, EnableTlsSuiteBEapPhase1Param) {
+    EXPECT_TRUE(sta_network_->enableTlsSuiteBEapPhase1Param(true).isOk());
+    EXPECT_TRUE(sta_network_->enableTlsSuiteBEapPhase1Param(false).isOk());
+}
+
+/*
+ * SetEapEncryptedImsiIdentity
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetEapEncryptedImsiIdentity) {
+    EXPECT_TRUE(
+        sta_network_->setEapEncryptedImsiIdentity(kTestEncryptedIdentity)
+            .isOk());
+}
+
+/*
+ * SendNetworkEapIdentityResponse
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapIdentityResponse) {
+    EXPECT_TRUE(sta_network_
+                    ->sendNetworkEapIdentityResponse(kTestIdentity,
+                                                     kTestEncryptedIdentity)
+                    .isOk());
+}
+
+/*
+ * Enable SAE PK only mode
+ */
+TEST_P(SupplicantStaNetworkAidlTest, EnableSaePkOnlyMode) {
+    // Check for SAE PK support
+    WpaDriverCapabilitiesMask caps;
+    EXPECT_TRUE(sta_iface_->getWpaDriverCapabilities(&caps).isOk());
+    const bool saePkSupported =
+        !!(static_cast<uint32_t>(caps) &
+           static_cast<uint32_t>(WpaDriverCapabilitiesMask::SAE_PK));
+    LOG(INFO) << "SAE-PK Supported: " << saePkSupported;
+
+    // Operation will succeed if SAE PK is supported, or fail otherwise.
+    EXPECT_EQ(sta_network_->enableSaePkOnlyMode(true).isOk(), saePkSupported);
+    EXPECT_EQ(sta_network_->enableSaePkOnlyMode(false).isOk(), saePkSupported);
+}
+
+/*
+ * Enable
+ */
+TEST_P(SupplicantStaNetworkAidlTest, Enable) {
+    // wpa_supplicant won't perform any connection initiation
+    // unless at least the SSID and key mgmt params are set.
+    EXPECT_TRUE(sta_network_->setSsid(kTestSsid).isOk());
+    EXPECT_TRUE(sta_network_->setKeyMgmt(kTestKeyMgmt).isOk());
+
+    EXPECT_TRUE(sta_network_->enable(false).isOk());
+    EXPECT_TRUE(sta_network_->enable(true).isOk());
+
+    // Now remove the network and ensure that the call fails.
+    removeNetwork();
+    ASSERT_FALSE(sta_network_->enable(true).isOk());
+}
+
+/*
+ * Disable
+ */
+TEST_P(SupplicantStaNetworkAidlTest, Disable) {
+    // wpa_supplicant won't perform any connection initiation
+    // unless at least the SSID and key mgmt params are set.
+    EXPECT_TRUE(sta_network_->setSsid(kTestSsid).isOk());
+    EXPECT_TRUE(sta_network_->setKeyMgmt(kTestKeyMgmt).isOk());
+
+    EXPECT_TRUE(sta_network_->disable().isOk());
+
+    // Now remove the network and ensure that the call fails.
+    removeNetwork();
+    EXPECT_FALSE(sta_network_->disable().isOk());
+}
+
+/*
+ * Select
+ */
+TEST_P(SupplicantStaNetworkAidlTest, Select) {
+    // wpa_supplicant won't perform any connection initiation
+    // unless at least the SSID and key mgmt params are set.
+    EXPECT_TRUE(sta_network_->setSsid(kTestSsid).isOk());
+    EXPECT_TRUE(sta_network_->setKeyMgmt(kTestKeyMgmt).isOk());
+
+    EXPECT_TRUE(sta_network_->select().isOk());
+
+    // Now remove the network and ensure that the call fails.
+    removeNetwork();
+    EXPECT_FALSE(sta_network_->select().isOk());
+}
+
+/*
+ * SendNetworkEapSimGsmAuthResponse
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapSimGsmAuthResponse) {
+    NetworkResponseEapSimGsmAuthParams param;
+    param.kc =
+        std::vector<uint8_t>({0x56, 0x67, 0x67, 0xf4, 0x76, 0x87, 0x98, 0x12});
+    param.sres = std::vector<uint8_t>({0x56, 0x67, 0x67, 0xf4});
+    const std::vector<NetworkResponseEapSimGsmAuthParams> params = {param};
+    EXPECT_TRUE(sta_network_->sendNetworkEapSimGsmAuthResponse(params).isOk());
+}
+
+/*
+ * SendNetworkEapSimGsmAuthFailure
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapSimGsmAuthFailure) {
+    EXPECT_TRUE(sta_network_->sendNetworkEapSimGsmAuthFailure().isOk());
+}
+
+/*
+ * SendNetworkEapSimUmtsAuthResponse
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapSimUmtsAuthResponse) {
+    NetworkResponseEapSimUmtsAuthParams params;
+    params.res = std::vector<uint8_t>({0x56, 0x67, 0x67, 0xf4, 0x67});
+    params.ik = std::vector<uint8_t>(16, 0x65);
+    params.ck = std::vector<uint8_t>(16, 0x45);
+    EXPECT_TRUE(sta_network_->sendNetworkEapSimUmtsAuthResponse(params).isOk());
+}
+
+/*
+ * SendNetworkEapSimUmtsAuthFailure
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapSimUmtsAuthFailure) {
+    EXPECT_TRUE(sta_network_->sendNetworkEapSimUmtsAuthFailure().isOk());
+}
+
+/*
+ * SendNetworkEapSimUmtsAutsResponse
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapSimUmtsAutsResponse) {
+    const std::vector<uint8_t> testAutParam = std::vector<uint8_t>(14, 0xe1);
+    EXPECT_TRUE(
+        sta_network_->sendNetworkEapSimUmtsAutsResponse(testAutParam).isOk());
+}
+
+/*
+ * GetWpsNfcConfigurationToken
+ */
+TEST_P(SupplicantStaNetworkAidlTest, GetWpsNfcConfigurationToken) {
+    EXPECT_TRUE(sta_network_->setSsid(kTestSsid).isOk());
+    EXPECT_TRUE(sta_network_->setKeyMgmt(kTestKeyMgmt).isOk());
+    EXPECT_TRUE(sta_network_->setPskPassphrase(kTestPskPassphrase).isOk());
+
+    std::vector<uint8_t> retrievedToken;
+    EXPECT_TRUE(
+        sta_network_->getWpsNfcConfigurationToken(&retrievedToken).isOk());
+    EXPECT_NE(retrievedToken.size(), 0);
+}
+
+/*
+ * SetRoamingConsortiumSelection
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetRoamingConsortiumSelection) {
+    const std::vector<uint8_t> testSelection = std::vector<uint8_t>({0x11, 0x21, 0x33, 0x44});
+    EXPECT_TRUE(sta_network_->setRoamingConsortiumSelection(testSelection).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkAidlTest);
+INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantStaNetworkAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             ISupplicant::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
new file mode 100644
index 0000000..b7e1a80
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SUPPLICANT_TEST_UTILS_H
+#define SUPPLICANT_TEST_UTILS_H
+
+#include <VtsCoreUtil.h>
+#include <android-base/logging.h>
+#include <wifi_system/supplicant_manager.h>
+
+using aidl::android::hardware::wifi::supplicant::ISupplicantStaIface;
+using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
+using android::wifi_system::SupplicantManager;
+
+std::string getStaIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.interface", buffer.data(), "wlan0");
+    return std::string(buffer.data());
+}
+
+std::string getP2pIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.direct.interface", buffer.data(), "p2p0");
+    return std::string(buffer.data());
+}
+
+bool keyMgmtSupported(std::shared_ptr<ISupplicantStaIface> iface,
+                      KeyMgmtMask expected) {
+    KeyMgmtMask caps;
+    if (!iface->getKeyMgmtCapabilities(&caps).isOk()) {
+        return false;
+    }
+    return !!(static_cast<uint32_t>(caps) & static_cast<uint32_t>(expected));
+}
+
+bool isFilsSupported(std::shared_ptr<ISupplicantStaIface> iface) {
+    KeyMgmtMask filsMask = static_cast<KeyMgmtMask>(
+        static_cast<uint32_t>(KeyMgmtMask::FILS_SHA256) |
+        static_cast<uint32_t>(KeyMgmtMask::FILS_SHA384));
+    return keyMgmtSupported(iface, filsMask);
+}
+
+bool waitForSupplicantState(bool is_running) {
+    SupplicantManager supplicant_manager;
+    int count = 50; /* wait at most 5 seconds for completion */
+    while (count-- > 0) {
+        if (supplicant_manager.IsSupplicantRunning() == is_running) {
+            return true;
+        }
+        usleep(100000);
+    }
+    LOG(ERROR) << "Supplicant not " << (is_running ? "running" : "stopped");
+    return false;
+}
+
+bool waitForFrameworkReady() {
+    int waitCount = 15;
+    do {
+        // Check whether package service is ready or not.
+        if (!testing::checkSubstringInCommandOutput(
+                "/system/bin/service check package", ": not found")) {
+            return true;
+        }
+        LOG(INFO) << "Framework is not ready";
+        sleep(1);
+    } while (waitCount-- > 0);
+    return false;
+}
+
+bool waitForSupplicantStart() { return waitForSupplicantState(true); }
+
+bool waitForSupplicantStop() { return waitForSupplicantState(false); }
+
+void stopSupplicant() {
+    SupplicantManager supplicant_manager;
+    ASSERT_TRUE(supplicant_manager.StopSupplicant());
+    ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
+}
+
+bool startWifiFramework() {
+    std::system("svc wifi enable");
+    std::system("cmd wifi set-scan-always-available enabled");
+    return waitForSupplicantStart();
+}
+
+bool stopWifiFramework() {
+    std::system("svc wifi disable");
+    std::system("cmd wifi set-scan-always-available disabled");
+    return waitForSupplicantStop();
+}
+
+void initializeService() {
+    ASSERT_TRUE(stopWifiFramework());
+    std::system("/system/bin/start");
+    ASSERT_TRUE(waitForFrameworkReady());
+    stopSupplicant();
+}
+
+#endif  // SUPPLICANT_TEST_UTILS_H
\ No newline at end of file