Merge "Finish IRadio 1.6/IRadioConfig 1.3 AIDL VTS"
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/automotive/can/1.0/tools/libprotocan/Android.bp b/automotive/can/1.0/tools/libprotocan/Android.bp
new file mode 100644
index 0000000..76c238b
--- /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.vehicle@2.0-protocan-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/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
index d7d5476..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;
   }
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/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
index 2fe31d5..9435311 100644
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
+++ b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
@@ -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;
   }
diff --git a/dumpstate/aidl/Android.bp b/dumpstate/aidl/Android.bp
index e18eade..22d836b 100644
--- a/dumpstate/aidl/Android.bp
+++ b/dumpstate/aidl/Android.bp
@@ -34,7 +34,6 @@
             enabled: false,
         },
         ndk: {
-            separate_platform_variant: false,
             vndk: {
                 enabled: true,
             },
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index 6e2f1d4..22bb4fa 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -37,7 +37,6 @@
             sdk_version: "module_current",
         },
         ndk: {
-            separate_platform_variant: false,
             vndk: {
                 enabled: true,
             },
diff --git a/ir/aidl/Android.bp b/ir/aidl/Android.bp
index 8741157..6dacb85 100644
--- a/ir/aidl/Android.bp
+++ b/ir/aidl/Android.bp
@@ -25,7 +25,6 @@
             sdk_version: "module_current",
         },
         ndk: {
-            separate_platform_variant: false,
             vndk: {
                 // TODO(b/206116595) enable this
                 enabled: false,
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/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 decf5b1..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
@@ -45,4 +45,6 @@
   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/ITuner.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
index 1fcbb06..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;
@@ -127,4 +128,24 @@
      * @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/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index 45f3dfa..48c1b66 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -64,6 +64,7 @@
             FrontendStatusType::STREAM_ID_LIST,
     };
     mFrontendStatusCaps[0] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ISDBS] = 1;
 
     FrontendCapabilities capsAtsc3;
     capsAtsc3.set<FrontendCapabilities::Tag::atsc3Caps>(FrontendAtsc3Capabilities());
@@ -78,6 +79,7 @@
             FrontendStatusType::BANDWIDTH,
     };
     mFrontendStatusCaps[1] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ATSC3] = 1;
 
     FrontendCapabilities capsDvbc;
     capsDvbc.set<FrontendCapabilities::Tag::dvbcCaps>(FrontendDvbcCapabilities());
@@ -89,6 +91,7 @@
             FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH,
     };
     mFrontendStatusCaps[2] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DVBC] = 1;
 
     FrontendCapabilities capsDvbs;
     capsDvbs.set<FrontendCapabilities::Tag::dvbsCaps>(FrontendDvbsCapabilities());
@@ -99,6 +102,7 @@
             FrontendStatusType::ROLL_OFF,        FrontendStatusType::IS_MISO,
     };
     mFrontendStatusCaps[3] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DVBS] = 1;
 
     FrontendCapabilities capsDvbt;
     capsDvbt.set<FrontendCapabilities::Tag::dvbtCaps>(FrontendDvbtCapabilities());
@@ -115,6 +119,7 @@
             FrontendStatusType::DVBT_CELL_IDS,
     };
     mFrontendStatusCaps[4] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DVBT] = 1;
 
     FrontendCapabilities capsIsdbt;
     FrontendIsdbtCapabilities isdbtCaps{
@@ -145,6 +150,7 @@
             FrontendStatusType::INTERLEAVINGS,
     };
     mFrontendStatusCaps[5] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ISDBT] = 1;
 
     FrontendCapabilities capsAnalog;
     capsAnalog.set<FrontendCapabilities::Tag::analogCaps>(FrontendAnalogCapabilities());
@@ -156,6 +162,7 @@
             FrontendStatusType::TS_DATA_RATES,
     };
     mFrontendStatusCaps[6] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ANALOG] = 1;
 
     FrontendCapabilities capsAtsc;
     capsAtsc.set<FrontendCapabilities::Tag::atscCaps>(FrontendAtscCapabilities());
@@ -167,6 +174,7 @@
             FrontendStatusType::IS_LINEAR,
     };
     mFrontendStatusCaps[7] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ATSC] = 1;
 
     FrontendCapabilities capsIsdbs3;
     capsIsdbs3.set<FrontendCapabilities::Tag::isdbs3Caps>(FrontendIsdbs3Capabilities());
@@ -177,6 +185,7 @@
             FrontendStatusType::IS_SHORT_FRAMES, FrontendStatusType::STREAM_ID_LIST,
     };
     mFrontendStatusCaps[8] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ISDBS3] = 1;
 
     FrontendCapabilities capsDtmb;
     capsDtmb.set<FrontendCapabilities::Tag::dtmbCaps>(FrontendDtmbCapabilities());
@@ -187,6 +196,7 @@
             FrontendStatusType::TRANSMISSION_MODE,
     };
     mFrontendStatusCaps[9] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DTMB] = 1;
 
     mLnbs.resize(2);
     mLnbs[0] = ndk::SharedRefBase::make<Lnb>(0);
@@ -324,6 +334,25 @@
     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__);
     {
diff --git a/tv/tuner/aidl/default/Tuner.h b/tv/tuner/aidl/default/Tuner.h
index b33a1be..216a2b6 100644
--- a/tv/tuner/aidl/default/Tuner.h
+++ b/tv/tuner/aidl/default/Tuner.h
@@ -57,6 +57,10 @@
                                        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;
 
@@ -81,6 +85,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/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 075ffad..41e98ea 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) {
@@ -519,6 +521,41 @@
     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);
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.h b/tv/tuner/aidl/vts/functional/FrontendTests.h
index 8f769a0..1745f76 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.h
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.h
@@ -100,6 +100,7 @@
     void tuneTest(FrontendConfig frontendConf);
     void scanTest(FrontendConfig frontend, FrontendScanType type);
     void debugInfoTest(FrontendConfig frontendConf);
+    void maxNumberOfFrontendsTest();
 
     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 f489bf7..0566089 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -899,6 +899,14 @@
     mFrontendTests.debugInfoTest(frontendMap[live.frontendId]);
 }
 
+TEST_P(TunerFrontendAidlTest, maxNumberOfFrontends) {
+    description("Test Max Frontend number");
+    if (!live.hasFrontendConnection) {
+        return;
+    }
+    mFrontendTests.maxNumberOfFrontendsTest();
+}
+
 TEST_P(TunerBroadcastAidlTest, BroadcastDataFlowVideoFilterTest) {
     description("Test Video Filter functionality in Broadcast use case.");
     if (!live.hasFrontendConnection) {
diff --git a/wifi/1.5/default/wifi_feature_flags.cpp b/wifi/1.5/default/wifi_feature_flags.cpp
index 124ba32..70ce55a 100644
--- a/wifi/1.5/default/wifi_feature_flags.cpp
+++ b/wifi/1.5/default/wifi_feature_flags.cpp
@@ -157,43 +157,42 @@
 // 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{
+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}}})}}},
+           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}}})}}},
+         {{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}}})}}},
+         {{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}}})}}},
+         {{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}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}}};
+           ChipIfaceCombination::make_vec({{{{STA}, 1}, {{P2P, NAN, AP}, 1}}, {{{STA}, 2}}})}}}};
 
 #undef STA
 #undef AP