Merge "Add GNSS HAL v2.0"
diff --git a/atrace/1.0/vts/functional/Android.bp b/atrace/1.0/vts/functional/Android.bp
index 6b50fb5..d3f4276 100644
--- a/atrace/1.0/vts/functional/Android.bp
+++ b/atrace/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalAtraceV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.atrace@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/audio/core/2.0/vts/functional/Android.bp b/audio/core/2.0/vts/functional/Android.bp
index d1ddaff..cfa637b 100644
--- a/audio/core/2.0/vts/functional/Android.bp
+++ b/audio/core/2.0/vts/functional/Android.bp
@@ -29,4 +29,5 @@
         "libicuuc_stubdata",
         "libxml2",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/audio/core/4.0/vts/functional/Android.bp b/audio/core/4.0/vts/functional/Android.bp
index e3b376c..7be888f 100644
--- a/audio/core/4.0/vts/functional/Android.bp
+++ b/audio/core/4.0/vts/functional/Android.bp
@@ -35,4 +35,5 @@
     header_libs: [
         "android.hardware.audio.common.util@all-versions",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp
index 51d2e11..1760e01 100644
--- a/audio/effect/2.0/vts/functional/Android.bp
+++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -32,4 +32,5 @@
         "libicuuc_stubdata",
         "libxml2",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/audio/effect/4.0/vts/functional/Android.bp b/audio/effect/4.0/vts/functional/Android.bp
index 96ded69..d6f8643 100644
--- a/audio/effect/4.0/vts/functional/Android.bp
+++ b/audio/effect/4.0/vts/functional/Android.bp
@@ -35,4 +35,5 @@
     header_libs: [
         "android.hardware.audio.common.util@all-versions",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/authsecret/1.0/vts/functional/Android.bp b/authsecret/1.0/vts/functional/Android.bp
index de9f560..f2b3a8a 100644
--- a/authsecret/1.0/vts/functional/Android.bp
+++ b/authsecret/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalAuthSecretV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.authsecret@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/automotive/audiocontrol/1.0/vts/functional/Android.bp b/automotive/audiocontrol/1.0/vts/functional/Android.bp
index c6e0d8e..3cb6340 100644
--- a/automotive/audiocontrol/1.0/vts/functional/Android.bp
+++ b/automotive/audiocontrol/1.0/vts/functional/Android.bp
@@ -16,16 +16,14 @@
 
 cc_test {
     name: "VtsHalAudioControlV1_0TargetTest",
-
     srcs: [
         "VtsHalAudioControlV1_0TargetTest.cpp",
     ],
-
     defaults: [
         "VtsHalTargetTestDefaults",
     ],
-
     static_libs: [
         "android.hardware.automotive.audiocontrol@1.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp
index 5d696fc..2ef33fd 100644
--- a/automotive/evs/1.0/vts/functional/Android.bp
+++ b/automotive/evs/1.0/vts/functional/Android.bp
@@ -16,21 +16,17 @@
 
 cc_test {
     name: "VtsHalEvsV1_0TargetTest",
-
     srcs: [
         "VtsHalEvsV1_0TargetTest.cpp",
         "FrameHandler.cpp",
         "FormatConvert.cpp"
     ],
-
     defaults: ["VtsHalTargetTestDefaults"],
-
     shared_libs: [
         "libui",
     ],
-
     static_libs: ["android.hardware.automotive.evs@1.0"],
-
+    test_suites: ["general-tests"],
     cflags: [
         "-O0",
         "-g",
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 7802ef0..a11d452 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -95,6 +95,7 @@
         "tests/VmsUtils_test.cpp",
     ],
     header_libs: ["libbase_headers"],
+    test_suites: ["general-tests"],
 }
 
 cc_binary {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 5007a6d..7909ac1 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -381,8 +381,8 @@
                 // kHvacPowerProperties.
                 .configArray =
                     {
-                        0x12400500,  // HVAC_FAN_SPEED
-                        0x12400501   // HVAC_FAN_DIRECTION
+                        toInt(VehicleProperty::HVAC_FAN_SPEED),
+                        toInt(VehicleProperty::HVAC_FAN_DIRECTION)
                     }},
      .initialValue = {.int32Values = {1}}},
 
diff --git a/biometrics/fingerprint/2.1/vts/functional/Android.bp b/biometrics/fingerprint/2.1/vts/functional/Android.bp
index bee3657..60228f2 100644
--- a/biometrics/fingerprint/2.1/vts/functional/Android.bp
+++ b/biometrics/fingerprint/2.1/vts/functional/Android.bp
@@ -19,5 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"],
     static_libs: ["android.hardware.biometrics.fingerprint@2.1"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp
index 48bbadf..f4b1e7b 100644
--- a/bluetooth/1.0/default/Android.bp
+++ b/bluetooth/1.0/default/Android.bp
@@ -94,6 +94,7 @@
         "android.hardware.bluetooth-hci",
         "libgmock",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test_host {
diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp
index 2e60588..54039e5 100644
--- a/bluetooth/1.0/vts/functional/Android.bp
+++ b/bluetooth/1.0/vts/functional/Android.bp
@@ -22,4 +22,5 @@
         "android.hardware.bluetooth@1.0",
         "libbluetooth-types",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/bluetooth/a2dp/1.0/vts/functional/Android.bp b/bluetooth/a2dp/1.0/vts/functional/Android.bp
index f1ffc45..e50e167 100644
--- a/bluetooth/a2dp/1.0/vts/functional/Android.bp
+++ b/bluetooth/a2dp/1.0/vts/functional/Android.bp
@@ -23,4 +23,5 @@
         "android.hardware.bluetooth.a2dp@1.0",
         "libbluetooth-types",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/boot/1.0/vts/functional/Android.bp b/boot/1.0/vts/functional/Android.bp
index 2ef89f3..5d1a9cb 100644
--- a/boot/1.0/vts/functional/Android.bp
+++ b/boot/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalBootV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.boot@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/broadcastradio/1.0/vts/functional/Android.bp b/broadcastradio/1.0/vts/functional/Android.bp
index 7040a01..9ba9fbe 100644
--- a/broadcastradio/1.0/vts/functional/Android.bp
+++ b/broadcastradio/1.0/vts/functional/Android.bp
@@ -22,4 +22,5 @@
         "android.hardware.broadcastradio@1.0",
         "android.hardware.broadcastradio@vts-utils-lib",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
index 9240cf0..0a02a69 100644
--- a/broadcastradio/1.1/vts/functional/Android.bp
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -25,4 +25,5 @@
         "android.hardware.broadcastradio@vts-utils-lib",
         "libgmock",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp
index 900454e..840c4b8 100644
--- a/broadcastradio/2.0/default/Android.bp
+++ b/broadcastradio/2.0/default/Android.bp
@@ -43,7 +43,6 @@
         "libbase",
         "libhidlbase",
         "libhidltransport",
-        "liblog",
         "libutils",
     ],
 }
diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp
index 0148fec..28a0dd5 100644
--- a/broadcastradio/2.0/default/BroadcastRadio.cpp
+++ b/broadcastradio/2.0/default/BroadcastRadio.cpp
@@ -13,15 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "BcRadioDef.module"
-#define LOG_NDEBUG 0
-
 #include "BroadcastRadio.h"
 
-#include <log/log.h>
-
 #include "resources.h"
 
+#include <android-base/logging.h>
+
 namespace android {
 namespace hardware {
 namespace broadcastradio {
@@ -66,7 +63,6 @@
       mAmFmConfig(gDefaultAmFmConfig) {}
 
 Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
-    ALOGV("%s", __func__);
     _hidl_cb(mProperties);
     return {};
 }
@@ -77,8 +73,6 @@
 }
 
 Return<void> BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb) {
-    ALOGV("%s(%d)", __func__, full);
-
     if (full) {
         AmFmRegionConfig config = {};
         config.ranges = hidl_vec<AmFmBandRange>({
@@ -96,8 +90,6 @@
 }
 
 Return<void> BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-
     hidl_vec<DabTableEntry> config = {
         {"5A", 174928},  {"7D", 194064},  {"8A", 195936},  {"8B", 197648},  {"9A", 202928},
         {"9B", 204640},  {"9C", 206352},  {"10B", 211648}, {"10C", 213360}, {"10D", 215072},
@@ -111,7 +103,7 @@
 
 Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback,
                                          openSession_cb _hidl_cb) {
-    ALOGV("%s", __func__);
+    LOG(DEBUG) << "opening new session...";
 
     /* For the needs of default implementation it's fine to instantiate new session object
      * out of the lock scope. If your implementation needs it, use reentrant lock.
@@ -122,7 +114,7 @@
 
     auto oldSession = mSession.promote();
     if (oldSession != nullptr) {
-        ALOGI("Closing previously opened tuner");
+        LOG(INFO) << "closing previously opened tuner";
         oldSession->close();
         mSession = nullptr;
     }
@@ -134,14 +126,14 @@
 }
 
 Return<void> BroadcastRadio::getImage(uint32_t id, getImage_cb _hidl_cb) {
-    ALOGV("%s(%x)", __func__, id);
+    LOG(DEBUG) << "fetching image " << std::hex << id;
 
     if (id == resources::demoPngId) {
         _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
         return {};
     }
 
-    ALOGI("Image %x doesn't exists", id);
+    LOG(INFO) << "image " << std::hex << id << " doesn't exists";
     _hidl_cb({});
     return {};
 }
@@ -149,7 +141,7 @@
 Return<void> BroadcastRadio::registerAnnouncementListener(
     const hidl_vec<AnnouncementType>& enabled, const sp<IAnnouncementListener>& /* listener */,
     registerAnnouncementListener_cb _hidl_cb) {
-    ALOGV("%s(%s)", __func__, toString(enabled).c_str());
+    LOG(DEBUG) << "registering announcement listener for " << toString(enabled);
 
     _hidl_cb(Result::NOT_SUPPORTED, nullptr);
     return {};
diff --git a/broadcastradio/2.0/default/TunerSession.cpp b/broadcastradio/2.0/default/TunerSession.cpp
index da97562..2ba4d02 100644
--- a/broadcastradio/2.0/default/TunerSession.cpp
+++ b/broadcastradio/2.0/default/TunerSession.cpp
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "BcRadioDef.tuner"
-#define LOG_NDEBUG 0
-
 #include "TunerSession.h"
 
 #include "BroadcastRadio.h"
 
+#include <android-base/logging.h>
 #include <broadcastradio-utils-2x/Utils.h>
-#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -68,7 +65,7 @@
 }
 
 void TunerSession::tuneInternalLocked(const ProgramSelector& sel) {
-    ALOGV("%s(%s)", __func__, toString(sel).c_str());
+    LOG(VERBOSE) << "tune (internal) to " << toString(sel);
 
     VirtualProgram virtualProgram;
     ProgramInfo programInfo;
@@ -93,17 +90,18 @@
 }
 
 Return<Result> TunerSession::tune(const ProgramSelector& sel) {
-    ALOGV("%s(%s)", __func__, toString(sel).c_str());
+    LOG(DEBUG) << "tune to " << toString(sel);
+
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return Result::INVALID_STATE;
 
     if (!utils::isSupported(module().mProperties, sel)) {
-        ALOGW("Selector not supported");
+        LOG(WARNING) << "selector not supported: " << toString(sel);
         return Result::NOT_SUPPORTED;
     }
 
     if (!utils::isValid(sel)) {
-        ALOGE("ProgramSelector is not valid");
+        LOG(ERROR) << "selector is not valid: " << toString(sel);
         return Result::INVALID_ARGUMENTS;
     }
 
@@ -119,8 +117,9 @@
     return Result::OK;
 }
 
-Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) {
-    ALOGV("%s", __func__);
+Return<Result> TunerSession::scan(bool directionUp, bool skipSubChannel) {
+    LOG(DEBUG) << "seek up=" << directionUp << " skipSubChannel=" << skipSubChannel;
+
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return Result::INVALID_STATE;
 
@@ -130,8 +129,8 @@
 
     if (list.empty()) {
         mIsTuneCompleted = false;
-        auto task = [this, directionUp]() {
-            ALOGI("Performing failed seek up=%d", directionUp);
+        auto task = [this]() {
+            LOG(DEBUG) << "program list is empty, seek couldn't stop";
 
             mCallback->onTuneFailed(Result::TIMEOUT, {});
         };
@@ -162,7 +161,7 @@
 
     mIsTuneCompleted = false;
     auto task = [this, tuneTo, directionUp]() {
-        ALOGI("Performing seek up=%d", directionUp);
+        LOG(VERBOSE) << "executing seek up=" << directionUp;
 
         lock_guard<mutex> lk(mMut);
         tuneInternalLocked(tuneTo);
@@ -173,21 +172,21 @@
 }
 
 Return<Result> TunerSession::step(bool directionUp) {
-    ALOGV("%s", __func__);
+    LOG(DEBUG) << "step up=" << directionUp;
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return Result::INVALID_STATE;
 
     cancelLocked();
 
     if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) {
-        ALOGE("Can't step in anything else than AM/FM");
+        LOG(WARNING) << "can't step in anything else than AM/FM";
         return Result::NOT_SUPPORTED;
     }
 
     auto stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
     auto range = getAmFmRangeLocked();
     if (!range) {
-        ALOGE("Can't find current band");
+        LOG(ERROR) << "can't find current band";
         return Result::INTERNAL_ERROR;
     }
 
@@ -201,7 +200,7 @@
 
     mIsTuneCompleted = false;
     auto task = [this, stepTo]() {
-        ALOGI("Performing step to %s", std::to_string(stepTo).c_str());
+        LOG(VERBOSE) << "executing step to " << stepTo;
 
         lock_guard<mutex> lk(mMut);
 
@@ -213,7 +212,7 @@
 }
 
 void TunerSession::cancelLocked() {
-    ALOGV("%s", __func__);
+    LOG(VERBOSE) << "cancelling current operations...";
 
     mThread.cancelAll();
     if (utils::getType(mCurrentProgram.primaryId) != IdentifierType::INVALID) {
@@ -222,7 +221,6 @@
 }
 
 Return<void> TunerSession::cancel() {
-    ALOGV("%s", __func__);
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return {};
 
@@ -232,7 +230,7 @@
 }
 
 Return<Result> TunerSession::startProgramListUpdates(const ProgramFilter& filter) {
-    ALOGV("%s(%s)", __func__, toString(filter).c_str());
+    LOG(DEBUG) << "requested program list updates, filter=" << toString(filter);
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return Result::INVALID_STATE;
 
@@ -259,41 +257,37 @@
 }
 
 Return<void> TunerSession::stopProgramListUpdates() {
-    ALOGV("%s", __func__);
+    LOG(DEBUG) << "requested program list updates to stop";
     return {};
 }
 
 Return<void> TunerSession::isConfigFlagSet(ConfigFlag flag, isConfigFlagSet_cb _hidl_cb) {
-    ALOGV("%s(%s)", __func__, toString(flag).c_str());
+    LOG(VERBOSE) << __func__ << " " << toString(flag);
 
     _hidl_cb(Result::NOT_SUPPORTED, false);
     return {};
 }
 
 Return<Result> TunerSession::setConfigFlag(ConfigFlag flag, bool value) {
-    ALOGV("%s(%s, %d)", __func__, toString(flag).c_str(), value);
+    LOG(VERBOSE) << __func__ << " " << toString(flag) << " " << value;
 
     return Result::NOT_SUPPORTED;
 }
 
 Return<void> TunerSession::setParameters(const hidl_vec<VendorKeyValue>& /* parameters */,
                                          setParameters_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-
     _hidl_cb({});
     return {};
 }
 
 Return<void> TunerSession::getParameters(const hidl_vec<hidl_string>& /* keys */,
                                          getParameters_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-
     _hidl_cb({});
     return {};
 }
 
 Return<void> TunerSession::close() {
-    ALOGV("%s", __func__);
+    LOG(DEBUG) << "closing session...";
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return {};
 
@@ -304,7 +298,7 @@
 
 std::optional<AmFmBandRange> TunerSession::getAmFmRangeLocked() const {
     if (!mIsTuneCompleted) {
-        ALOGW("tune operation in process");
+        LOG(WARNING) << "tune operation is in process";
         return {};
     }
     if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) return {};
diff --git a/broadcastradio/2.0/default/VirtualProgram.cpp b/broadcastradio/2.0/default/VirtualProgram.cpp
index acde704..a971927 100644
--- a/broadcastradio/2.0/default/VirtualProgram.cpp
+++ b/broadcastradio/2.0/default/VirtualProgram.cpp
@@ -13,15 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "BcRadioDef.VirtualProgram"
-
 #include "VirtualProgram.h"
 
 #include "resources.h"
 
 #include <android-base/logging.h>
 #include <broadcastradio-utils-2x/Utils.h>
-#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -72,7 +69,7 @@
             info.physicallyTunedTo = selectId(IdentifierType::SXM_CHANNEL);
             break;
         default:
-            LOG(FATAL) << "Unsupported program type: " << toString(pType);
+            LOG(FATAL) << "unsupported program type: " << toString(pType);
     }
 
     info.infoFlags |= ProgramInfoFlags::TUNED;
diff --git a/broadcastradio/2.0/default/VirtualRadio.cpp b/broadcastradio/2.0/default/VirtualRadio.cpp
index f601d41..0b65979 100644
--- a/broadcastradio/2.0/default/VirtualRadio.cpp
+++ b/broadcastradio/2.0/default/VirtualRadio.cpp
@@ -13,13 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "BcRadioDef.VirtualRadio"
-//#define LOG_NDEBUG 0
-
 #include "VirtualRadio.h"
 
 #include <broadcastradio-utils-2x/Utils.h>
-#include <log/log.h>
 
 namespace android {
 namespace hardware {
diff --git a/broadcastradio/2.0/default/service.cpp b/broadcastradio/2.0/default/service.cpp
index 7e677a1..af96dad 100644
--- a/broadcastradio/2.0/default/service.cpp
+++ b/broadcastradio/2.0/default/service.cpp
@@ -13,8 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "BcRadioDef.service"
-
 #include <android-base/logging.h>
 #include <hidl/HidlTransportSupport.h>
 
@@ -26,7 +24,9 @@
 using android::hardware::broadcastradio::V2_0::implementation::BroadcastRadio;
 using android::hardware::broadcastradio::V2_0::implementation::gAmFmRadio;
 
-int main(int /* argc */, char** /* argv */) {
+int main() {
+    android::base::SetDefaultTag("BcRadioDef");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
     configureRpcThreadpool(4, true);
 
     BroadcastRadio broadcastRadio(gAmFmRadio);
diff --git a/broadcastradio/2.0/vts/functional/Android.bp b/broadcastradio/2.0/vts/functional/Android.bp
index 6940bca..3e18a54 100644
--- a/broadcastradio/2.0/vts/functional/Android.bp
+++ b/broadcastradio/2.0/vts/functional/Android.bp
@@ -28,4 +28,5 @@
         "android.hardware.broadcastradio@vts-utils-lib",
         "libgmock",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 3d7039d..c523013 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "BcRadio.vts"
-#define LOG_NDEBUG 0
 #define EGMOCK_VERBOSE 1
 
 #include <VtsHalHidlTargetTestBase.h>
@@ -446,7 +444,7 @@
     EXPECT_EQ(Result::OK, result);
     EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
 
-    ALOGD("current program info: %s", toString(infoCb).c_str());
+    LOG(DEBUG) << "current program info: " << toString(infoCb);
 
     // it should tune exactly to what was requested
     auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY);
@@ -823,11 +821,11 @@
     using android::hardware::broadcastradio::V2_0::vts::gEnv;
     using android::hardware::broadcastradio::V2_0::IBroadcastRadio;
     using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
+    android::base::SetDefaultTag("BcRadio.vts");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
     gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadio>;
     ::testing::AddGlobalTestEnvironment(gEnv);
     ::testing::InitGoogleTest(&argc, argv);
     gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
+    return RUN_ALL_TESTS();
 }
diff --git a/broadcastradio/common/tests/Android.bp b/broadcastradio/common/tests/Android.bp
index 3ba31db..ef8733c 100644
--- a/broadcastradio/common/tests/Android.bp
+++ b/broadcastradio/common/tests/Android.bp
@@ -36,6 +36,7 @@
         "android.hardware.broadcastradio@1.1",
         "android.hardware.broadcastradio@2.0",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -59,6 +60,7 @@
     shared_libs: [
         "android.hardware.broadcastradio@2.0",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -73,4 +75,5 @@
         "WorkerThread_test.cpp",
     ],
     static_libs: ["android.hardware.broadcastradio@common-utils-lib"],
+    test_suites: ["general-tests"],
 }
diff --git a/broadcastradio/common/utils/Android.bp b/broadcastradio/common/utils/Android.bp
index 33ba7da..32e06d7 100644
--- a/broadcastradio/common/utils/Android.bp
+++ b/broadcastradio/common/utils/Android.bp
@@ -29,7 +29,6 @@
     export_include_dirs: ["include"],
     shared_libs: [
         "libbase",
-        "liblog",
         "libutils",
     ],
 }
diff --git a/broadcastradio/common/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp
index bfcbb39..31f4d3f 100644
--- a/broadcastradio/common/utils/WorkerThread.cpp
+++ b/broadcastradio/common/utils/WorkerThread.cpp
@@ -14,13 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "WorkerThread"
-//#define LOG_NDEBUG 0
-
 #include <broadcastradio-utils/WorkerThread.h>
 
-#include <log/log.h>
-
 namespace android {
 
 using std::chrono::milliseconds;
@@ -39,7 +34,6 @@
 WorkerThread::WorkerThread() : mIsTerminating(false), mThread(&WorkerThread::threadLoop, this) {}
 
 WorkerThread::~WorkerThread() {
-    ALOGV("%s", __func__);
     {
         lock_guard<mutex> lk(mMut);
         mIsTerminating = true;
@@ -49,8 +43,6 @@
 }
 
 void WorkerThread::schedule(function<void()> task, milliseconds delay) {
-    ALOGV("%s", __func__);
-
     auto when = steady_clock::now() + delay;
 
     lock_guard<mutex> lk(mMut);
@@ -59,14 +51,11 @@
 }
 
 void WorkerThread::cancelAll() {
-    ALOGV("%s", __func__);
-
     lock_guard<mutex> lk(mMut);
     priority_queue<Task>().swap(mTasks);  // empty queue
 }
 
 void WorkerThread::threadLoop() {
-    ALOGV("%s", __func__);
     while (!mIsTerminating) {
         unique_lock<mutex> lk(mMut);
         if (mTasks.empty()) {
diff --git a/broadcastradio/common/utils2x/Utils.cpp b/broadcastradio/common/utils2x/Utils.cpp
index f292c08..7892653 100644
--- a/broadcastradio/common/utils2x/Utils.cpp
+++ b/broadcastradio/common/utils2x/Utils.cpp
@@ -14,12 +14,10 @@
  * limitations under the License.
  */
 #define LOG_TAG "BcRadioDef.utils"
-//#define LOG_NDEBUG 0
 
 #include <broadcastradio-utils-2x/Utils.h>
 
 #include <android-base/logging.h>
-#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -130,7 +128,7 @@
         case IdentifierType::SXM_SERVICE_ID:
             return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
         default:  // includes all vendor types
-            ALOGW("Unsupported program type: %s", toString(type).c_str());
+            LOG(WARNING) << "unsupported program type: " << toString(type);
             return false;
     }
 }
@@ -166,7 +164,7 @@
         return val;
     }
 
-    ALOGW("Identifier %s not found", toString(type).c_str());
+    LOG(WARNING) << "identifier not found: " << toString(type);
     return 0;
 }
 
@@ -205,7 +203,7 @@
     auto expect = [&valid](bool condition, std::string message) {
         if (!condition) {
             valid = false;
-            ALOGE("Identifier not valid, expected %s", message.c_str());
+            LOG(ERROR) << "identifier not valid, expected " << message;
         }
     };
 
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
index 1f716f1..f6cd6ae 100644
--- a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
@@ -29,7 +29,7 @@
  * INTERNAL IMPLEMENTATION - don't use in user code.
  */
 #if EGMOCK_VERBOSE
-#define EGMOCK_LOG_(...) ALOGV("egmock: " __VA_ARGS__)
+#define EGMOCK_LOG_(...) LOG(VERBOSE) << "egmock: " << __VA_ARGS__
 #else
 #define EGMOCK_LOG_(...)
 #endif
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index 392ebbc..9c2b02b 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -466,8 +466,8 @@
 }
 
 void CameraModule::removeCamera(int cameraId) {
-    free_camera_metadata(
-        const_cast<camera_metadata_t*>(mCameraInfoMap[cameraId].static_camera_characteristics));
+    free_camera_metadata(const_cast<camera_metadata_t*>(
+        mCameraInfoMap.valueFor(cameraId).static_camera_characteristics));
     mCameraInfoMap.removeItem(cameraId);
     mDeviceVersionMap.removeItem(cameraId);
 }
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index e7361dd..b96f574 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -48,24 +48,31 @@
 } // anonymous namespace
 
 ExternalCameraDevice::ExternalCameraDevice(
-            const std::string& cameraId, const ExternalCameraConfig& cfg) :
+        const std::string& cameraId, const ExternalCameraConfig& cfg) :
         mCameraId(cameraId),
-        mCfg(cfg) {
-
-    status_t ret = initCameraCharacteristics();
-    if (ret != OK) {
-        ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
-        mInitFailed = true;
-    }
-}
+        mCfg(cfg) {}
 
 ExternalCameraDevice::~ExternalCameraDevice() {}
 
 bool ExternalCameraDevice::isInitFailed() {
+    Mutex::Autolock _l(mLock);
+    return isInitFailedLocked();
+}
+
+bool ExternalCameraDevice::isInitFailedLocked() {
+    if (!mInitialized) {
+        status_t ret = initCameraCharacteristics();
+        if (ret != OK) {
+            ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
+            mInitFailed = true;
+        }
+        mInitialized = true;
+    }
     return mInitFailed;
 }
 
-Return<void> ExternalCameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) {
+Return<void> ExternalCameraDevice::getResourceCost(
+        ICameraDevice::getResourceCost_cb _hidl_cb) {
     CameraResourceCost resCost;
     resCost.resourceCost = 100;
     _hidl_cb(Status::OK, resCost);
@@ -73,11 +80,11 @@
 }
 
 Return<void> ExternalCameraDevice::getCameraCharacteristics(
-        getCameraCharacteristics_cb _hidl_cb) {
+        ICameraDevice::getCameraCharacteristics_cb _hidl_cb) {
     Mutex::Autolock _l(mLock);
     V3_2::CameraMetadata hidlChars;
 
-    if (isInitFailed()) {
+    if (isInitFailedLocked()) {
         _hidl_cb(Status::INTERNAL_ERROR, hidlChars);
         return Void();
     }
@@ -94,7 +101,7 @@
 }
 
 Return<void> ExternalCameraDevice::open(
-        const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) {
+        const sp<ICameraDeviceCallback>& callback, ICameraDevice::open_cb _hidl_cb) {
     Status status = Status::OK;
     sp<ExternalCameraDeviceSession> session = nullptr;
 
@@ -143,7 +150,7 @@
         }
     }
 
-    session = new ExternalCameraDeviceSession(
+    session = createSession(
             callback, mCfg, mSupportedFormats, mCroppingType,
             mCameraCharacteristics, mCameraId, std::move(fd));
     if (session == nullptr) {
@@ -479,52 +486,9 @@
     UPDATE(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys,
            ARRAY_SIZE(availableResultKeys));
 
-    const int32_t availableCharacteristicsKeys[] = {
-        ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
-        ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
-        ANDROID_CONTROL_AE_AVAILABLE_MODES,
-        ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
-        ANDROID_CONTROL_AE_COMPENSATION_RANGE,
-        ANDROID_CONTROL_AE_COMPENSATION_STEP,
-        ANDROID_CONTROL_AE_LOCK_AVAILABLE,
-        ANDROID_CONTROL_AF_AVAILABLE_MODES,
-        ANDROID_CONTROL_AVAILABLE_EFFECTS,
-        ANDROID_CONTROL_AVAILABLE_MODES,
-        ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
-        ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
-        ANDROID_CONTROL_AWB_AVAILABLE_MODES,
-        ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
-        ANDROID_CONTROL_MAX_REGIONS,
-        ANDROID_FLASH_INFO_AVAILABLE,
-        ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
-        ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
-        ANDROID_LENS_FACING,
-        ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
-        ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
-        ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
-        ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
-        ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
-        ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
-        ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
-        ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
-        ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
-        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-        ANDROID_SCALER_CROPPING_TYPE,
-        ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
-        ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
-        ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
-        ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
-        ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
-        ANDROID_SENSOR_ORIENTATION,
-        ANDROID_SHADING_AVAILABLE_MODES,
-        ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
-        ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
-        ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
-        ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
-        ANDROID_SYNC_MAX_LATENCY};
     UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
-           availableCharacteristicsKeys,
-           ARRAY_SIZE(availableCharacteristicsKeys));
+           AVAILABLE_CHARACTERISTICS_KEYS_3_4.data(),
+           AVAILABLE_CHARACTERISTICS_KEYS_3_4.size());
 
     return OK;
 }
@@ -931,6 +895,18 @@
     }
 }
 
+sp<ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+        const sp<ICameraDeviceCallback>& cb,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) {
+    return new ExternalCameraDeviceSession(
+            cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
 }  // namespace implementation
 }  // namespace V3_4
 }  // namespace device
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 653ad59..4ef5fc9 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -81,6 +81,8 @@
     return locked;
 }
 
+buffer_handle_t sEmptyBuffer = nullptr;
+
 } // Anonymous namespace
 
 // Static instances
@@ -103,11 +105,8 @@
         mCroppingType(croppingType),
         mCameraId(cameraId),
         mV4l2Fd(std::move(v4l2Fd)),
-        mOutputThread(new OutputThread(this, mCroppingType)),
         mMaxThumbResolution(getMaxThumbResolution()),
-        mMaxJpegResolution(getMaxJpegResolution()) {
-    mInitFail = initialize();
-}
+        mMaxJpegResolution(getMaxJpegResolution()) {}
 
 bool ExternalCameraDeviceSession::initialize() {
     if (mV4l2Fd.get() < 0) {
@@ -142,6 +141,12 @@
             model = card;
         }
     }
+
+    initOutputThread();
+    if (mOutputThread == nullptr) {
+        ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+        return true;
+    }
     mOutputThread->setExifMakeModel(make, model);
 
     status_t status = initDefaultRequests();
@@ -168,6 +173,32 @@
     return false;
 }
 
+bool ExternalCameraDeviceSession::isInitFailed() {
+    Mutex::Autolock _l(mLock);
+    if (!mInitialized) {
+        mInitFail = initialize();
+        mInitialized = true;
+    }
+    return mInitFail;
+}
+
+void ExternalCameraDeviceSession::initOutputThread() {
+    mOutputThread = new OutputThread(this, mCroppingType);
+}
+
+void ExternalCameraDeviceSession::closeOutputThread() {
+    closeOutputThreadImpl();
+}
+
+void ExternalCameraDeviceSession::closeOutputThreadImpl() {
+    if (mOutputThread) {
+        mOutputThread->flush();
+        mOutputThread->requestExit();
+        mOutputThread->join();
+        mOutputThread.clear();
+    }
+}
+
 Status ExternalCameraDeviceSession::initStatus() const {
     Mutex::Autolock _l(mLock);
     Status status = Status::OK;
@@ -181,7 +212,7 @@
 ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
     if (!isClosed()) {
         ALOGE("ExternalCameraDeviceSession deleted before close!");
-        close();
+        close(/*callerIsDtor*/true);
     }
 }
 
@@ -442,18 +473,23 @@
     return Status::OK;
 }
 
-Return<void> ExternalCameraDeviceSession::close() {
+Return<void> ExternalCameraDeviceSession::close(bool callerIsDtor) {
     Mutex::Autolock _il(mInterfaceLock);
     bool closed = isClosed();
     if (!closed) {
-        mOutputThread->flush();
-        mOutputThread->requestExit();
-        mOutputThread->join();
+        if (callerIsDtor) {
+            closeOutputThreadImpl();
+        } else {
+            closeOutputThread();
+        }
 
         Mutex::Autolock _l(mLock);
         // free all buffers
-        for(auto pair : mStreamMap) {
-            cleanupBuffersLocked(/*Stream ID*/pair.first);
+        {
+            Mutex::Autolock _l(mCbsLock);
+            for(auto pair : mStreamMap) {
+                cleanupBuffersLocked(/*Stream ID*/pair.first);
+            }
         }
         v4l2StreamOffLocked();
         ALOGV("%s: closing V4L2 camera FD %d", __FUNCTION__, mV4l2Fd.get());
@@ -463,10 +499,61 @@
     return Void();
 }
 
-Status ExternalCameraDeviceSession::importRequest(
+Status ExternalCameraDeviceSession::importRequestLocked(
+    const CaptureRequest& request,
+    hidl_vec<buffer_handle_t*>& allBufPtrs,
+    hidl_vec<int>& allFences) {
+    return importRequestLockedImpl(request, allBufPtrs, allFences);
+}
+
+Status ExternalCameraDeviceSession::importBuffer(int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+    Mutex::Autolock _l(mCbsLock);
+    return importBufferLocked(streamId, bufId, buf, outBufPtr, allowEmptyBuf);
+}
+
+Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+
+    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+        if (allowEmptyBuf) {
+            *outBufPtr = &sEmptyBuffer;
+            return Status::OK;
+        } else {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
+    if (cbs.count(bufId) == 0) {
+        if (buf == nullptr) {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+        // Register a newly seen buffer
+        buffer_handle_t importedBuf = buf;
+        sHandleImporter.importBuffer(importedBuf);
+        if (importedBuf == nullptr) {
+            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+            return Status::INTERNAL_ERROR;
+        } else {
+            cbs[bufId] = importedBuf;
+        }
+    }
+    *outBufPtr = &cbs[bufId];
+    return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::importRequestLockedImpl(
         const CaptureRequest& request,
         hidl_vec<buffer_handle_t*>& allBufPtrs,
-        hidl_vec<int>& allFences) {
+        hidl_vec<int>& allFences,
+        bool allowEmptyBuf) {
     size_t numOutputBufs = request.outputBuffers.size();
     size_t numBufs = numOutputBufs;
     // Validate all I/O buffers
@@ -485,26 +572,17 @@
         streamIds[i] = request.outputBuffers[i].streamId;
     }
 
-    for (size_t i = 0; i < numBufs; i++) {
-        buffer_handle_t buf = allBufs[i];
-        uint64_t bufId = allBufIds[i];
-        CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]];
-        if (cbs.count(bufId) == 0) {
-            if (buf == nullptr) {
-                ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-                return Status::ILLEGAL_ARGUMENT;
-            }
-            // Register a newly seen buffer
-            buffer_handle_t importedBuf = buf;
-            sHandleImporter.importBuffer(importedBuf);
-            if (importedBuf == nullptr) {
-                ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i);
-                return Status::INTERNAL_ERROR;
-            } else {
-                cbs[bufId] = importedBuf;
+    {
+        Mutex::Autolock _l(mCbsLock);
+        for (size_t i = 0; i < numBufs; i++) {
+            Status st = importBufferLocked(
+                    streamIds[i], allBufIds[i], allBufs[i], &allBufPtrs[i],
+                    allowEmptyBuf);
+            if (st != Status::OK) {
+                // Detailed error logs printed in importBuffer
+                return st;
             }
         }
-        allBufPtrs[i] = &cbs[bufId];
     }
 
     // All buffers are imported. Now validate output buffer acquire fences
@@ -652,7 +730,7 @@
         }
     }
 
-    status = importRequest(request, allBufPtrs, allFences);
+    status = importRequestLocked(request, allBufPtrs, allFences);
     if (status != Status::OK) {
         return status;
     }
@@ -775,9 +853,11 @@
         result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
         if (req->buffers[i].fenceTimeout) {
             result.outputBuffers[i].status = BufferStatus::ERROR;
-            native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
-            handle->data[0] = req->buffers[i].acquireFence;
-            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            if (req->buffers[i].acquireFence > 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
             notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
         } else {
             result.outputBuffers[i].status = BufferStatus::OK;
@@ -1747,6 +1827,12 @@
                 (req->frameIn->mFourcc >> 24) & 0xFF);
     }
 
+    int res = requestBufferStart(req->buffers);
+    if (res != 0) {
+        ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+        return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+    }
+
     std::unique_lock<std::mutex> lk(mBufferLock);
     // Convert input V4L2 frame to YU12 of the same size
     // TODO: see if we can save some computation by converting to YV12 here
@@ -1759,7 +1845,7 @@
 
     // TODO: in some special case maybe we can decode jpg directly to gralloc output?
     ATRACE_BEGIN("MJPGtoI420");
-    int res = libyuv::MJPGToI420(
+    res = libyuv::MJPGToI420(
             inData, inDataSize,
             static_cast<uint8_t*>(mYu12FrameLayout.y),
             mYu12FrameLayout.yStride,
@@ -1783,10 +1869,23 @@
         return true;
     }
 
+    ATRACE_BEGIN("Wait for BufferRequest done");
+    res = waitForBufferRequestDone(&req->buffers);
+    ATRACE_END();
+
+    if (res != 0) {
+        ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+        lk.unlock();
+        return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+    }
+
     ALOGV("%s processing new request", __FUNCTION__);
     const int kSyncWaitTimeoutMs = 500;
     for (auto& halBuf : req->buffers) {
-        if (halBuf.acquireFence != -1) {
+        if (*(halBuf.bufPtr) == nullptr) {
+            ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+            halBuf.fenceTimeout = true;
+        } else if (halBuf.acquireFence != -1) {
             int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
             if (ret) {
                 halBuf.fenceTimeout = true;
@@ -2045,7 +2144,7 @@
 }
 
 void ExternalCameraDeviceSession::updateBufferCaches(const hidl_vec<BufferCache>& cachesToRemove) {
-    Mutex::Autolock _l(mLock);
+    Mutex::Autolock _l(mCbsLock);
     for (auto& cache : cachesToRemove) {
         auto cbsIt = mCirculatingBuffers.find(cache.streamId);
         if (cbsIt == mCirculatingBuffers.end()) {
@@ -2499,30 +2598,33 @@
     }
 
     Mutex::Autolock _l(mLock);
-    // Add new streams
-    for (const auto& stream : config.streams) {
-        if (mStreamMap.count(stream.id) == 0) {
-            mStreamMap[stream.id] = stream;
-            mCirculatingBuffers.emplace(stream.id, CirculatingBuffers{});
-        }
-    }
-
-    // Cleanup removed streams
-    for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
-        int id = it->first;
-        bool found = false;
+    {
+        Mutex::Autolock _l(mCbsLock);
+        // Add new streams
         for (const auto& stream : config.streams) {
-            if (id == stream.id) {
-                found = true;
-                break;
+            if (mStreamMap.count(stream.id) == 0) {
+                mStreamMap[stream.id] = stream;
+                mCirculatingBuffers.emplace(stream.id, CirculatingBuffers{});
             }
         }
-        if (!found) {
-            // Unmap all buffers of deleted stream
-            cleanupBuffersLocked(id);
-            it = mStreamMap.erase(it);
-        } else {
-            ++it;
+
+        // Cleanup removed streams
+        for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+            int id = it->first;
+            bool found = false;
+            for (const auto& stream : config.streams) {
+                if (id == stream.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                // Unmap all buffers of deleted stream
+                cleanupBuffersLocked(id);
+                it = mStreamMap.erase(it);
+            } else {
+                ++it;
+            }
         }
     }
 
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 6e56596..cabeaa4 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -97,7 +97,7 @@
     // Call by CameraDevice to dump active device states
     void dumpState(const native_handle_t*);
     // Caller must use this method to check if CameraDeviceSession ctor failed
-    bool isInitFailed() { return mInitFail; }
+    bool isInitFailed();
     bool isClosed();
 
     // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
@@ -134,7 +134,7 @@
             ICameraDeviceSession::processCaptureRequest_cb);
 
     Return<Status> flush();
-    Return<void> close();
+    Return<void> close(bool callerIsDtor = false);
 
     Return<void> configureStreams_3_3(
             const V3_2::StreamConfiguration&,
@@ -170,10 +170,17 @@
         std::vector<HalStreamBuffer> buffers;
     };
 
+    static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
     Status constructDefaultRequestSettingsRaw(RequestTemplate type,
             V3_2::CameraMetadata *outMetadata);
 
     bool initialize();
+    // To init/close different version of output thread
+    virtual void initOutputThread();
+    virtual void closeOutputThread();
+    void closeOutputThreadImpl();
+
     Status initStatus() const;
     status_t initDefaultRequests();
     status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
@@ -195,10 +202,28 @@
     bool isSupported(const Stream&);
 
     // Validate and import request's output buffers and acquire fence
-    Status importRequest(
+    virtual Status importRequestLocked(
             const CaptureRequest& request,
             hidl_vec<buffer_handle_t*>& allBufPtrs,
             hidl_vec<int>& allFences);
+
+    Status importRequestLockedImpl(
+            const CaptureRequest& request,
+            hidl_vec<buffer_handle_t*>& allBufPtrs,
+            hidl_vec<int>& allFences,
+            // Optional argument for ICameraDeviceSession@3.5 impl
+            bool allowEmptyBuf = false);
+
+    Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf);
+
+    Status importBufferLocked(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf);
+
     static void cleanupInflightFences(
             hidl_vec<int>& allFences, size_t numFences);
     void cleanupBuffersLocked(int id);
@@ -224,7 +249,7 @@
     class OutputThread : public android::Thread {
     public:
         OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
-        ~OutputThread();
+        virtual ~OutputThread();
 
         Status allocateIntermediateBuffers(
                 const Size& v4lSize, const Size& thumbSize,
@@ -236,7 +261,14 @@
         virtual bool threadLoop() override;
 
         void setExifMakeModel(const std::string& make, const std::string& model);
-    private:
+
+    protected:
+        // Methods to request output buffer in parallel
+        // No-op for device@3.4. Implemented in device@3.5
+        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
+        virtual int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*) { return 0; }
+
         static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
                 static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
                 static_cast<uint32_t>('X') << 24;
@@ -319,6 +351,7 @@
     //    - init failed
     //    - camera disconnected
     bool mClosed = false;
+    bool mInitialized = false;
     bool mInitFail = false;
     bool mFirstRequest = false;
     common::V1_0::helper::CameraMetadata mLatestReqSetting;
@@ -351,6 +384,8 @@
     typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
     // Stream ID -> circulating buffers map
     std::map<int, CirculatingBuffers> mCirculatingBuffers;
+    // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+    mutable Mutex mCbsLock;
 
     std::mutex mAfTriggerLock; // protect mAfTrigger
     bool mAfTrigger = false;
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index ff0cfb3..719a3ed 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -25,6 +25,8 @@
 #include <hidl/MQDescriptor.h>
 #include "ExternalCameraDeviceSession.h"
 
+#include <vector>
+
 namespace android {
 namespace hardware {
 namespace camera {
@@ -49,7 +51,7 @@
 /*
  * The camera device HAL implementation is opened lazily (via the open call)
  */
-struct ExternalCameraDevice : public ICameraDevice {
+struct ExternalCameraDevice : public virtual RefBase {
 
     // Called by external camera provider HAL.
     // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
@@ -57,33 +59,54 @@
     // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
     // camera is detached.
     ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
-    ~ExternalCameraDevice();
+    virtual ~ExternalCameraDevice();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<ICameraDevice> getInterface() {
+        return new TrampolineDeviceInterface_3_4(this);
+    }
 
     // Caller must use this method to check if CameraDevice ctor failed
     bool isInitFailed();
+    bool isInitFailedLocked();
 
     /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */
     // The following method can be called without opening the actual camera device
-    Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
+    Return<void> getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb);
 
-    Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override;
+    Return<void> getCameraCharacteristics(
+            ICameraDevice::getCameraCharacteristics_cb _hidl_cb);
 
-    Return<Status> setTorchMode(TorchMode) override;
+    Return<Status> setTorchMode(TorchMode);
 
     // Open the device HAL and also return a default capture session
-    Return<void> open(const sp<ICameraDeviceCallback>&, open_cb) override;
+    Return<void> open(const sp<ICameraDeviceCallback>&, ICameraDevice::open_cb);
 
     // Forward the dump call to the opened session, or do nothing
-    Return<void> dumpState(const ::android::hardware::hidl_handle&) override;
+    Return<void> dumpState(const ::android::hardware::hidl_handle&);
     /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
 
 protected:
+    // Overridden by child implementations for returning different versions of
+    // ExternalCameraDeviceSession
+    virtual sp<ExternalCameraDeviceSession> createSession(
+            const sp<ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd);
+
     // Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd
     void initSupportedFormatsLocked(int fd);
 
+    // Calls into virtual member function. Do not use it in constructor
     status_t initCameraCharacteristics();
     // Init non-device dependent keys
-    status_t initDefaultCharsKeys(::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+    virtual status_t initDefaultCharsKeys(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
     // Init camera control chars keys. Caller still owns fd
     status_t initCameraControlsCharsKeys(int fd,
             ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
@@ -103,6 +126,7 @@
             /*inout*/std::vector<SupportedV4L2Format>* pFmts);
 
     Mutex mLock;
+    bool mInitialized = false;
     bool mInitFailed = false;
     std::string mCameraId;
     const ExternalCameraConfig& mCfg;
@@ -112,6 +136,84 @@
     wp<ExternalCameraDeviceSession> mSession = nullptr;
 
     ::android::hardware::camera::common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+    const std::vector<int32_t> AVAILABLE_CHARACTERISTICS_KEYS_3_4 = {
+        ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+        ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+        ANDROID_CONTROL_AE_AVAILABLE_MODES,
+        ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+        ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+        ANDROID_CONTROL_AE_COMPENSATION_STEP,
+        ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+        ANDROID_CONTROL_AF_AVAILABLE_MODES,
+        ANDROID_CONTROL_AVAILABLE_EFFECTS,
+        ANDROID_CONTROL_AVAILABLE_MODES,
+        ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+        ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+        ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+        ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+        ANDROID_CONTROL_MAX_REGIONS,
+        ANDROID_FLASH_INFO_AVAILABLE,
+        ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
+        ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+        ANDROID_LENS_FACING,
+        ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+        ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
+        ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+        ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+        ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+        ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+        ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
+        ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
+        ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+        ANDROID_SCALER_CROPPING_TYPE,
+        ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+        ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+        ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+        ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+        ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
+        ANDROID_SENSOR_ORIENTATION,
+        ANDROID_SHADING_AVAILABLE_MODES,
+        ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
+        ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
+        ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+        ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
+        ANDROID_SYNC_MAX_LATENCY};
+
+private:
+
+    struct TrampolineDeviceInterface_3_4 : public ICameraDevice {
+        TrampolineDeviceInterface_3_4(sp<ExternalCameraDevice> parent) :
+            mParent(parent) {}
+
+        virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+                override {
+            return mParent->getResourceCost(_hidl_cb);
+        }
+
+        virtual Return<void> getCameraCharacteristics(
+                V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getCameraCharacteristics(_hidl_cb);
+        }
+
+        virtual Return<Status> setTorchMode(TorchMode mode) override {
+            return mParent->setTorchMode(mode);
+        }
+
+        virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+                V3_2::ICameraDevice::open_cb _hidl_cb) override {
+            return mParent->open(callback, _hidl_cb);
+        }
+
+        virtual Return<void> dumpState(const hidl_handle& fd) override {
+            return mParent->dumpState(fd);
+        }
+
+    private:
+        sp<ExternalCameraDevice> mParent;
+    };
+
 };
 
 }  // namespace implementation
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 09cf3a4..7a48865 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -20,6 +20,12 @@
     export_include_dirs: ["include/device_v3_5_impl"]
 }
 
+cc_library_headers {
+    name: "camera.device@3.5-external-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/ext_device_v3_5_impl"]
+}
+
 cc_library_shared {
     name: "camera.device@3.5-impl",
     defaults: ["hidl_defaults"],
@@ -52,3 +58,45 @@
     ],
     local_include_dirs: ["include/device_v3_5_impl"],
 }
+
+cc_library_shared {
+    name: "camera.device@3.5-external-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "ExternalCameraDevice.cpp",
+        "ExternalCameraDeviceSession.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "camera.device@3.4-external-impl",
+        "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.graphics.mapper@2.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata",
+        "libfmq",
+        "libsync",
+        "libyuv",
+        "libjpeg",
+        "libexif",
+        "libtinyxml2"
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/ext_device_v3_5_impl"],
+    export_shared_lib_headers: [
+        "libfmq",
+    ],
+}
diff --git a/camera/device/3.5/default/ExternalCameraDevice.cpp b/camera/device/3.5/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..e8d14b5
--- /dev/null
+++ b/camera/device/3.5/default/ExternalCameraDevice.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.
+ */
+
+#define LOG_TAG "ExtCamDev@3.5"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice_3_5.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+ExternalCameraDevice::ExternalCameraDevice(
+        const std::string& cameraId, const ExternalCameraConfig& cfg) :
+        V3_4::implementation::ExternalCameraDevice(cameraId, cfg) {}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+Return<void> ExternalCameraDevice::getPhysicalCameraCharacteristics(const hidl_string&,
+        V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) {
+    CameraMetadata cameraCharacteristics;
+    // External camera HAL doesn't support physical camera functions
+    _hidl_cb(Status::ILLEGAL_ARGUMENT, cameraCharacteristics);
+    return Void();
+}
+
+sp<V3_4::implementation::ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+        const sp<V3_2::ICameraDeviceCallback>& cb,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) {
+    return new ExternalCameraDeviceSession(
+            cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+#define UPDATE(tag, data, size)                    \
+do {                                               \
+  if (metadata->update((tag), (data), (size))) {   \
+    ALOGE("Update " #tag " failed!");              \
+    return -EINVAL;                                \
+  }                                                \
+} while (0)
+
+status_t ExternalCameraDevice::initDefaultCharsKeys(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    status_t res =
+            V3_4::implementation::ExternalCameraDevice::initDefaultCharsKeys(metadata);
+
+    if (res != OK) {
+        return res;
+    }
+
+    const uint8_t bufMgrVer = ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5;
+    UPDATE(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &bufMgrVer, 1);
+
+    std::vector<int> availableCharacteristicsKeys = AVAILABLE_CHARACTERISTICS_KEYS_3_4;
+    availableCharacteristicsKeys.reserve(availableCharacteristicsKeys.size() +
+            EXTRA_CHARACTERISTICS_KEYS_3_5.size());
+    for (const auto& key : EXTRA_CHARACTERISTICS_KEYS_3_5) {
+        availableCharacteristicsKeys.push_back(key);
+    }
+    UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
+           availableCharacteristicsKeys.data(),
+           availableCharacteristicsKeys.size());
+
+    return OK;
+}
+
+#undef UPDATE
+
+}  // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..ae7c45e
--- /dev/null
+++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ExtCamDevSsn@3.5"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+        const sp<V3_2::ICameraDeviceCallback>& callback,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) :
+        V3_4::implementation::ExternalCameraDeviceSession(
+                callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
+
+    mCallback_3_5 = nullptr;
+
+    auto castResult = V3_5::ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        sp<V3_5::ICameraDeviceCallback> callback3_5 = castResult;
+        if (callback3_5 != nullptr) {
+            mCallback_3_5 = callback3_5;
+        }
+    }
+
+    if (mCallback_3_5 != nullptr) {
+        mSupportBufMgr = true;
+    }
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
+    closeOutputThreadImpl();
+}
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_5(
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb)  {
+    return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb);
+}
+
+Return<void> ExternalCameraDeviceSession::signalStreamFlush(
+        const hidl_vec<int32_t>& /*streamIds*/, uint32_t /*streamConfigCounter*/) {
+    return Void();
+}
+
+Status ExternalCameraDeviceSession::importRequestLocked(
+        const CaptureRequest& request,
+        hidl_vec<buffer_handle_t*>& allBufPtrs,
+        hidl_vec<int>& allFences) {
+    if (mSupportBufMgr) {
+        return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true);
+    }
+    return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false);
+}
+
+
+ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
+        wp<ExternalCameraDeviceSession> parent,
+        sp<V3_5::ICameraDeviceCallback> callbacks) :
+        mParent(parent),
+        mCallbacks(callbacks) {}
+
+int ExternalCameraDeviceSession::BufferRequestThread::requestBufferStart(
+        const std::vector<HalStreamBuffer>& bufReqs) {
+    if (bufReqs.empty()) {
+        ALOGE("%s: bufReqs is empty!", __FUNCTION__);
+        return -1;
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        if (mRequestingBuffer) {
+            ALOGE("%s: BufferRequestThread does not support more than one concurrent request!",
+                    __FUNCTION__);
+            return -1;
+        }
+
+        mBufferReqs = bufReqs;
+        mRequestingBuffer = true;
+    }
+    mRequestCond.notify_one();
+    return 0;
+}
+
+int ExternalCameraDeviceSession::BufferRequestThread::waitForBufferRequestDone(
+        std::vector<HalStreamBuffer>* outBufReq) {
+    std::unique_lock<std::mutex> lk(mLock);
+    if (!mRequestingBuffer) {
+        ALOGE("%s: no pending buffer request!", __FUNCTION__);
+        return -1;
+    }
+
+    if (mPendingReturnBufferReqs.empty()) {
+        std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqProcTimeoutMs);
+        auto st = mRequestDoneCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            ALOGE("%s: wait for buffer request finish timeout!", __FUNCTION__);
+            return -1;
+        }
+    }
+    mRequestingBuffer = false;
+    *outBufReq = std::move(mPendingReturnBufferReqs);
+    mPendingReturnBufferReqs.clear();
+    return 0;
+}
+
+void ExternalCameraDeviceSession::BufferRequestThread::waitForNextRequest() {
+    ATRACE_CALL();
+    std::unique_lock<std::mutex> lk(mLock);
+    int waitTimes = 0;
+    while (mBufferReqs.empty()) {
+        if (exitPending()) {
+            return;
+        }
+        std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
+        auto st = mRequestCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            waitTimes++;
+            if (waitTimes == kReqWaitTimesWarn) {
+                // BufferRequestThread just wait forever for new buffer request
+                // But it will print some periodic warning indicating it's waiting
+                ALOGV("%s: still waiting for new buffer request", __FUNCTION__);
+                waitTimes = 0;
+            }
+        }
+    }
+
+    // Fill in hidl BufferRequest
+    mHalBufferReqs.resize(mBufferReqs.size());
+    for (size_t i = 0; i < mHalBufferReqs.size(); i++) {
+        mHalBufferReqs[i].streamId = mBufferReqs[i].streamId;
+        mHalBufferReqs[i].numBuffersRequested = 1;
+    }
+}
+
+bool ExternalCameraDeviceSession::BufferRequestThread::threadLoop() {
+    waitForNextRequest();
+    if (exitPending()) {
+        return false;
+    }
+
+    ATRACE_BEGIN("HIDL requestStreamBuffers");
+    BufferRequestStatus status;
+    hidl_vec<StreamBufferRet> bufRets;
+    auto err = mCallbacks->requestStreamBuffers(mHalBufferReqs,
+            [&status, &bufRets]
+            (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) {
+                status = s;
+                bufRets = std::move(rets);
+            });
+    ATRACE_END();
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        return false;
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+    if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) {
+        if (bufRets.size() != mHalBufferReqs.size()) {
+            ALOGE("%s: expect %zu buffer requests returned, only got %zu",
+                    __FUNCTION__, mHalBufferReqs.size(), bufRets.size());
+            return false;
+        }
+
+        auto parent = mParent.promote();
+        if (parent == nullptr) {
+            ALOGE("%s: session has been disconnected!", __FUNCTION__);
+            return false;
+        }
+
+        hidl_vec<int> importedFences;
+        importedFences.resize(bufRets.size());
+        for (size_t i = 0; i < bufRets.size(); i++) {
+            int streamId = bufRets[i].streamId;
+            switch (bufRets[i].val.getDiscriminator()) {
+                case StreamBuffersVal::hidl_discriminator::error:
+                    continue;
+                case StreamBuffersVal::hidl_discriminator::buffers: {
+                    const hidl_vec<V3_2::StreamBuffer>& hBufs = bufRets[i].val.buffers();
+                    if (hBufs.size() != 1) {
+                        ALOGE("%s: expect 1 buffer returned, got %zu!", __FUNCTION__, hBufs.size());
+                        return false;
+                    }
+                    const V3_2::StreamBuffer& hBuf = hBufs[0];
+
+                    mBufferReqs[i].bufferId = hBuf.bufferId;
+                    // TODO: create a batch import API so we don't need to lock/unlock mCbsLock
+                    // repeatedly?
+                    lk.unlock();
+                    Status s = parent->importBuffer(streamId,
+                            hBuf.bufferId, hBuf.buffer.getNativeHandle(),
+                            /*out*/&mBufferReqs[i].bufPtr,
+                            /*allowEmptyBuf*/false);
+                    lk.lock();
+
+                    if (s != Status::OK) {
+                        ALOGE("%s: stream %d import buffer failed!", __FUNCTION__, streamId);
+                        cleanupInflightFences(importedFences, i - 1);
+                        return false;
+                    }
+                    if (!sHandleImporter.importFence(hBuf.acquireFence,
+                            mBufferReqs[i].acquireFence)) {
+                        ALOGE("%s: stream %d import fence failed!", __FUNCTION__, streamId);
+                        cleanupInflightFences(importedFences, i - 1);
+                        return false;
+                    }
+                    importedFences[i] = mBufferReqs[i].acquireFence;
+                }
+                break;
+                default:
+                    ALOGE("%s: unkown StreamBuffersVal discrimator!", __FUNCTION__);
+                    return false;
+            }
+        }
+    } else {
+        ALOGE("%s: requestStreamBuffers call failed!", __FUNCTION__);
+    }
+
+    mPendingReturnBufferReqs = std::move(mBufferReqs);
+    mBufferReqs.clear();
+
+    lk.unlock();
+    mRequestDoneCond.notify_one();
+    return true;
+}
+
+void ExternalCameraDeviceSession::initOutputThread() {
+    if (mSupportBufMgr) {
+        mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
+        mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
+    }
+    mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread);
+}
+
+void ExternalCameraDeviceSession::closeOutputThreadImpl() {
+    if (mBufferRequestThread) {
+        mBufferRequestThread->requestExit();
+        mBufferRequestThread->join();
+        mBufferRequestThread.clear();
+    }
+}
+
+void ExternalCameraDeviceSession::closeOutputThread() {
+    closeOutputThreadImpl();
+    V3_4::implementation::ExternalCameraDeviceSession::closeOutputThread();
+}
+
+ExternalCameraDeviceSession::OutputThread::OutputThread(
+        wp<ExternalCameraDeviceSession> parent,
+        CroppingType ct,
+        sp<BufferRequestThread> bufReqThread) :
+        V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct),
+        mBufferRequestThread(bufReqThread) {}
+
+ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
+
+int ExternalCameraDeviceSession::OutputThread::requestBufferStart(
+        const std::vector<HalStreamBuffer>& bufs) {
+    if (mBufferRequestThread != nullptr) {
+        return mBufferRequestThread->requestBufferStart(bufs);
+    }
+    return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::waitForBufferRequestDone(
+        /*out*/std::vector<HalStreamBuffer>* outBufs) {
+    if (mBufferRequestThread != nullptr) {
+        return mBufferRequestThread->waitForBufferRequestDone(outBufs);
+    }
+    return 0;
+}
+
+} // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..4d2d6b7
--- /dev/null
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
@@ -0,0 +1,256 @@
+/*
+ * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_5::BufferRequest;
+using ::android::hardware::camera::device::V3_5::BufferRequestStatus;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+
+struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession {
+
+    ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd);
+    virtual ~ExternalCameraDeviceSession();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<V3_4::ICameraDeviceSession> getInterface() override {
+        return new TrampolineSessionInterface_3_5(this);
+    }
+
+protected:
+    // Methods from v3.4 and earlier will trampoline to inherited implementation
+    Return<void> configureStreams_3_5(
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb);
+
+    Return<void> signalStreamFlush(
+            const hidl_vec<int32_t>& requests,
+            uint32_t streamConfigCounter);
+
+    virtual void initOutputThread() override;
+    virtual void closeOutputThread() override;
+    void closeOutputThreadImpl();
+
+    virtual Status importRequestLocked(
+            const CaptureRequest& request,
+            hidl_vec<buffer_handle_t*>& allBufPtrs,
+            hidl_vec<int>& allFences) override;
+
+    class BufferRequestThread : public android::Thread {
+    public:
+        BufferRequestThread(
+                wp<ExternalCameraDeviceSession> parent,
+                sp<V3_5::ICameraDeviceCallback> callbacks);
+
+        int requestBufferStart(const std::vector<HalStreamBuffer>&);
+        int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*);
+
+        virtual bool threadLoop() override;
+
+    private:
+        void waitForNextRequest();
+
+        const wp<ExternalCameraDeviceSession> mParent;
+        const sp<V3_5::ICameraDeviceCallback> mCallbacks;
+
+        std::mutex mLock;
+        bool mRequestingBuffer = false;
+
+        std::vector<HalStreamBuffer> mBufferReqs;
+        std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
+        // mHalBufferReqs is not under mLock protection during the HIDL transaction
+        hidl_vec<BufferRequest>      mHalBufferReqs;
+
+        // request buffers takes much less time in steady state, but can take much longer
+        // when requesting 1st buffer from a stream.
+        // TODO: consider a separate timeout for new vs. steady state?
+        // TODO: or make sure framework is warming up the pipeline during configure new stream?
+        static const int kReqProcTimeoutMs = 66;
+
+        static const int kReqWaitTimeoutMs = 33;
+        static const int kReqWaitTimesWarn = 90;  // 33ms * 90 ~= 3 sec
+        std::condition_variable mRequestCond;     // signaled when a new buffer request incoming
+        std::condition_variable mRequestDoneCond; // signaled when a request is done
+    };
+
+    sp<BufferRequestThread> mBufferRequestThread;
+
+    class OutputThread :
+            public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
+    public:
+        // TODO: pass buffer request thread to OutputThread ctor
+        OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType,
+                sp<BufferRequestThread> bufReqThread);
+        virtual ~OutputThread();
+
+    protected:
+        // Methods to request output buffer in parallel
+        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
+        virtual int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*) override;
+
+        const sp<BufferRequestThread> mBufferRequestThread;
+    };
+
+    sp<V3_5::ICameraDeviceCallback> mCallback_3_5;
+    bool mSupportBufMgr;
+
+private:
+
+    struct TrampolineSessionInterface_3_5 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_5(sp<ExternalCameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const V3_4::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_5(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_5_cb _hidl_cb) override {
+            return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> signalStreamFlush(
+                const hidl_vec<int32_t>& requests,
+                uint32_t streamConfigCounter) override {
+            return mParent->signalStreamFlush(requests, streamConfigCounter);
+        }
+
+    private:
+        sp<ExternalCameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h
new file mode 100644
index 0000000..7db86dc
--- /dev/null
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h
@@ -0,0 +1,131 @@
+/*
+ * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE_H
+
+#include "utils/Mutex.h"
+#include "CameraMetadata.h"
+
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include "ExternalCameraDeviceSession.h"
+#include <../../../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_5::ICameraDevice;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct ExternalCameraDevice : public V3_4::implementation::ExternalCameraDevice {
+
+    // Called by external camera provider HAL.
+    // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+    // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
+    // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
+    virtual ~ExternalCameraDevice();
+
+    virtual sp<V3_2::ICameraDevice> getInterface() override {
+        return new TrampolineDeviceInterface_3_5(this);
+    }
+
+    Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+            V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb);
+
+protected:
+    virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession(
+            const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd) override;
+
+    virtual status_t initDefaultCharsKeys(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override;
+
+    const std::vector<int32_t> EXTRA_CHARACTERISTICS_KEYS_3_5 = {
+        ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION
+    };
+
+private:
+    struct TrampolineDeviceInterface_3_5 : public ICameraDevice {
+        TrampolineDeviceInterface_3_5(sp<ExternalCameraDevice> parent) :
+            mParent(parent) {}
+
+        virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+                override {
+            return mParent->getResourceCost(_hidl_cb);
+        }
+
+        virtual Return<void> getCameraCharacteristics(
+                V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getCameraCharacteristics(_hidl_cb);
+        }
+
+        virtual Return<Status> setTorchMode(TorchMode mode) override {
+            return mParent->setTorchMode(mode);
+        }
+
+        virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+                V3_2::ICameraDevice::open_cb _hidl_cb) override {
+            return mParent->open(callback, _hidl_cb);
+        }
+
+        virtual Return<void> dumpState(const hidl_handle& fd) override {
+            return mParent->dumpState(fd);
+        }
+
+        virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+                V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
+        }
+    private:
+        sp<ExternalCameraDevice> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE_H
diff --git a/camera/metadata/3.4/types.hal b/camera/metadata/3.4/types.hal
index 4eb6929..61a399e 100644
--- a/camera/metadata/3.4/types.hal
+++ b/camera/metadata/3.4/types.hal
@@ -113,6 +113,15 @@
                                                                  = 0x18,
 };
 
+/** android.sensor.info.colorFilterArrangement enumeration values added since v3.2
+ * @see ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+ */
+enum CameraMetadataEnumAndroidSensorInfoColorFilterArrangement :
+        @3.2::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement {
+    ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO,
+    ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR,
+};
+
 /** android.info.supportedBufferManagementVersion enumeration values
  * @see ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION
  */
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index de02d78..167954c 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -21,6 +21,7 @@
         "camera.device@3.4-impl",
         "camera.device@3.5-impl",
         "camera.device@3.4-external-impl",
+        "camera.device@3.5-external-impl",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
         "android.hardware.graphics.mapper@2.0",
@@ -34,7 +35,8 @@
     header_libs: [
         "camera.device@3.4-impl_headers",
         "camera.device@3.5-impl_headers",
-        "camera.device@3.4-external-impl_headers"
+        "camera.device@3.4-external-impl_headers",
+        "camera.device@3.5-external-impl_headers"
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
@@ -107,6 +109,8 @@
         "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.common@1.0",
     ],
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProvider.cpp
index 1cec0e5..604df5c 100644
--- a/camera/provider/2.4/default/ExternalCameraProvider.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProvider.cpp
@@ -24,6 +24,8 @@
 #include <linux/videodev2.h>
 #include "ExternalCameraProvider.h"
 #include "ExternalCameraDevice_3_4.h"
+#include "ExternalCameraDevice_3_5.h"
+#include <cutils/properties.h>
 
 namespace android {
 namespace hardware {
@@ -62,6 +64,21 @@
         mCfg(ExternalCameraConfig::loadFromCfg()),
         mHotPlugThread(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:
+            // OK
+            break;
+        default:
+            ALOGW("Unknown minor camera device HAL version %d in property "
+                    "'camera.external.hal3TrebleMinorVersion', defaulting to 4",
+                    mPreferredHal3MinorVersion);
+            mPreferredHal3MinorVersion = 4;
+    }
 }
 
 ExternalCameraProvider::~ExternalCameraProvider() {
@@ -136,20 +153,43 @@
         return Void();
     }
 
-    ALOGV("Constructing v3.4 external camera device");
-    sp<device::V3_2::ICameraDevice> device;
-    sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
-            new device::V3_4::implementation::ExternalCameraDevice(
+    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(
                     cameraId, mCfg);
+            break;
+        }
+        case 5: {
+            ALOGV("Constructing v3.5 external camera device");
+            deviceImpl = new device::V3_5::implementation::ExternalCameraDevice(
+                    cameraId, 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__, cameraId.c_str());
-        device = nullptr;
         _hidl_cb(Status::INTERNAL_ERROR, nullptr);
         return Void();
     }
-    device = deviceImpl;
 
-    _hidl_cb (Status::OK, device);
+    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();
 }
@@ -157,7 +197,12 @@
 void ExternalCameraProvider::addExternalCamera(const char* devName) {
     ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
     Mutex::Autolock _l(mLock);
-    std::string deviceName = std::string("device@3.4/external/") + devName;
+    std::string deviceName;
+    if (mPreferredHal3MinorVersion == 5) {
+        deviceName = std::string("device@3.5/external/") + devName;
+    } else {
+        deviceName = std::string("device@3.4/external/") + devName;
+    }
     mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
     if (mCallbacks != nullptr) {
         mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
@@ -199,7 +244,12 @@
 
 void ExternalCameraProvider::deviceRemoved(const char* devName) {
     Mutex::Autolock _l(mLock);
-    std::string deviceName = std::string("device@3.4/external/") + devName;
+    std::string deviceName;
+    if (mPreferredHal3MinorVersion == 5) {
+        deviceName = std::string("device@3.5/external/") + devName;
+    } else {
+        deviceName = std::string("device@3.4/external/") + devName;
+    }
     if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
         mCameraStatusMap.erase(deviceName);
         if (mCallbacks != nullptr) {
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.h b/camera/provider/2.4/default/ExternalCameraProvider.h
index c83cc70..a69cf8b 100644
--- a/camera/provider/2.4/default/ExternalCameraProvider.h
+++ b/camera/provider/2.4/default/ExternalCameraProvider.h
@@ -95,6 +95,7 @@
     std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
     const ExternalCameraConfig mCfg;
     HotplugThread mHotPlugThread;
+    int mPreferredHal3MinorVersion;
 };
 
 
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index eb8d43e..f8f058e 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -38,6 +38,7 @@
         "android.hardware.camera.device@3.3",
         "android.hardware.camera.device@3.4",
         "android.hardware.camera.device@3.5",
+	"android.hardware.camera.metadata@3.4",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.common@1.0",
@@ -46,4 +47,5 @@
         "libgrallocusage",
         "libhidlmemory",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 837905c..bb03d91 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -31,8 +31,11 @@
 #include <android/hardware/camera/device/3.5/ICameraDevice.h>
 #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/metadata/3.4/types.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
 #include <CameraMetadata.h>
@@ -110,6 +113,7 @@
 using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback;
 using ::android::hardware::camera::device::V1_0::FrameCallbackFlag;
 using ::android::hardware::camera::device::V1_0::HandleTimestampMessage;
+using ::android::hardware::camera::metadata::V3_4::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
 using ::android::hardware::MessageQueue;
 using ::android::hardware::kSynchronizedReadWrite;
 using ::android::hidl::allocator::V1_0::IAllocator;
@@ -130,6 +134,7 @@
 const int64_t kEmptyFlushTimeoutMSec = 200;
 const char kDumpOutput[] = "/dev/null";
 const uint32_t kBurstFrameCount = 10;
+const int64_t kBufferReturnTimeoutSec = 1;
 
 struct AvailableStream {
     int32_t width;
@@ -142,6 +147,11 @@
     int32_t outputFormat;
 };
 
+enum ReprocessType {
+    PRIV_REPROCESS,
+    YUV_REPROCESS,
+};
+
 namespace {
     // "device@<version>/legacy/<id>"
     const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
@@ -536,7 +546,7 @@
 
  hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider);
 
- struct EmptyDeviceCb : public V3_4::ICameraDeviceCallback {
+    struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback {
      virtual Return<void> processCaptureResult(
          const hidl_vec<CaptureResult>& /*results*/) override {
          ALOGI("processCaptureResult callback");
@@ -556,19 +566,63 @@
          ADD_FAILURE();  // Empty callback should not reach here
          return Void();
      }
+
+     virtual Return<void> requestStreamBuffers(
+             const hidl_vec<V3_5::BufferRequest>&,
+             requestStreamBuffers_cb _hidl_cb) override {
+         ALOGI("requestStreamBuffers callback");
+         // HAL might want to request buffer after configureStreams, but tests with EmptyDeviceCb
+         // doesn't actually need to send capture requests, so just return an error.
+         hidl_vec<V3_5::StreamBufferRet> emptyBufRets;
+         _hidl_cb(V3_5::BufferRequestStatus::FAILED_UNKNOWN, emptyBufRets);
+         return Void();
+     }
+
+     virtual Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>&) override {
+         ALOGI("returnStreamBuffers");
+         ADD_FAILURE();  // Empty callback should not reach here
+         return Void();
+     }
+
     };
 
-    struct DeviceCb : public V3_4::ICameraDeviceCallback {
-        DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+    struct DeviceCb : public V3_5::ICameraDeviceCallback {
+        DeviceCb(CameraHidlTest *parent, bool checkMonochromeResult) : mParent(parent),
+                mCheckMonochromeResult(checkMonochromeResult) {}
+
         Return<void> processCaptureResult_3_4(
                 const hidl_vec<V3_4::CaptureResult>& results) override;
         Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
         Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
 
+        Return<void> requestStreamBuffers(
+                const hidl_vec<V3_5::BufferRequest>& bufReqs,
+                requestStreamBuffers_cb _hidl_cb) override;
+
+        Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>& buffers) override;
+
+        void setCurrentStreamConfig(const hidl_vec<V3_2::Stream>& streams,
+                const hidl_vec<V3_2::HalStream>& halStreams);
+
+        void waitForBuffersReturned();
+
      private:
         bool processCaptureResultLocked(const CaptureResult& results);
 
-        CameraHidlTest *mParent;               // Parent object
+        CameraHidlTest *mParent; // Parent object
+        bool mCheckMonochromeResult;
+        bool hasOutstandingBuffersLocked();
+
+        /* members for requestStreamBuffers() and returnStreamBuffers()*/
+        std::mutex mLock; // protecting members below
+        bool                      mUseHalBufManager = false;
+        hidl_vec<V3_2::Stream>    mStreams;
+        hidl_vec<V3_2::HalStream> mHalStreams;
+        uint64_t mNextBufferId = 1;
+        using OutstandingBuffers = std::unordered_map<uint64_t, hidl_handle>;
+        // size == mStreams.size(). Tracking each streams outstanding buffers
+        std::vector<OutstandingBuffers> mOutstandingBufferIds;
+        std::condition_variable mFlushedCondition;
     };
 
     struct TorchProviderCb : public ICameraProviderCallback {
@@ -652,21 +706,27 @@
             camera_metadata_t **staticMeta /*out*/);
     void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
             sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
-            sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/);
+            sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+            sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/);
     void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
             StreamConfigurationMode configMode,
             ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2,
-            ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4);
+            ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4,
+            ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5);
 
     void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
             const std::unordered_set<std::string>& physicalIds,
             sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+            sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
             V3_2::Stream* previewStream /*out*/,
             device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
             bool *supportsPartialResults /*out*/,
-            uint32_t *partialResultCount /*out*/);
+            uint32_t *partialResultCount /*out*/,
+            bool *useHalBufManager /*out*/,
+            sp<DeviceCb> *cb /*out*/,
+            uint32_t streamConfigCounter = 0);
     void configurePreviewStream(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
@@ -674,7 +734,10 @@
             V3_2::Stream *previewStream /*out*/,
             HalStreamConfiguration *halStreamConfig /*out*/,
             bool *supportsPartialResults /*out*/,
-            uint32_t *partialResultCount /*out*/);
+            uint32_t *partialResultCount /*out*/,
+            bool *useHalBufManager /*out*/,
+            sp<DeviceCb> *cb /*out*/,
+            uint32_t streamConfigCounter = 0);
 
     void verifyLogicalCameraMetadata(const std::string& cameraName,
             const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device,
@@ -682,6 +745,17 @@
             const hidl_vec<hidl_string>& deviceNames);
     void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
     void verifyRecommendedConfigs(const CameraMetadata& metadata);
+    void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
+    void verifyMonochromeCameraResult(
+            const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata);
+
+    void verifyBuffersReturned(sp<device::V3_2::ICameraDeviceSession> session,
+            int deviceVerison, int32_t streamId, sp<DeviceCb> cb,
+            uint32_t streamConfigCounter = 0);
+
+    void verifyBuffersReturned(sp<device::V3_4::ICameraDeviceSession> session,
+            hidl_vec<int32_t> streamIds, sp<DeviceCb> cb,
+            uint32_t streamConfigCounter = 0);
 
     static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
             std::vector<AvailableStream> &outputStreams,
@@ -700,6 +774,7 @@
     static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
             AvailableStream &hfrStream);
     static Status isZSLModeAvailable(const camera_metadata_t *staticMeta);
+    static Status isZSLModeAvailable(const camera_metadata_t *staticMeta, ReprocessType reprocType);
     static Status getZSLInputOutputMap(camera_metadata_t *staticMeta,
             std::vector<AvailableZSLInputOutput> &inputOutputMap);
     static Status findLargestSize(
@@ -707,6 +782,7 @@
             int32_t format, AvailableStream &result);
     static Status isAutoFocusModeAvailable(
             CameraParameters &cameraParams, const char *mode) ;
+    static Status isMonochromeCamera(const camera_metadata_t *staticMeta);
 
 protected:
 
@@ -1050,6 +1126,11 @@
         }
         request->haveResultMetadata = true;
         request->collectedResult.sort();
+
+        // Verify final result metadata
+        if (mCheckMonochromeResult) {
+            mParent->verifyMonochromeCameraResult(request->collectedResult);
+        }
     }
 
     uint32_t numBuffersReturned = results.outputBuffers.size();
@@ -1075,9 +1156,51 @@
     if (request->shutterTimestamp != 0) {
         notify = true;
     }
+
+    if (mUseHalBufManager) {
+        returnStreamBuffers(results.outputBuffers);
+    }
     return notify;
 }
 
+void CameraHidlTest::DeviceCb::setCurrentStreamConfig(
+        const hidl_vec<V3_2::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) {
+    ASSERT_EQ(streams.size(), halStreams.size());
+    ASSERT_NE(streams.size(), 0);
+    for (size_t i = 0; i < streams.size(); i++) {
+        ASSERT_EQ(streams[i].id, halStreams[i].id);
+    }
+    std::lock_guard<std::mutex> l(mLock);
+    mUseHalBufManager = true;
+    mStreams = streams;
+    mHalStreams = halStreams;
+    mOutstandingBufferIds.clear();
+    for (size_t i = 0; i < streams.size(); i++) {
+        mOutstandingBufferIds.emplace_back();
+    }
+}
+
+bool CameraHidlTest::DeviceCb::hasOutstandingBuffersLocked() {
+    if (!mUseHalBufManager) {
+        return false;
+    }
+    for (const auto& outstandingBuffers : mOutstandingBufferIds) {
+        if (!outstandingBuffers.empty()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void CameraHidlTest::DeviceCb::waitForBuffersReturned() {
+    std::unique_lock<std::mutex> lk(mLock);
+    if (hasOutstandingBuffersLocked()) {
+        auto timeout = std::chrono::seconds(kBufferReturnTimeoutSec);
+        auto st = mFlushedCondition.wait_for(lk, timeout);
+        ASSERT_NE(std::cv_status::timeout, st);
+    }
+}
+
 Return<void> CameraHidlTest::DeviceCb::notify(
         const hidl_vec<NotifyMsg>& messages) {
     std::lock_guard<std::mutex> l(mParent->mLock);
@@ -1120,6 +1243,124 @@
     return Void();
 }
 
+Return<void> CameraHidlTest::DeviceCb::requestStreamBuffers(
+        const hidl_vec<V3_5::BufferRequest>& bufReqs,
+        requestStreamBuffers_cb _hidl_cb) {
+    using V3_5::BufferRequestStatus;
+    using V3_5::StreamBufferRet;
+    using V3_5::StreamBufferRequestError;
+    hidl_vec<StreamBufferRet> bufRets;
+    std::unique_lock<std::mutex> l(mLock);
+
+    if (!mUseHalBufManager) {
+        ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__);
+        ADD_FAILURE();
+        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+        return Void();
+    }
+
+    if (bufReqs.size() > mStreams.size()) {
+        ALOGE("%s: illegal buffer request: too many requests!", __FUNCTION__);
+        ADD_FAILURE();
+        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+        return Void();
+    }
+
+    std::vector<int32_t> indexes(bufReqs.size());
+    for (size_t i = 0; i < bufReqs.size(); i++) {
+        bool found = false;
+        for (size_t idx = 0; idx < mStreams.size(); idx++) {
+            if (bufReqs[i].streamId == mStreams[idx].id) {
+                found = true;
+                indexes[i] = idx;
+                break;
+            }
+        }
+        if (!found) {
+            ALOGE("%s: illegal buffer request: unknown streamId %d!",
+                    __FUNCTION__, bufReqs[i].streamId);
+            ADD_FAILURE();
+            _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+            return Void();
+        }
+    }
+
+    bool allStreamOk = true;
+    bool atLeastOneStreamOk = false;
+    bufRets.resize(bufReqs.size());
+    for (size_t i = 0; i < bufReqs.size(); i++) {
+        int32_t idx = indexes[i];
+        const auto& stream = mStreams[idx];
+        const auto& halStream = mHalStreams[idx];
+        const V3_5::BufferRequest& bufReq = bufReqs[i];
+        if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) {
+            bufRets[i].streamId = stream.id;
+            bufRets[i].val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
+            allStreamOk = false;
+            continue;
+        }
+
+        hidl_vec<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested);
+        for (size_t i = 0; i < bufReq.numBuffersRequested; i++) {
+            hidl_handle buffer_handle;
+            mParent->allocateGraphicBuffer(stream.width, stream.height,
+                    android_convertGralloc1To0Usage(
+                            halStream.producerUsage, halStream.consumerUsage),
+                    halStream.overrideFormat, &buffer_handle);
+
+            tmpRetBuffers[i] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK,
+                                nullptr, nullptr};
+            mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle));
+        }
+        atLeastOneStreamOk = true;
+        bufRets[0].val.buffers(std::move(tmpRetBuffers));
+    }
+
+    if (allStreamOk) {
+        _hidl_cb(BufferRequestStatus::OK, bufRets);
+    } else if (atLeastOneStreamOk) {
+        _hidl_cb(BufferRequestStatus::FAILED_PARTIAL, bufRets);
+    } else {
+        _hidl_cb(BufferRequestStatus::FAILED_UNKNOWN, bufRets);
+    }
+
+    if (!hasOutstandingBuffersLocked()) {
+        l.unlock();
+        mFlushedCondition.notify_one();
+    }
+    return Void();
+}
+
+Return<void> CameraHidlTest::DeviceCb::returnStreamBuffers(
+        const hidl_vec<StreamBuffer>& buffers) {
+    if (!mUseHalBufManager) {
+        ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__);
+        ADD_FAILURE();
+    }
+
+    std::lock_guard<std::mutex> l(mLock);
+    for (const auto& buf : buffers) {
+        bool found = false;
+        for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) {
+            if (mStreams[idx].id == buf.streamId &&
+                    mOutstandingBufferIds[idx].count(buf.bufferId) == 1) {
+                mOutstandingBufferIds[idx].erase(buf.bufferId);
+                // TODO: check do we need to close/delete native handle or assume we have enough
+                // memory to run till the test finish? since we do not capture much requests (and
+                // most of time one buffer is sufficient)
+                found = true;
+                break;
+            }
+        }
+        if (found) {
+            continue;
+        }
+        ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId);
+        ADD_FAILURE();
+    }
+    return Void();
+}
+
 hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> provider) {
     std::vector<std::string> cameraDeviceNames;
     Return<void> ret;
@@ -2080,6 +2321,7 @@
 
                 ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
                     verifyCameraCharacteristics(status, chars);
+                    verifyMonochromeCharacteristics(chars, deviceVersion);
                     verifyRecommendedConfigs(chars);
                     verifyLogicalCameraMetadata(name, device3_x, chars, deviceVersion,
                             cameraDeviceNames);
@@ -2359,14 +2601,18 @@
                 // cast the 3.3/3.4 interface, and that lower versions can't be cast to it.
                 sp<device::V3_3::ICameraDeviceSession> sessionV3_3;
                 sp<device::V3_4::ICameraDeviceSession> sessionV3_4;
-                castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4);
-                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4 ||
-                        deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+                sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
+                castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5);
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+                    ASSERT_TRUE(sessionV3_5.get() != nullptr);
+                } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
                     ASSERT_TRUE(sessionV3_4.get() != nullptr);
                 } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
                     ASSERT_TRUE(sessionV3_3.get() != nullptr);
-                } else {
+                } else { //V3_2
                     ASSERT_TRUE(sessionV3_3.get() == nullptr);
+                    ASSERT_TRUE(sessionV3_4.get() == nullptr);
+                    ASSERT_TRUE(sessionV3_5.get() == nullptr);
                 }
                 native_handle_t* raw_handle = native_handle_create(1, 0);
                 raw_handle->data[0] = open(kDumpOutput, O_RDWR);
@@ -2522,15 +2768,17 @@
         sp<ICameraDeviceSession> session;
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
         openEmptyDeviceSession(name, mProvider,
                 &session /*out*/, &staticMeta /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
         ASSERT_NE(0u, outputStreams.size());
 
         int32_t streamId = 0;
+        uint32_t streamConfigCounter = 0;
         for (auto& it : outputStreams) {
             V3_2::Stream stream3_2;
             bool isJpeg = static_cast<PixelFormat>(it.format) == PixelFormat::BLOB;
@@ -2543,11 +2791,20 @@
                              (isJpeg) ? static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF) : 0,
                              StreamRotation::ROTATION_0};
             ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
+            ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
             ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
             ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
             createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
-                                      &config3_2, &config3_4);
-            if (session3_4 != nullptr) {
+                                      &config3_2, &config3_4, &config3_5);
+            if (session3_5 != nullptr) {
+                config3_5.streamConfigCounter = streamConfigCounter++;
+                ret = session3_5->configureStreams_3_5(config3_5,
+                        [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(1u, halConfig.streams.size());
+                            ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId);
+                        });
+            } else if (session3_4 != nullptr) {
                 ret = session3_4->configureStreams_3_4(config3_4,
                         [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                             ASSERT_EQ(Status::OK, s);
@@ -2599,8 +2856,9 @@
         sp<ICameraDeviceSession> session;
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -2615,29 +2873,38 @@
                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                          0,
                          StreamRotation::ROTATION_0};
+        uint32_t streamConfigCounter = 0;
         ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream3_2};
+        ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
         ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
         ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
         createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
-                                  &config3_2, &config3_4);
-        if(session3_4 != nullptr) {
-            ret = session3_4->configureStreams_3_4(config3_4,
-                [](Status s, device::V3_4::HalStreamConfiguration) {
-                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                  &config3_2, &config3_4, &config3_5);
+        if (session3_5 != nullptr) {
+            config3_5.streamConfigCounter = streamConfigCounter++;
+            ret = session3_5->configureStreams_3_5(config3_5,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
                             (Status::INTERNAL_ERROR == s));
-                });
+                    });
+        } else if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
         } else if(session3_3 != nullptr) {
             ret = session3_3->configureStreams_3_3(config3_2,
-                [](Status s, device::V3_3::HalStreamConfiguration) {
-                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                            (Status::INTERNAL_ERROR == s));
-                });
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
         } else {
             ret = session->configureStreams(config3_2,
-                [](Status s, HalStreamConfiguration) {
-                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                            (Status::INTERNAL_ERROR == s));
-                });
+                    [](Status s, HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
         }
         ASSERT_TRUE(ret.isOk());
 
@@ -2651,8 +2918,14 @@
                   StreamRotation::ROTATION_0};
         streams[0] = stream3_2;
         createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
-                &config3_2, &config3_4);
-        if(session3_4 != nullptr) {
+                &config3_2, &config3_4, &config3_5);
+        if (session3_5 != nullptr) {
+            config3_5.streamConfigCounter = streamConfigCounter++;
+            ret = session3_5->configureStreams_3_5(config3_5, [](Status s,
+                        device::V3_4::HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+        } else if(session3_4 != nullptr) {
             ret = session3_4->configureStreams_3_4(config3_4, [](Status s,
                         device::V3_4::HalStreamConfiguration) {
                     ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
@@ -2681,8 +2954,14 @@
                       StreamRotation::ROTATION_0};
             streams[0] = stream3_2;
             createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
-                    &config3_2, &config3_4);
-            if(session3_4 != nullptr) {
+                    &config3_2, &config3_4, &config3_5);
+            if (session3_5 != nullptr) {
+                config3_5.streamConfigCounter = streamConfigCounter++;
+                ret = session3_5->configureStreams_3_5(config3_5,
+                        [](Status s, device::V3_4::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else if(session3_4 != nullptr) {
                 ret = session3_4->configureStreams_3_4(config3_4,
                         [](Status s, device::V3_4::HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
@@ -2710,8 +2989,14 @@
                       static_cast<StreamRotation>(UINT32_MAX)};
             streams[0] = stream3_2;
             createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
-                    &config3_2, &config3_4);
-            if(session3_4 != nullptr) {
+                    &config3_2, &config3_4, &config3_5);
+            if (session3_5 != nullptr) {
+                config3_5.streamConfigCounter = streamConfigCounter++;
+                ret = session3_5->configureStreams_3_5(config3_5,
+                        [](Status s, device::V3_4::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else if(session3_4 != nullptr) {
                 ret = session3_4->configureStreams_3_4(config3_4,
                         [](Status s, device::V3_4::HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
@@ -2758,8 +3043,9 @@
         sp<ICameraDeviceSession> session;
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
 
         Status rc = isZSLModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -2777,13 +3063,35 @@
         ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap));
         ASSERT_NE(0u, inputOutputMap.size());
 
+        bool supportMonoY8 = false;
+        if (Status::OK == isMonochromeCamera(staticMeta)) {
+            for (auto& it : inputStreams) {
+                if (it.format == static_cast<uint32_t>(PixelFormat::Y8)) {
+                    supportMonoY8 = true;
+                    break;
+                }
+            }
+        }
+
         int32_t streamId = 0;
+        bool hasPrivToY8 = false, hasY8ToY8 = false, hasY8ToBlob = false;
+        uint32_t streamConfigCounter = 0;
         for (auto& inputIter : inputOutputMap) {
             AvailableStream input;
             ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat,
                     input));
             ASSERT_NE(0u, inputStreams.size());
 
+            if (inputIter.inputFormat == static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED)
+                    && inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+                hasPrivToY8 = true;
+            } else if (inputIter.inputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+                if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::BLOB)) {
+                    hasY8ToBlob = true;
+                } else if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+                    hasY8ToY8 = true;
+                }
+            }
             AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
                                                inputIter.outputFormat};
             std::vector<AvailableStream> outputStreams;
@@ -2818,11 +3126,19 @@
 
                 ::android::hardware::hidl_vec<V3_2::Stream> streams = {inputStream, zslStream,
                                                                  outputStream};
+                ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
                 ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
                 ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
-                                          &config3_2, &config3_4);
-                if (session3_4 != nullptr) {
+                                          &config3_2, &config3_4, &config3_5);
+                if (session3_5 != nullptr) {
+                    config3_5.streamConfigCounter = streamConfigCounter++;
+                    ret = session3_5->configureStreams_3_5(config3_5,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(3u, halConfig.streams.size());
+                            });
+                } else if (session3_4 != nullptr) {
                     ret = session3_4->configureStreams_3_4(config3_4,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
@@ -2845,6 +3161,16 @@
             }
         }
 
+        if (supportMonoY8) {
+            if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) {
+                ASSERT_TRUE(hasPrivToY8);
+            }
+            if (Status::OK == isZSLModeAvailable(staticMeta, YUV_REPROCESS)) {
+                ASSERT_TRUE(hasY8ToY8);
+                ASSERT_TRUE(hasY8ToBlob);
+            }
+        }
+
         free_camera_metadata(staticMeta);
         ret = session->close();
         ASSERT_TRUE(ret.isOk());
@@ -2874,9 +3200,14 @@
         sp<ICameraDeviceSession> session;
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4);
-        ASSERT_NE(session3_4, nullptr);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
+            ASSERT_NE(session3_4, nullptr);
+        } else {
+            ASSERT_NE(session3_5, nullptr);
+        }
 
         std::unordered_set<int32_t> availableSessionKeys;
         auto rc = getSupportedKeys(staticMetaBuffer, ANDROID_REQUEST_AVAILABLE_SESSION_KEYS,
@@ -2915,17 +3246,29 @@
                                 StreamRotation::ROTATION_0};
         ::android::hardware::hidl_vec<V3_4::Stream> streams = {previewStream};
         ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+        ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
         config.streams = streams;
         config.operationMode = StreamConfigurationMode::NORMAL_MODE;
         const camera_metadata_t *sessionParamsBuffer = sessionParams.getAndLock();
         config.sessionParams.setToExternal(
                 reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (sessionParamsBuffer)),
                 get_camera_metadata_size(sessionParamsBuffer));
-        ret = session3_4->configureStreams_3_4(config,
-                [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
-                    ASSERT_EQ(Status::OK, s);
-                    ASSERT_EQ(1u, halConfig.streams.size());
-                });
+        config3_5.v3_4 = config;
+        config3_5.streamConfigCounter = 0;
+        if (session3_5 != nullptr) {
+            ret = session3_5->configureStreams_3_5(config3_5,
+                    [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                    });
+        } else {
+            ret = session3_4->configureStreams_3_4(config,
+                    [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                    });
+        }
+
         ASSERT_TRUE(ret.isOk());
 
         free_camera_metadata(staticMetaBuffer);
@@ -2960,8 +3303,9 @@
         sp<ICameraDeviceSession> session;
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
 
         outputBlobStreams.clear();
         ASSERT_EQ(Status::OK,
@@ -2975,6 +3319,7 @@
         ASSERT_NE(0u, outputPreviewStreams.size());
 
         int32_t streamId = 0;
+        uint32_t streamConfigCounter = 0;
         for (auto& blobIter : outputBlobStreams) {
             for (auto& previewIter : outputPreviewStreams) {
                 V3_2::Stream previewStream = {streamId++,
@@ -2995,11 +3340,19 @@
                                      StreamRotation::ROTATION_0};
                 ::android::hardware::hidl_vec<V3_2::Stream> streams = {previewStream,
                                                                  blobStream};
+                ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
                 ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
                 ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
-                                          &config3_2, &config3_4);
-                if (session3_4 != nullptr) {
+                                          &config3_2, &config3_4, &config3_5);
+                if (session3_5 != nullptr) {
+                    config3_5.streamConfigCounter = streamConfigCounter++;
+                    ret = session3_5->configureStreams_3_5(config3_5,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else if (session3_4 != nullptr) {
                     ret = session3_4->configureStreams_3_4(config3_4,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
@@ -3049,8 +3402,9 @@
         sp<ICameraDeviceSession> session;
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
 
         Status rc = isConstrainedModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -3065,6 +3419,7 @@
         ASSERT_EQ(Status::OK, rc);
 
         int32_t streamId = 0;
+        uint32_t streamConfigCounter = 0;
         V3_2::Stream stream = {streamId,
                          StreamType::OUTPUT,
                          static_cast<uint32_t>(hfrStream.width),
@@ -3074,11 +3429,20 @@
                          0,
                          StreamRotation::ROTATION_0};
         ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream};
+        ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
         ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
         ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
         createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
-                                  &config3_2, &config3_4);
-        if (session3_4 != nullptr) {
+                                  &config3_2, &config3_4, &config3_5);
+        if (session3_5 != nullptr) {
+            config3_5.streamConfigCounter = streamConfigCounter++;
+            ret = session3_5->configureStreams_3_5(config3_5,
+                    [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId);
+                    });
+        } else if (session3_4 != nullptr) {
             ret = session3_4->configureStreams_3_4(config3_4,
                     [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                         ASSERT_EQ(Status::OK, s);
@@ -3112,8 +3476,15 @@
                   StreamRotation::ROTATION_0};
         streams[0] = stream;
         createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
-                                  &config3_2, &config3_4);
-        if (session3_4 != nullptr) {
+                                  &config3_2, &config3_4, &config3_5);
+        if (session3_5 != nullptr) {
+            config3_5.streamConfigCounter = streamConfigCounter++;
+            ret = session3_5->configureStreams_3_5(config3_5,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
+        } else if (session3_4 != nullptr) {
             ret = session3_4->configureStreams_3_4(config3_4,
                     [](Status s, device::V3_4::HalStreamConfiguration) {
                         ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
@@ -3144,8 +3515,14 @@
                   StreamRotation::ROTATION_0};
         streams[0] = stream;
         createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
-                                  &config3_2, &config3_4);
-        if (session3_4 != nullptr) {
+                                  &config3_2, &config3_4, &config3_5);
+        if (session3_5 != nullptr) {
+            config3_5.streamConfigCounter = streamConfigCounter++;
+            ret = session3_5->configureStreams_3_5(config3_5,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else if (session3_4 != nullptr) {
             ret = session3_4->configureStreams_3_4(config3_4,
                     [](Status s, device::V3_4::HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
@@ -3173,8 +3550,14 @@
                   StreamRotation::ROTATION_0};
         streams[0] = stream;
         createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
-                                  &config3_2, &config3_4);
-        if (session3_4 != nullptr) {
+                                  &config3_2, &config3_4, &config3_5);
+        if (session3_5 != nullptr) {
+            config3_5.streamConfigCounter = streamConfigCounter++;
+            ret = session3_5->configureStreams_3_5(config3_5,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else if (session3_4 != nullptr) {
             ret = session3_4->configureStreams_3_4(config3_4,
                     [](Status s, device::V3_4::HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
@@ -3224,8 +3607,9 @@
         sp<ICameraDeviceSession> session;
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
 
         outputBlobStreams.clear();
         ASSERT_EQ(Status::OK,
@@ -3240,6 +3624,7 @@
         ASSERT_NE(0u, outputVideoStreams.size());
 
         int32_t streamId = 0;
+        uint32_t streamConfigCounter = 0;
         for (auto& blobIter : outputBlobStreams) {
             for (auto& videoIter : outputVideoStreams) {
                 V3_2::Stream videoStream = {streamId++,
@@ -3259,11 +3644,19 @@
                                      static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF),
                                      StreamRotation::ROTATION_0};
                 ::android::hardware::hidl_vec<V3_2::Stream> streams = {videoStream, blobStream};
+                ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
                 ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
                 ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
-                                          &config3_2, &config3_4);
-                if (session3_4 != nullptr) {
+                                          &config3_2, &config3_4, &config3_5);
+                if (session3_5 != nullptr) {
+                    config3_5.streamConfigCounter = streamConfigCounter++;
+                    ret = session3_5->configureStreams_3_5(config3_5,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else if (session3_4 != nullptr) {
                     ret = session3_4->configureStreams_3_4(config3_4,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
@@ -3314,12 +3707,14 @@
         V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
         bool supportsPartialResults = false;
+        bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
         configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
                 &previewStream /*out*/, &halStreamConfig /*out*/,
                 &supportsPartialResults /*out*/,
-                &partialResultCount /*out*/);
+                &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
 
         std::shared_ptr<ResultMetadataQueue> resultQueue;
         auto resultQueueRet =
@@ -3350,17 +3745,26 @@
         ASSERT_TRUE(ret.isOk());
 
         hidl_handle buffer_handle;
-        allocateGraphicBuffer(previewStream.width, previewStream.height,
-                android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                    halStreamConfig.streams[0].consumerUsage),
-                halStreamConfig.streams[0].overrideFormat, &buffer_handle);
-
-        StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                                     bufferId,
-                                     buffer_handle,
-                                     BufferStatus::OK,
-                                     nullptr,
-                                     nullptr};
+        StreamBuffer outputBuffer;
+        if (useHalBufManager) {
+            outputBuffer = {halStreamConfig.streams[0].id,
+                            /*bufferId*/ 0,
+                            buffer_handle,
+                            BufferStatus::OK,
+                            nullptr,
+                            nullptr};
+        } else {
+            allocateGraphicBuffer(previewStream.width, previewStream.height,
+                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                        halStreamConfig.streams[0].consumerUsage),
+                    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};
@@ -3440,6 +3844,10 @@
             ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
         }
 
+        if (useHalBufManager) {
+            verifyBuffersReturned(session, deviceVersion, previewStream.id, cb);
+        }
+
         ret = session->close();
         ASSERT_TRUE(ret.isOk());
     }
@@ -3521,12 +3929,16 @@
 
         V3_4::HalStreamConfiguration halStreamConfig;
         bool supportsPartialResults = false;
+        bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
         V3_2::Stream previewStream;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<DeviceCb> cb;
         configurePreviewStreams3_4(name, deviceVersion, mProvider, &previewThreshold, physicalIds,
-                &session3_4, &previewStream, &halStreamConfig /*out*/,
-                &supportsPartialResults /*out*/, &partialResultCount /*out*/);
+                &session3_4, &session3_5, &previewStream, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                &useHalBufManager /*out*/, &cb /*out*/);
         ASSERT_NE(session3_4, nullptr);
 
         std::shared_ptr<ResultMetadataQueue> resultQueue;
@@ -3555,14 +3967,19 @@
         size_t k = 0;
         for (const auto& halStream : halStreamConfig.streams) {
             hidl_handle buffer_handle;
-            allocateGraphicBuffer(previewStream.width, previewStream.height,
-                    android_convertGralloc1To0Usage(halStream.v3_3.v3_2.producerUsage,
-                        halStream.v3_3.v3_2.consumerUsage),
-                    halStream.v3_3.v3_2.overrideFormat, &buffer_handle);
-            graphicBuffers.push_back(buffer_handle);
-            outputBuffers[k] = {halStream.v3_3.v3_2.id, bufferId, buffer_handle,
-                BufferStatus::OK, nullptr, nullptr};
-            bufferId++;
+            if (useHalBufManager) {
+                outputBuffers[k] = {halStream.v3_3.v3_2.id, /*bufferId*/0, buffer_handle,
+                    BufferStatus::OK, nullptr, nullptr};
+            } else {
+                allocateGraphicBuffer(previewStream.width, previewStream.height,
+                        android_convertGralloc1To0Usage(halStream.v3_3.v3_2.producerUsage,
+                            halStream.v3_3.v3_2.consumerUsage),
+                        halStream.v3_3.v3_2.overrideFormat, &buffer_handle);
+                graphicBuffers.push_back(buffer_handle);
+                outputBuffers[k] = {halStream.v3_3.v3_2.id, bufferId, buffer_handle,
+                    BufferStatus::OK, nullptr, nullptr};
+                bufferId++;
+            }
             k++;
         }
         hidl_vec<V3_4::PhysicalCameraSetting> camSettings(1);
@@ -3664,6 +4081,15 @@
 
         defaultPreviewSettings.unlock(settingsBuffer);
         filteredSettings.unlock(filteredSettingsBuffer);
+
+        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_3.v3_2.id;
+            }
+            verifyBuffersReturned(session3_4, streamIds, cb);
+        }
+
         ret = session3_4->close();
         ASSERT_TRUE(ret.isOk());
     }
@@ -3712,12 +4138,15 @@
         ASSERT_TRUE(ret.isOk());
 
         bool supportsPartialResults = false;
+        bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
         V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
+        sp<DeviceCb> cb;
         configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold,
                 &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/,
-                &supportsPartialResults /*out*/, &partialResultCount /*out*/);
+                &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                &useHalBufManager /*out*/, &cb /*out*/);
         std::shared_ptr<ResultMetadataQueue> resultQueue;
 
         auto resultQueueRet = session->getCaptureResultMetadataQueue(
@@ -3751,13 +4180,18 @@
             std::unique_lock<std::mutex> l(mLock);
 
             isoValues[i] = ((i % 2) == 0) ? isoRange.data.i32[0] : isoRange.data.i32[1];
-            allocateGraphicBuffer(previewStream.width, previewStream.height,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                        halStreamConfig.streams[0].consumerUsage),
-                    halStreamConfig.streams[0].overrideFormat, &buffers[i]);
+            if (useHalBufManager) {
+                outputBuffers[i] = {halStreamConfig.streams[0].id, /*bufferId*/0,
+                    nullptr, BufferStatus::OK, nullptr, nullptr};
+            } else {
+                allocateGraphicBuffer(previewStream.width, previewStream.height,
+                        android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                            halStreamConfig.streams[0].consumerUsage),
+                        halStreamConfig.streams[0].overrideFormat, &buffers[i]);
+                outputBuffers[i] = {halStreamConfig.streams[0].id, bufferId + i,
+                    buffers[i], BufferStatus::OK, nullptr, nullptr};
+            }
 
-            outputBuffers[i] = {halStreamConfig.streams[0].id, bufferId + i,
-                buffers[i], BufferStatus::OK, nullptr, nullptr};
             requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings.data()));
 
             // Disable all 3A routines
@@ -3810,6 +4244,9 @@
                         std::round(isoValues[i]*isoTol));
         }
 
+        if (useHalBufManager) {
+            verifyBuffersReturned(session, deviceVersion, previewStream.id, cb);
+        }
         ret = session->close();
         ASSERT_TRUE(ret.isOk());
     }
@@ -3839,18 +4276,25 @@
         V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
         bool supportsPartialResults = false;
+        bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
         configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
                 &previewStream /*out*/, &halStreamConfig /*out*/,
                 &supportsPartialResults /*out*/,
-                &partialResultCount /*out*/);
+                &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
 
         hidl_handle buffer_handle;
-        allocateGraphicBuffer(previewStream.width, previewStream.height,
-                android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                    halStreamConfig.streams[0].consumerUsage),
-                halStreamConfig.streams[0].overrideFormat, &buffer_handle);
+
+        if (useHalBufManager) {
+            bufferId = 0;
+        } else {
+            allocateGraphicBuffer(previewStream.width, previewStream.height,
+                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                        halStreamConfig.streams[0].consumerUsage),
+                    halStreamConfig.streams[0].overrideFormat, &buffer_handle);
+        }
 
         StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
                                      bufferId,
@@ -3906,12 +4350,14 @@
         V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
         bool supportsPartialResults = false;
+        bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
         configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
                 &previewStream /*out*/, &halStreamConfig /*out*/,
                 &supportsPartialResults /*out*/,
-                &partialResultCount /*out*/);
+                &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
 
         RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
         Return<void> ret;
@@ -3970,12 +4416,14 @@
         V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
         bool supportsPartialResults = false;
+        bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
         configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
                 &previewStream /*out*/, &halStreamConfig /*out*/,
                 &supportsPartialResults /*out*/,
-                &partialResultCount /*out*/);
+                &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
 
         std::shared_ptr<ResultMetadataQueue> resultQueue;
         auto resultQueueRet =
@@ -4005,10 +4453,14 @@
         ASSERT_TRUE(ret.isOk());
 
         hidl_handle buffer_handle;
-        allocateGraphicBuffer(previewStream.width, previewStream.height,
-                android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                    halStreamConfig.streams[0].consumerUsage),
-                halStreamConfig.streams[0].overrideFormat, &buffer_handle);
+        if (useHalBufManager) {
+            bufferId = 0;
+        } else {
+            allocateGraphicBuffer(previewStream.width, previewStream.height,
+                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                        halStreamConfig.streams[0].consumerUsage),
+                    halStreamConfig.streams[0].overrideFormat, &buffer_handle);
+        }
 
         StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
                                      bufferId,
@@ -4075,6 +4527,10 @@
             }
         }
 
+        if (useHalBufManager) {
+            verifyBuffersReturned(session, deviceVersion, previewStream.id, cb);
+        }
+
         ret = session->close();
         ASSERT_TRUE(ret.isOk());
     }
@@ -4100,12 +4556,14 @@
         V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
         bool supportsPartialResults = false;
+        bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
         configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
                 &previewStream /*out*/, &halStreamConfig /*out*/,
                 &supportsPartialResults /*out*/,
-                &partialResultCount /*out*/);
+                &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
 
         Return<Status> returnStatus = session->flush();
         ASSERT_TRUE(returnStatus.isOk());
@@ -4325,6 +4783,16 @@
 // Check whether ZSL is available using the static camera
 // characteristics.
 Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta) {
+    if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) {
+        return Status::OK;
+    } else {
+        return isZSLModeAvailable(staticMeta, YUV_REPROCESS);
+    }
+}
+
+Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta,
+        ReprocessType reprocType) {
+
     Status ret = Status::METHOD_NOT_SUPPORTED;
     if (nullptr == staticMeta) {
         return Status::ILLEGAL_ARGUMENT;
@@ -4338,10 +4806,34 @@
     }
 
     for (size_t i = 0; i < entry.count; i++) {
-        if ((ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
-                entry.data.u8[i]) ||
-                (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING ==
-                        entry.data.u8[i]) ){
+        if ((reprocType == PRIV_REPROCESS &&
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING == entry.data.u8[i]) ||
+                (reprocType == YUV_REPROCESS &&
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING == entry.data.u8[i])) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+// Check whether this is a monochrome camera using the static camera characteristics.
+Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) {
+    Status ret = Status::METHOD_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME == entry.data.u8[i]) {
             ret = Status::OK;
             break;
         }
@@ -4413,9 +4905,11 @@
         const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
         StreamConfigurationMode configMode,
         ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2 /*out*/,
-        ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4 /*out*/) {
+        ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4 /*out*/,
+        ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5 /*out*/) {
     ASSERT_NE(nullptr, config3_2);
     ASSERT_NE(nullptr, config3_4);
+    ASSERT_NE(nullptr, config3_5);
 
     ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(streams3_2.size());
     size_t idx = 0;
@@ -4424,7 +4918,9 @@
         stream.v3_2 = stream3_2;
         streams3_4[idx++] = stream;
     }
-    *config3_4 = {streams3_4, configMode, {}};
+    // Caller is responsible to fill in non-zero config3_5->streamConfigCounter after this returns
+    *config3_5 = {{streams3_4, configMode, {}}, 0};
+    *config3_4 = config3_5->v3_4;
     *config3_2 = {streams3_2, configMode};
 }
 
@@ -4434,15 +4930,22 @@
         const AvailableStream *previewThreshold,
         const std::unordered_set<std::string>& physicalIds,
         sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+        sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
         V3_2::Stream *previewStream /*out*/,
         device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
         bool *supportsPartialResults /*out*/,
-        uint32_t *partialResultCount /*out*/) {
+        uint32_t *partialResultCount /*out*/,
+        bool *useHalBufManager /*out*/,
+        sp<DeviceCb> *outCb /*out*/,
+        uint32_t streamConfigCounter) {
     ASSERT_NE(nullptr, session3_4);
+    ASSERT_NE(nullptr, session3_5);
     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_FALSE(physicalIds.empty());
 
     std::vector<AvailableStream> outputPreviewStreams;
@@ -4460,22 +4963,6 @@
         });
     ASSERT_TRUE(ret.isOk());
 
-    sp<DeviceCb> cb = new DeviceCb(this);
-    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());
-
-    sp<device::V3_3::ICameraDeviceSession> session3_3;
-    castSession(session, deviceVersion, &session3_3, session3_4);
-    ASSERT_NE(nullptr, session3_4);
-
     camera_metadata_t *staticMeta;
     ret = device3_x->getCameraCharacteristics([&] (Status s,
             CameraMetadata metadata) {
@@ -4494,6 +4981,33 @@
         *supportsPartialResults = (*partialResultCount > 1);
     }
 
+    bool checkMonochromeResultTags = Status::OK == isMonochromeCamera(staticMeta) &&
+            deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5;
+    sp<DeviceCb> cb = new DeviceCb(this, checkMonochromeResultTags);
+    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;
+    castSession(session, deviceVersion, &session3_3, session3_4, session3_5);
+    ASSERT_NE(nullptr, (*session3_4).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);
+    }
+
     outputPreviewStreams.clear();
     auto rc = getAvailableOutputStreams(staticMeta,
             outputPreviewStreams, previewThreshold);
@@ -4514,6 +5028,7 @@
     }
 
     ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
     config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
     RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
     ret = (*session3_4)->constructDefaultRequestSettings(reqTemplate,
@@ -4523,12 +5038,32 @@
             });
     ASSERT_TRUE(ret.isOk());
 
-    ret = (*session3_4)->configureStreams_3_4(config3_4,
-            [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
-            ASSERT_EQ(Status::OK, s);
-            ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
-            *halStreamConfig = halConfig;
-            });
+    if (*session3_5 != nullptr) {
+        config3_5.v3_4 = config3_4;
+        config3_5.streamConfigCounter = streamConfigCounter;
+        ret = (*session3_5)->configureStreams_3_5(config3_5,
+                [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
+                    *halStreamConfig = halConfig;
+                    if (*useHalBufManager) {
+                        hidl_vec<V3_2::Stream> streams(physicalIds.size());
+                        hidl_vec<V3_2::HalStream> halStreams(physicalIds.size());
+                        for (size_t i = 0; i < physicalIds.size(); i++) {
+                            streams[i] = streams3_4[i].v3_2;
+                            halStreams[i] = halConfig.streams[i].v3_3.v3_2;
+                        }
+                        cb->setCurrentStreamConfig(streams, halStreams);
+                    }
+                });
+    } else {
+        ret = (*session3_4)->configureStreams_3_4(config3_4,
+                [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                ASSERT_EQ(Status::OK, s);
+                ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
+                *halStreamConfig = halConfig;
+                });
+    }
     *previewStream = streams3_4[0].v3_2;
     ASSERT_TRUE(ret.isOk());
 }
@@ -4541,12 +5076,17 @@
         V3_2::Stream *previewStream /*out*/,
         HalStreamConfiguration *halStreamConfig /*out*/,
         bool *supportsPartialResults /*out*/,
-        uint32_t *partialResultCount /*out*/) {
+        uint32_t *partialResultCount /*out*/,
+        bool *useHalBufManager /*out*/,
+        sp<DeviceCb> *outCb /*out*/,
+        uint32_t streamConfigCounter) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, previewStream);
     ASSERT_NE(nullptr, halStreamConfig);
     ASSERT_NE(nullptr, supportsPartialResults);
     ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, outCb);
 
     std::vector<AvailableStream> outputPreviewStreams;
     ::android::sp<ICameraDevice> device3_x;
@@ -4563,21 +5103,6 @@
         });
     ASSERT_TRUE(ret.isOk());
 
-    sp<DeviceCb> cb = new DeviceCb(this);
-    ret = device3_x->open(
-        cb,
-        [&](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());
-
-    sp<device::V3_3::ICameraDeviceSession> session3_3;
-    sp<device::V3_4::ICameraDeviceSession> session3_4;
-    castSession(*session, deviceVersion, &session3_3, &session3_4);
-
     camera_metadata_t *staticMeta;
     ret = device3_x->getCameraCharacteristics([&] (Status s,
             CameraMetadata metadata) {
@@ -4596,6 +5121,33 @@
         *supportsPartialResults = (*partialResultCount > 1);
     }
 
+    bool checkMonochromeResultTags = Status::OK == isMonochromeCamera(staticMeta) &&
+            deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5;
+    sp<DeviceCb> cb = new DeviceCb(this, checkMonochromeResultTags);
+    ret = device3_x->open(
+        cb,
+        [&](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;
+    castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5);
+
+    *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);
+    }
+
     outputPreviewStreams.clear();
     auto rc = getAvailableOutputStreams(staticMeta,
             outputPreviewStreams, previewThreshold);
@@ -4611,9 +5163,33 @@
     ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
     ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
     ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
     createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
-                              &config3_2, &config3_4);
-    if (session3_4 != nullptr) {
+                              &config3_2, &config3_4, &config3_5);
+    if (session3_5 != nullptr) {
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        ret = session3_5->constructDefaultRequestSettings(reqTemplate,
+                                                       [&config3_5](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           config3_5.v3_4.sessionParams = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
+        config3_5.streamConfigCounter = streamConfigCounter;
+        ret = session3_5->configureStreams_3_5(config3_5,
+                [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(1u, halConfig.streams.size());
+                    halStreamConfig->streams.resize(1);
+                    halStreamConfig->streams[0] = halConfig.streams[0].v3_3.v3_2;
+                    if (*useHalBufManager) {
+                        hidl_vec<V3_2::Stream> streams(1);
+                        hidl_vec<V3_2::HalStream> halStreams(1);
+                        streams[0] = stream3_2;
+                        halStreams[0] = halConfig.streams[0].v3_3.v3_2;
+                        cb->setCurrentStreamConfig(streams, halStreams);
+                    }
+                });
+    } else if (session3_4 != nullptr) {
         RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
         ret = session3_4->constructDefaultRequestSettings(reqTemplate,
                                                        [&config3_4](auto status, const auto& req) {
@@ -4655,18 +5231,25 @@
 //Cast camera device session to corresponding version
 void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
         sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
-        sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/) {
+        sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+        sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/) {
     ASSERT_NE(nullptr, session3_3);
     ASSERT_NE(nullptr, session3_4);
+    ASSERT_NE(nullptr, session3_5);
 
     switch (deviceVersion) {
-        case CAMERA_DEVICE_API_VERSION_3_5:
+        case CAMERA_DEVICE_API_VERSION_3_5: {
+            auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_5 = castResult;
+        }
+        [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_4: {
             auto castResult = device::V3_4::ICameraDeviceSession::castFrom(session);
             ASSERT_TRUE(castResult.isOk());
             *session3_4 = castResult;
-            break;
         }
+        [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_3: {
             auto castResult = device::V3_3::ICameraDeviceSession::castFrom(session);
             ASSERT_TRUE(castResult.isOk());
@@ -4723,6 +5306,7 @@
         Return<void> ret = device3_5->getPhysicalCameraCharacteristics(physicalId,
                 [&](auto status, const auto& chars) {
             verifyCameraCharacteristics(status, chars);
+            verifyMonochromeCharacteristics(chars, deviceVersion);
         });
         ASSERT_TRUE(ret.isOk());
 
@@ -4774,6 +5358,178 @@
     }
 }
 
+void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
+        int deviceVersion) {
+    const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
+    Status rc = isMonochromeCamera(metadata);
+    if (Status::METHOD_NOT_SUPPORTED == rc) {
+        return;
+    }
+    ASSERT_EQ(Status::OK, rc);
+
+    camera_metadata_ro_entry entry;
+    // Check capabilities
+    int retcode = find_camera_metadata_ro_entry(metadata,
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        ASSERT_EQ(std::find(entry.data.u8, entry.data.u8 + entry.count,
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING),
+                entry.data.u8 + entry.count);
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_5) {
+            ASSERT_EQ(std::find(entry.data.u8, entry.data.u8 + entry.count,
+                    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW),
+                    entry.data.u8 + entry.count);
+        }
+    }
+
+    if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) {
+        // Check Cfa
+        retcode = find_camera_metadata_ro_entry(metadata,
+                ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, &entry);
+        if ((0 == retcode) && (entry.count == 1)) {
+            ASSERT_TRUE(entry.data.i32[0] == static_cast<int32_t>(
+                    CameraMetadataEnumAndroidSensorInfoColorFilterArrangement::ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO)
+                    || entry.data.i32[0] == static_cast<int32_t>(
+                    CameraMetadataEnumAndroidSensorInfoColorFilterArrangement::ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR));
+        }
+
+        // Check availableRequestKeys
+        retcode = find_camera_metadata_ro_entry(metadata,
+                ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+        if ((0 == retcode) && (entry.count > 0)) {
+            for (size_t i = 0; i < entry.count; i++) {
+                ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE);
+                ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM);
+                ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS);
+            }
+        } else {
+            ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+        }
+
+        // Check availableResultKeys
+        retcode = find_camera_metadata_ro_entry(metadata,
+                ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+        if ((0 == retcode) && (entry.count > 0)) {
+            for (size_t i = 0; i < entry.count; i++) {
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_GREEN_SPLIT);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
+                ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE);
+                ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM);
+                ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS);
+            }
+        } else {
+            ADD_FAILURE() << "Get camera availableResultKeys failed!";
+        }
+
+        // Check availableCharacteristicKeys
+        retcode = find_camera_metadata_ro_entry(metadata,
+                ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+        if ((0 == retcode) && (entry.count > 0)) {
+            for (size_t i = 0; i < entry.count; i++) {
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM1);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM2);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX1);
+                ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX2);
+            }
+        } else {
+            ADD_FAILURE() << "Get camera availableResultKeys failed!";
+        }
+
+        // Check blackLevelPattern
+        retcode = find_camera_metadata_ro_entry(metadata,
+                ANDROID_SENSOR_BLACK_LEVEL_PATTERN, &entry);
+        if ((0 == retcode) && (entry.count > 0)) {
+            ASSERT_EQ(entry.count, 4);
+            for (size_t i = 1; i < entry.count; i++) {
+                ASSERT_EQ(entry.data.i32[i], entry.data.i32[0]);
+            }
+        }
+    }
+}
+
+void CameraHidlTest::verifyMonochromeCameraResult(
+        const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata) {
+    camera_metadata_ro_entry entry;
+
+    // Check tags that are not applicable for monochrome camera
+    ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_GREEN_SPLIT));
+    ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_NEUTRAL_COLOR_POINT));
+    ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_MODE));
+    ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_TRANSFORM));
+    ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_GAINS));
+
+    // Check dynamicBlackLevel
+    entry = metadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+    if (entry.count > 0) {
+        ASSERT_EQ(entry.count, 4);
+        for (size_t i = 1; i < entry.count; i++) {
+            ASSERT_FLOAT_EQ(entry.data.f[i], entry.data.f[0]);
+        }
+    }
+
+    // Check noiseProfile
+    entry = metadata.find(ANDROID_SENSOR_NOISE_PROFILE);
+    if (entry.count > 0) {
+        ASSERT_EQ(entry.count, 2);
+    }
+
+    // Check lensShadingMap
+    entry = metadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+    if (entry.count > 0) {
+        ASSERT_EQ(entry.count % 4, 0);
+        for (size_t i = 0; i < entry.count/4; i++) {
+            ASSERT_FLOAT_EQ(entry.data.f[i*4+1], entry.data.f[i*4]);
+            ASSERT_FLOAT_EQ(entry.data.f[i*4+2], entry.data.f[i*4]);
+            ASSERT_FLOAT_EQ(entry.data.f[i*4+3], entry.data.f[i*4]);
+        }
+    }
+
+    // Check tonemapCurve
+    camera_metadata_ro_entry curveRed = metadata.find(ANDROID_TONEMAP_CURVE_RED);
+    camera_metadata_ro_entry curveGreen = metadata.find(ANDROID_TONEMAP_CURVE_GREEN);
+    camera_metadata_ro_entry curveBlue = metadata.find(ANDROID_TONEMAP_CURVE_BLUE);
+    if (curveRed.count > 0 && curveGreen.count > 0 && curveBlue.count > 0) {
+        ASSERT_EQ(curveRed.count, curveGreen.count);
+        ASSERT_EQ(curveRed.count, curveBlue.count);
+        for (size_t i = 0; i < curveRed.count; i++) {
+            ASSERT_FLOAT_EQ(curveGreen.data.f[i], curveRed.data.f[i]);
+            ASSERT_FLOAT_EQ(curveBlue.data.f[i], curveRed.data.f[i]);
+        }
+    }
+}
+
+void CameraHidlTest::verifyBuffersReturned(
+        sp<device::V3_2::ICameraDeviceSession> session,
+        int deviceVersion, int32_t streamId,
+        sp<DeviceCb> cb, uint32_t streamConfigCounter) {
+    sp<device::V3_3::ICameraDeviceSession> session3_3;
+    sp<device::V3_4::ICameraDeviceSession> session3_4;
+    sp<device::V3_5::ICameraDeviceSession> session3_5;
+    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+    ASSERT_NE(nullptr, session3_5.get());
+
+    hidl_vec<int32_t> streamIds(1);
+    streamIds[0] = streamId;
+    session3_5->signalStreamFlush(streamIds, /*streamConfigCounter*/streamConfigCounter);
+    cb->waitForBuffersReturned();
+}
+
+void CameraHidlTest::verifyBuffersReturned(
+        sp<device::V3_4::ICameraDeviceSession> session3_4,
+        hidl_vec<int32_t> streamIds, sp<DeviceCb> cb, uint32_t streamConfigCounter) {
+    auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session3_4);
+    ASSERT_TRUE(castResult.isOk());
+    sp<device::V3_5::ICameraDeviceSession> session3_5 = castResult;
+    ASSERT_NE(nullptr, session3_5.get());
+
+    session3_5->signalStreamFlush(streamIds, /*streamConfigCounter*/streamConfigCounter);
+    cb->waitForBuffersReturned();
+}
+
 // Open a device session with empty callbacks and return static metadata.
 void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
         sp<ICameraProvider> provider,
diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp
index 544162b..debb3e5 100644
--- a/cas/1.0/default/Android.bp
+++ b/cas/1.0/default/Android.bp
@@ -1,5 +1,5 @@
-cc_binary {
-    name: "android.hardware.cas@1.0-service",
+cc_defaults {
+    name: "cas_service_defaults",
     defaults: ["hidl_defaults"],
     vendor: true,
     relative_install_path: "hw",
@@ -13,7 +13,6 @@
     ],
 
     compile_multilib: "32",
-    init_rc: ["android.hardware.cas@1.0-service.rc"],
 
     shared_libs: [
       "android.hardware.cas@1.0",
@@ -31,3 +30,19 @@
       "media_plugin_headers",
     ],
 }
+
+cc_binary {
+    name: "android.hardware.cas@1.0-service",
+    vintf_fragments: ["android.hardware.cas@1.0-service.xml"],
+    defaults: ["cas_service_defaults"],
+    init_rc: ["android.hardware.cas@1.0-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.cas@1.0-service-lazy",
+    vintf_fragments: ["android.hardware.cas@1.0-service-lazy.xml"],
+    overrides: ["android.hardware.cas@1.0-service"],
+    defaults: ["cas_service_defaults"],
+    init_rc: ["android.hardware.cas@1.0-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
new file mode 100644
index 0000000..735cfbc
--- /dev/null
+++ b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.cas-hal-1-0 /vendor/bin/hw/android.hardware.cas@1.0-service
+    interface android.hardware.cas@1.0::IMediaCasService default
+    oneshot
+    disabled
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.xml b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.xml
new file mode 100644
index 0000000..9b55370
--- /dev/null
+++ b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.xml b/cas/1.0/default/android.hardware.cas@1.0-service.xml
new file mode 100644
index 0000000..9b55370
--- /dev/null
+++ b/cas/1.0/default/android.hardware.cas@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.0/default/service.cpp b/cas/1.0/default/service.cpp
index 04a8ad9..2e6e55d 100644
--- a/cas/1.0/default/service.cpp
+++ b/cas/1.0/default/service.cpp
@@ -15,7 +15,11 @@
  */
 
 //#define LOG_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.cas@1.0-service-lazy"
+#else
 #define LOG_TAG "android.hardware.cas@1.0-service"
+#endif
 
 #include <binder/ProcessState.h>
 #include <hidl/HidlTransportSupport.h>
@@ -25,24 +29,30 @@
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
-using android::hardware::cas::V1_0::implementation::MediaCasService;
+using android::hardware::LazyServiceRegistrar;
 using android::hardware::cas::V1_0::IMediaCasService;
+using android::hardware::cas::V1_0::implementation::MediaCasService;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
 
 int main() {
-    ALOGD("android.hardware.cas@1.0-service starting...");
-
-    // The CAS HAL may communicate to other vendor components via
-    // /dev/vndbinder
-    android::ProcessState::initWithDriver("/dev/vndbinder");
-
     configureRpcThreadpool(8, true /* callerWillJoin */);
 
     // Setup hwbinder service
     android::sp<IMediaCasService> service = new MediaCasService();
-    android::status_t status = service->registerAsService();
-    LOG_ALWAYS_FATAL_IF(
-            status != android::OK,
-            "Error while registering cas service: %d", status);
+    android::status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
+        status = serviceRegistrar->registerServiceWithCallback(service);
+    } else {
+        status = service->registerAsService();
+    }
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering cas service: %d", status);
+
     joinRpcThreadpool();
     return 0;
 }
diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp
index 0db9bb0..622baa5 100644
--- a/cas/1.0/vts/functional/Android.bp
+++ b/cas/1.0/vts/functional/Android.bp
@@ -29,5 +29,6 @@
     shared_libs: [
         "libbinder",
     ],
+    test_suites: ["general-tests"],
 }
 
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index d24cbab..ceb53be 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -145,7 +145,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.drm</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>ICryptoFactory</name>
             <regex-instance>.*</regex-instance>
@@ -157,7 +157,7 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.drm</name>
-        <version>1.1</version>
+        <version>1.2</version>
         <interface>
             <name>ICryptoFactory</name>
             <regex-instance>.*</regex-instance>
diff --git a/configstore/1.0/vts/functional/Android.bp b/configstore/1.0/vts/functional/Android.bp
index 1b8a591..008b59d 100644
--- a/configstore/1.0/vts/functional/Android.bp
+++ b/configstore/1.0/vts/functional/Android.bp
@@ -19,5 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalConfigstoreV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.configstore@1.0"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/confirmationui/1.0/vts/functional/Android.bp b/confirmationui/1.0/vts/functional/Android.bp
index 823e035..d19d702 100644
--- a/confirmationui/1.0/vts/functional/Android.bp
+++ b/confirmationui/1.0/vts/functional/Android.bp
@@ -27,4 +27,5 @@
         "libcn-cbor",
         "android.hardware.confirmationui-support-lib",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
index 62156b3..e215baa 100644
--- a/confirmationui/support/Android.bp
+++ b/confirmationui/support/Android.bp
@@ -46,6 +46,7 @@
         "android.hardware.keymaster@4.0",
         "libhidlbase",
     ],
+    test_suites: ["general-tests"],
     clang: true,
     cflags: [ "-O0" ],
 }
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
index 7c6e8c7..aef0340 100644
--- a/contexthub/1.0/vts/functional/Android.bp
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -19,5 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.contexthub@1.0"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index 57678fb..d6ebfdd 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -32,4 +32,5 @@
         "libssl",
         "libcrypto",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
index 782f283..1090b69 100644
--- a/drm/1.1/vts/functional/Android.bp
+++ b/drm/1.1/vts/functional/Android.bp
@@ -31,4 +31,5 @@
         "libssl",
         "libcrypto",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/dumpstate/1.0/vts/functional/Android.bp b/dumpstate/1.0/vts/functional/Android.bp
index 1ab530f..fc64d05 100644
--- a/dumpstate/1.0/vts/functional/Android.bp
+++ b/dumpstate/1.0/vts/functional/Android.bp
@@ -18,4 +18,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalDumpstateV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.dumpstate@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/gatekeeper/1.0/vts/functional/Android.bp b/gatekeeper/1.0/vts/functional/Android.bp
index aa1da7b..f55e5d2 100644
--- a/gatekeeper/1.0/vts/functional/Android.bp
+++ b/gatekeeper/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGatekeeperV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.gatekeeper@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/gnss/1.0/vts/functional/Android.bp b/gnss/1.0/vts/functional/Android.bp
index d7713db..505cb41 100644
--- a/gnss/1.0/vts/functional/Android.bp
+++ b/gnss/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGnssV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.gnss@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index 67ef486..9892eca 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -26,4 +26,5 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 8e346df..c98cc0d 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -34,4 +34,5 @@
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
index a6871fb..c760d0a 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -132,24 +132,13 @@
 
     Return<void> getRenderIntents(Display display, ColorMode mode,
                                   IComposerClient::getRenderIntents_cb hidl_cb) override {
-#ifdef USES_DISPLAY_RENDER_INTENTS
         std::vector<RenderIntent> intents;
         Error err = mHal->getRenderIntents(display, mode, &intents);
         hidl_cb(err, intents);
-#else
-        (void)display;
-        (void)mode;
-        hidl_cb(Error::NONE, hidl_vec<RenderIntent>({RenderIntent::COLORIMETRIC}));
-#endif
         return Void();
     }
 
     Return<Error> setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) override {
-#ifndef USES_DISPLAY_RENDER_INTENTS
-        if (intent != RenderIntent::COLORIMETRIC) {
-            return Error::BAD_PARAMETER;
-        }
-#endif
         return mHal->setColorMode_2_2(display, mode, intent);
     }
 
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index acc9245..b62f302 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -44,4 +44,5 @@
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
index 969317a..853c2a3 100644
--- a/graphics/mapper/2.0/vts/functional/Android.bp
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -24,4 +24,5 @@
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/graphics/mapper/2.1/vts/functional/Android.bp b/graphics/mapper/2.1/vts/functional/Android.bp
index ac67af8..afd8e7f 100644
--- a/graphics/mapper/2.1/vts/functional/Android.bp
+++ b/graphics/mapper/2.1/vts/functional/Android.bp
@@ -26,4 +26,5 @@
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@2.1-vts",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/health/1.0/vts/functional/Android.bp b/health/1.0/vts/functional/Android.bp
index 8742651..c14dcee 100644
--- a/health/1.0/vts/functional/Android.bp
+++ b/health/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalHealthV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.health@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/health/2.0/vts/functional/Android.bp b/health/2.0/vts/functional/Android.bp
index 4ad01b9..3544e5f 100644
--- a/health/2.0/vts/functional/Android.bp
+++ b/health/2.0/vts/functional/Android.bp
@@ -22,4 +22,5 @@
         "android.hardware.health@1.0",
         "android.hardware.health@2.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp
index 63591cf..250a7dc 100644
--- a/health/storage/1.0/vts/functional/Android.bp
+++ b/health/storage/1.0/vts/functional/Android.bp
@@ -22,5 +22,6 @@
     shared_libs: [
         "libhidltransport"
     ],
+    test_suites: ["general-tests"],
 }
 
diff --git a/ir/1.0/vts/functional/Android.bp b/ir/1.0/vts/functional/Android.bp
index 2a86f8e..f5c9d61 100644
--- a/ir/1.0/vts/functional/Android.bp
+++ b/ir/1.0/vts/functional/Android.bp
@@ -21,4 +21,5 @@
     static_libs: [
         "android.hardware.ir@1.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp
index 7d96704..b0371c7 100644
--- a/keymaster/3.0/vts/functional/Android.bp
+++ b/keymaster/3.0/vts/functional/Android.bp
@@ -29,4 +29,5 @@
         "libcrypto",
         "libsoftkeymasterdevice",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/keymaster/3.0/vts/functional/authorization_set.h b/keymaster/3.0/vts/functional/authorization_set.h
index 5f92d81..0c15e68 100644
--- a/keymaster/3.0/vts/functional/authorization_set.h
+++ b/keymaster/3.0/vts/functional/authorization_set.h
@@ -201,7 +201,7 @@
     void push_back(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data, size_t data_length) {
         hidl_vec<uint8_t> new_blob;
         new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
-        push_back(ttag, std::move(new_blob));
+        push_back(ttag, new_blob);
     }
 
     /**
@@ -225,8 +225,7 @@
     }
 
     hidl_vec<KeyParameter> hidl_data() const {
-        hidl_vec<KeyParameter> result;
-        result.setToExternal(const_cast<KeyParameter*>(data()), size());
+        hidl_vec<KeyParameter> result(begin(), end());
         return result;
     }
 
@@ -252,7 +251,7 @@
                                            size_t data_length) {
         hidl_vec<uint8_t> new_blob;
         new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
-        push_back(ttag, std::move(new_blob));
+        push_back(ttag, new_blob);
         return *this;
     }
 
@@ -262,6 +261,12 @@
         return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
     }
 
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, char* data,
+                                           size_t data_length) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
     AuthorizationSetBuilder& Authorizations(AuthorizationSet&& set);
     AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set);
 
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
index ac96c86..ff08066 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -214,9 +214,8 @@
         }
     }
 
-    const hidl_vec<KeyParameter> hidl_data() const {
-        hidl_vec<KeyParameter> result;
-        result.setToExternal(const_cast<KeyParameter*>(data()), size());
+    hidl_vec<KeyParameter> hidl_data() const {
+        hidl_vec<KeyParameter> result(begin(), end());
         return result;
     }
 
@@ -242,7 +241,7 @@
                                            size_t data_length) {
         hidl_vec<uint8_t> new_blob;
         new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
-        push_back(ttag, std::move(new_blob));
+        push_back(ttag, new_blob);
         return *this;
     }
 
@@ -252,6 +251,12 @@
         return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
     }
 
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, char* data,
+                                           size_t data_length) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
     AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) {
         for (const auto& entry : set) {
             push_back(entry);
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 90a0f1b..5e5ae8d 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -33,25 +33,19 @@
 
 namespace support {
 
-inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
-                                             bool inPlace = true) {
-    hidl_vec<uint8_t> result;
-    result.setToExternal(const_cast<unsigned char*>(data), length, !inPlace);
+inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length) {
+    hidl_vec<uint8_t> result(data, data + length);
     return result;
 }
 
-inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value, bool inPlace = true) {
-    hidl_vec<uint8_t> result;
-    result.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.data())),
-                         static_cast<size_t>(value.size()), !inPlace);
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value) {
+    hidl_vec<uint8_t> result(reinterpret_cast<const uint8_t*>(value.data()),
+                             reinterpret_cast<const uint8_t*>(value.data()) + value.size());
     return result;
 }
 
-inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob,
-                                             bool inPlace = true) {
-    hidl_vec<uint8_t> result;
-    result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size()),
-                         !inPlace);
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob) {
+    hidl_vec<uint8_t> result(blob.data(), blob.data() + static_cast<size_t>(blob.size()));
     return result;
 }
 
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index d74a16f..333e408 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -29,4 +29,5 @@
         "libkeymaster4support",
         "libsoftkeymasterdevice",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/light/2.0/vts/functional/Android.bp b/light/2.0/vts/functional/Android.bp
index e0ec4cf..9f03d27 100644
--- a/light/2.0/vts/functional/Android.bp
+++ b/light/2.0/vts/functional/Android.bp
@@ -19,5 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalLightV2_0TargetTest.cpp"],
     static_libs: ["android.hardware.light@2.0"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/media/c2/1.0/IComponent.hal b/media/c2/1.0/IComponent.hal
index 7fd551f..deb9255 100644
--- a/media/c2/1.0/IComponent.hal
+++ b/media/c2/1.0/IComponent.hal
@@ -22,19 +22,13 @@
 import IConfigurable;
 import IComponentInterface;
 import IComponentListener;
-import IInputSurface;
-import IInputSurfaceConnection;
 
 /**
- * Interface for a Codec2 component corresponding to API level 1.0 or below.
- * Components have two states: stopped and running. The running state has three
- * sub-states: executing, tripped and error.
- *
- * All methods in `IComponent` must not block. If a method call cannot be
- * completed in a timely manner, it must return `TIMED_OUT` in the return
- * status.
+ * Interface for a Codec 2.0 component corresponding to API level 1.0 or
+ * below. Components have two states: stopped and running. The running
+ * state has three sub-states: executing, tripped and error.
  */
-interface IComponent {
+interface IComponent extends IComponentInterface {
 
     // METHODS AVAILABLE WHEN RUNNING
     // =========================================================================
@@ -44,42 +38,44 @@
      *
      * This method must be supported in running (including tripped) states.
      *
-     * It is acceptable for this method to return `OK` and return an error value
-     * using the IComponentListener::onWorkDone() callback.
+     * This method must return within 1ms
      *
-     * @param workBundle `WorkBundle` object containing a list of `Work` objects
-     *     to queue to the component.
+     * It is acceptable for this method to return OK and return an error value
+     * using the onWorkDone() callback.
+     *
+     * @param workBundle WorkBundle object containing Works to queue to the
+     * component.
      * @return status Status of the call, which may be
-     *   - `OK`        - Works in @p workBundle were successfully queued.
-     *   - `BAD_INDEX` - Some component id in some `Worklet` is not valid.
-     *   - `CANNOT_DO` - The components are not tunneled but some `Work` object
-     *                   contains tunneling information.
-     *   - `NO_MEMORY` - Not enough memory to queue @p workBundle.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - Works in \p workBundle were successfully queued.
+     *   - BAD_INDEX - Some component(s) in some Work do(es) not exist.
+     *   - CANNOT_DO - The components are not tunneled.
+     *   - NO_MEMORY - Not enough memory to queue \p workBundle.
+     *   - CORRUPTED - Some unknown error prevented queuing the Works.
+     *                 (unexpected).
      */
     queue(WorkBundle workBundle) generates (Status status);
 
     /**
-     * Discards and abandons any pending `Work` items for the component.
+     * Discards and abandons any pending work for the component.
      *
      * This method must be supported in running (including tripped) states.
      *
-     * `Work` that could be immediately abandoned/discarded must be returned in
-     * @p flushedWorkBundle. The order in which queued `Work` items are
-     * discarded can be arbitrary.
+     * This method must return within 5ms.
      *
-     * `Work` that could not be abandoned or discarded immediately must be
-     * marked to be discarded at the earliest opportunity, and must be returned
-     * via IComponentListener::onWorkDone(). This must be completed within
-     * 500ms.
+     * Work that could be immediately abandoned/discarded must be returned in
+     * \p flushedWorks; this can be done in an arbitrary order.
+     *
+     * Work that could not be abandoned or discarded immediately must be marked
+     * to be discarded at the earliest opportunity, and must be returned via
+     * the onWorkDone() callback. This must be completed within 500ms.
      *
      * @return status Status of the call, which may be
-     *   - `OK`        - The component has been successfully flushed.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return flushedWorkBundle `WorkBundle` object containing flushed `Work`
-     *     items.
+     *   - OK        - The component has been successfully flushed.
+     *   - TIMED_OUT - The flush could not be completed within the time limit.
+     *                 (unexpected)
+     *   - CORRUPTED - Some unknown error prevented flushing from
+     *                 completion. (unexpected)
+     * @return flushedWorkBundle WorkBundle object containing flushed Works.
      */
     flush(
         ) generates (
@@ -91,39 +87,42 @@
      * Drains the component, and optionally downstream components. This is a
      * signalling method; as such it does not wait for any work completion.
      *
-     * The last `Work` item is marked as "drain-till-here", so the component is
-     * notified not to wait for further `Work` before it processes what is
-     * already queued. This method can also be used to set the end-of-stream
-     * flag after `Work` has been queued. Client can continue to queue further
-     * `Work` immediately after this method returns.
+     * Marks last work item as "drain-till-here", so component is notified not
+     * to wait for further work before it processes work already queued. This
+     * method can also be used to set the end-of-stream flag after work has been
+     * queued. Client can continue to queue further work immediately after this
+     * method returns.
      *
      * This method must be supported in running (including tripped) states.
      *
-     * `Work` that is completed must be returned via
-     * IComponentListener::onWorkDone().
+     * This method must return within 1ms.
+     *
+     * Work that is completed must be returned via the onWorkDone() callback.
      *
      * @param withEos Whether to drain the component with marking end-of-stream.
      * @return status Status of the call, which may be
-     *   - `OK`        - The drain request has been successfully recorded.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The drain request has been successfully recorded.
+     *   - TIMED_OUT - The flush could not be completed within the time limit.
+     *                 (unexpected)
+     *   - CORRUPTED - Some unknown error prevented flushing from completion.
+     *                 (unexpected)
      */
     drain(bool withEos) generates (Status status);
 
     /**
      * Starts using a surface for output.
      *
-     * This method must not block.
-     *
-     * @param blockPoolId Id of the `C2BlockPool` to be associated with the
-     *     output surface.
-     * @param surface Output surface.
+     * @param blockPoolId The id of the BlockPool to be associated with the
+     * output surface.
+     * @param surface A surface to use for codec output.
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `CANNOT_DO` - The component does not support an output surface.
-     *   - `REFUSED`   - The output surface cannot be accessed.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The operation completed successfully.
+     *   - CANNOT_DO - The component does not support an output surface.
+     *   - REFUSED   - The output surface cannot be accessed.
+     *   - TIMED_OUT - The component could not be connected within the time
+     *                 limit. (unexpected)
+     *   - CORRUPTED - Some unknown error prevented connecting the component.
+     *                 (unexpected)
      */
     setOutputSurface(
             uint64_t blockPoolId,
@@ -133,101 +132,65 @@
         );
 
     /**
-     * Starts using an input surface.
+     * Starts using a persistent OMX input surface for a component.
      *
      * The component must be in running state.
      *
-     * @param inputSurface Input surface to connect to.
+     * @param producer Producer component of an OMX persistent input surface.
+     * @param source Source component of an OMX persistent input surface.
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `CANNOT_DO` - The component does not support an input surface.
-     *   - `BAD_STATE` - The component is not in running state.
-     *   - `DUPLICATE` - The component is already connected to an input surface.
-     *   - `REFUSED`   - The input surface is already in use.
-     *   - `NO_MEMORY` - Not enough memory to start the component.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return connection `IInputSurfaceConnection` object, which can be used to
-     *     query and configure properties of the connection. This cannot be
-     *     null.
-     */
-    connectToInputSurface(
-            IInputSurface inputSurface
-        ) generates (
-            Status status,
-            IInputSurfaceConnection connection
-        );
-
-    /**
-     * Starts using an OMX input surface.
-     *
-     * The component must be in running state.
-     *
-     * This method is similar to connectToInputSurface(), but it takes an OMX
-     * input surface (as a pair of `IGraphicBufferProducer` and
-     * `IGraphicBufferSource`) instead of Codec2's own `IInputSurface`.
-     *
-     * @param producer Producer component of an OMX input surface.
-     * @param source Source component of an OMX input surface.
-     * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `CANNOT_DO` - The component does not support an OMX input surface.
-     *   - `BAD_STATE` - The component is not in running state.
-     *   - `DUPLICATE` - The component is already connected to an input surface.
-     *   - `REFUSED`   - The input surface is already in use.
-     *   - `NO_MEMORY` - Not enough memory to start the component.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return connection `IInputSurfaceConnection` object, which can be used to
-     *     query and configure properties of the connection. This cannot be
-     *     null.
+     *   - OK        - The operation completed successfully.
+     *   - CANNOT_DO - The component does not support an input surface.
+     *   - BAD_STATE - Component is not in running state.
+     *   - DUPLICATE - The component is already connected to an input surface.
+     *   - REFUSED   - The input surface is already in use.
+     *   - NO_MEMORY - Not enough memory to start the component.
+     *   - TIMED_OUT - The component could not be connected within the time
+     *                 limit. (unexpected)
+     *   - CORRUPTED - Some unknown error prevented connecting the component.
+     *                 (unexpected)
      */
     connectToOmxInputSurface(
             IGraphicBufferProducer producer,
             IGraphicBufferSource source
-        ) generates (
-            Status status,
-            IInputSurfaceConnection connection
-        );
+        ) generates (Status status);
 
     /**
      * Stops using an input surface.
      *
+     * This call is used for both Codec 2.0 and OMX input surfaces.
+     *
      * The component must be in running state.
      *
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `CANNOT_DO` - The component does not support an input surface.
-     *   - `BAD_STATE` - The component is not in running state.
-     *   - `NOT_FOUND` - The component is not connected to an input surface.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The operation completed successfully.
+     *   - CANNOT_DO - The component does not support an input surface.
+     *   - BAD_STATE - Component is not in running state.
+     *   - NOT_FOUND - The component is not connected to an input surface.
+     *   - TIMED_OUT - The component could not be connected within the time
+     *                 limit. (unexpected)
+     *   - CORRUPTED - Some unknown error prevented connecting the component.
+     *                 (unexpected)
      */
     disconnectFromInputSurface() generates (Status Status);
 
     /**
-     * Creates a local `C2BlockPool` backed by the given allocator and returns
-     * its id.
+     * Creates a local block pool backed by the given allocator and returns its
+     * identifier.
      *
-     * The returned @p blockPoolId is the only way the client can refer to a
-     * `C2BlockPool` object in the component. The id can be passed to
-     * setOutputSurface() or used in some C2Param objects later.
+     * This call must return within 100 msec.
      *
-     * The created `C2BlockPool` object can be destroyed by calling
-     * destroyBlockPool(), reset() or release(). reset() and release() must
-     * destroy all `C2BlockPool` objects that have been created.
-     *
-     * @param allocatorId Id of a `C2Allocator`.
+     * @param allocatorId The Codec 2.0 allocator ID
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `NO_MEMORY` - Not enough memory to create the pool.
-     *   - `BAD_VALUE` - @p allocatorId is not recognized.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return blockPoolId Id of the created C2BlockPool object. This may be
-     *     used in setOutputSurface() if the allocator
-     * @return configurable Configuration interface for the created pool. This
-     *     must not be null.
+     *   - OK        - The operation completed successfully.
+     *   - NO_MEMORY - Not enough memory to create the pool.
+     *   - BAD_VALUE - Invalid allocator.
+     *   - TIMED_OUT - The pool could not be created within the time
+     *                 limit. (unexpected)
+     *   - CORRUPTED - Some unknown error prevented creating the pool.
+     *                 (unexpected)
+     * @return blockPoolId The Codec 2.0 blockpool ID for the created pool.
+     * @return configurable Configuration interface for the created pool.
      */
     createBlockPool(uint32_t allocatorId) generates (
         Status status,
@@ -238,13 +201,17 @@
     /**
      * Destroys a local block pool previously created by createBlockPool().
      *
-     * @param blockPoolId Id of a `C2BlockPool` that was previously returned by
+     * This call must return within 100 msec.
+     *
+     * @param blockPoolId The block pool id previously returned by
      *      createBlockPool().
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `NOT_FOUND` - The supplied blockPoolId is not valid.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The operation completed successfully.
+     *   - NOT_FOUND - The supplied blockPoolId is not valid.
+     *   - TIMED_OUT - The pool could not be destroyedwithin the time limit.
+     *                 (unexpected)
+     *   - CORRUPTED - Some unknown error prevented destruction of the pool.
+     *                 (unexpected)
      */
     destroyBlockPool(uint64_t blockPoolId) generates (Status status);
 
@@ -256,24 +223,28 @@
      *
      * This method must be supported in stopped state as well as tripped state.
      *
-     * If the return value is `OK`, the component must be in the running state.
-     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
-     * expected as a response to this call. Otherwise, the component must be in
-     * the stopped state.
+     * If the return value is OK, the component must be in the running state.
+     * If the return value is BAD_STATE or DUPLICATE, no state change is
+     * expected as a response to this call.
+     * Otherwise, the component must be in the stopped state.
      *
      * If a component is in the tripped state and start() is called while the
-     * component configuration still results in a trip, start() must succeed and
-     * a new onTripped() callback must be used to communicate the configuration
+     * component configuration still results in a trip, start must succeed and
+     * a new onTripped callback must be used to communicate the configuration
      * conflict that results in the new trip.
      *
+     * This method must return within 500ms.
+     *
      * @return status Status of the call, which may be
-     *   - `OK`        - The component has started successfully.
-     *   - `BAD_STATE` - Component is not in stopped or tripped state.
-     *   - `DUPLICATE` - When called during another start call from another
-     *                   thread.
-     *   - `NO_MEMORY` - Not enough memory to start the component.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The component has started successfully.
+     *   - BAD_STATE - Component is not in stopped or tripped state.
+     *   - DUPLICATE - When called during another start call from another
+     *                 thread.
+     *   - NO_MEMORY - Not enough memory to start the component.
+     *   - TIMED_OUT - The component could not be started within the time limit.
+     *                 (unexpected)
+     *   - CORRUPTED - Some unknown error prevented starting the component.
+     *                 (unexpected)
      */
     start() generates (Status status);
 
@@ -284,22 +255,22 @@
      *
      * This method must return withing 500ms.
      *
-     * Upon this call, all pending `Work` must be abandoned.
-     *
-     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
-     * expected as a response to this call. For all other return values, the
-     * component must be in the stopped state.
+     * Upon this call, all pending work must be abandoned.
+     * If the return value is BAD_STATE or DUPLICATE, no state change is
+     * expected as a response to this call.
+     * For all other return values, the component must be in the stopped state.
      *
      * This does not alter any settings and tunings that may have resulted in a
      * tripped state.
      *
      * @return status Status of the call, which may be
-     *   - `OK`        - The component has stopped successfully.
-     *   - `BAD_STATE` - Component is not in running state.
-     *   - `DUPLICATE` - When called during another stop call from another
-     *                   thread.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The component has stopped successfully.
+     *   - BAD_STATE - Component is not in running state.
+     *   - DUPLICATE - When called during another stop call from another thread.
+     *   - TIMED_OUT - The component could not be stopped within the time limit.
+     *                 (unexpected)
+     *   - CORRUPTED - Some unknown error prevented starting the component.
+     *                 (unexpected)
      */
     stop() generates (Status status);
 
@@ -313,24 +284,25 @@
      *
      * This method must return withing 500ms.
      *
-     * When this call returns, if @p status is `OK`, all `Work` items must
-     * have been abandoned, and all resources (including `C2BlockPool` objects
-     * previously created by createBlockPool()) must have been released.
+     * After this call returns all work must have been abandoned, all references
+     * must have been released.
      *
-     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
-     * expected as a response to this call. For all other return values, the
-     * component must be in the stopped state.
+     * If the return value is BAD_STATE or DUPLICATE, no state change is
+     * expected as a response to this call.
+     * For all other return values, the component shall be in the stopped state.
      *
-     * This brings settings back to their default, "guaranteeing" no tripped
+     * This brings settings back to their default - "guaranteeing" no tripped
      * state.
      *
      * @return status Status of the call, which may be
-     *   - `OK`        - The component has been reset.
-     *   - `BAD_STATE` - Component is in released state.
-     *   - `DUPLICATE` - When called during another reset call from another
-     *                   thread.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The component has been reset.
+     *   - BAD_STATE - Component is in released state.
+     *   - DUPLICATE - When called during another reset call from another
+     *                 thread.
+     *   - TIMED_OUT - The component could not be reset within the time limit.
+     *                 (unexpected)
+     *   - CORRUPTED - Some unknown error prevented resetting the component.
+     *                 (unexpected)
      */
     reset() generates (Status status);
 
@@ -339,27 +311,19 @@
      *
      * This method must be supported in stopped state.
      *
-     * This method destroys the component. Upon return, if @p status is `OK` or
-     * `DUPLICATE`, all resources must have been released.
+     * This method must return withing 500ms. Upon return all references must
+     * be abandoned.
      *
      * @return status Status of the call, which may be
-     *   - `OK`        - The component has been released.
-     *   - `BAD_STATE` - The component is running.
-     *   - `DUPLICATE` - The component is already released.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The component has been released.
+     *   - BAD_STATE - The component is running.
+     *   - DUPLICATE - The component is already released.
+     *   - TIMED_OUT - The component could not be released within the time
+     *                 limit. (unexpected)
+     *   - CORRUPTED - Some unknown error prevented releasing the component.
+     *                 (unexpected)
      */
     release() generates (Status status);
 
-    /**
-     * Returns the @ref IComponentInterface instance associated to this
-     * component.
-     *
-     * An @p IConfigurable instance for the component can be obtained by calling
-     * IComponentInterface::getConfigurable() on the returned @p intf.
-     *
-     * @return intf `IComponentInterface` instance. This must not be null.
-     */
-    getInterface() generates (IComponentInterface intf);
 };
 
diff --git a/media/c2/1.0/IComponentInterface.hal b/media/c2/1.0/IComponentInterface.hal
index a007d02..d4b30b1 100644
--- a/media/c2/1.0/IComponentInterface.hal
+++ b/media/c2/1.0/IComponentInterface.hal
@@ -19,20 +19,21 @@
 import IConfigurable;
 
 /**
- * Component interface object. This object contains all of the configurations of
+ * Component interface object. This object contains all of the configuration of
  * a potential or actual component. It can be created and used independently of
- * an actual Codec2 component to query supported parameters for various
- * component settings, and configurations for a potential component.
- *
- * An actual component exposes this interface via IComponent::getInterface().
+ * an actual Codec 2.0 component instance to query support and parameters for
+ * various component settings and configurations for a potential component.
+ * Actual components also expose this interface.
  */
-interface IComponentInterface {
-    /**
-     * Returns the @ref IConfigurable instance associated to this component
-     * interface.
+interface IComponentInterface extends IConfigurable {
+    /*
+     * There are no additional methods to IConfigurable interface.
      *
-     * @return configurable `IConfigurable` instance. This must not be null.
+     * Component interfaces have no states.
+     *
+     * The name of the component or component interface object is a unique name
+     * for that component or component interface 'class'; however, multiple
+     * instances of that component must have the same name.
      */
-    getConfigurable() generates (IConfigurable configurable);
 };
 
diff --git a/media/c2/1.0/IComponentListener.hal b/media/c2/1.0/IComponentListener.hal
index 70d5fb2..eb71ecb 100644
--- a/media/c2/1.0/IComponentListener.hal
+++ b/media/c2/1.0/IComponentListener.hal
@@ -17,112 +17,54 @@
 package android.hardware.media.c2@1.0;
 
 /**
- * Callback interface for handling notifications from @ref IComponent.
+ * This callback interface is used for handling notifications from IComponent.
  */
 interface IComponentListener {
 
     /**
-     * Notify the listener that some `Work` items have been completed.
-     *
-     * All the input buffers in the returned `Work` objects must not be used by
-     * the component after onWorkDone() is called.
-     *
-     * @param workBundle List of completed `Work` objects.
+     * Notify the listener that some works have been completed.
      */
     oneway onWorkDone(WorkBundle workBundle);
 
     /**
      * Notify the listener that the component is tripped.
-     *
-     * @param settingResults List of failures.
      */
     oneway onTripped(vec<SettingResult> settingResults);
 
     /**
      * Notify the listener of an error.
      *
-     * @param status Error type. @p status may be `OK`, which means that an
-     *     error has occurred, but the error type does not fit into the type
-     *     `Status`. In this case, additional information is provided by
-     *     @p errorCode.
-     * @param errorCode Additional error information. The framework may not
-     *     recognize the meaning of this value.
+     * @param status Error type. \p status may be `OK`, which means that an
+     *     error has occurred, but the error type is unknown.
+     * @param errorCode Additional error code. The framework may not recognize
+     *     this.
      */
     oneway onError(Status status, uint32_t errorCode);
 
     /**
-     * Information about rendering of a frame to a `Surface`.
+     * Information about rendering of a frame.
      */
     struct RenderedFrame {
         /**
-         * Id of the `BufferQueue` containing the rendered buffer.
-         *
-         * This value must have been obtained by an earlier call to
-         * IGraphicBufferProducer::getUniqueId().
+         * Id of the buffer queue containing the rendered buffer.
          */
         uint64_t bufferQueueId;
         /**
          * Id of the slot of the rendered buffer.
-         *
-         * This value must have been obtained by an earlier call to
-         * IGraphicBufferProducer::dequeueBuffer() or
-         * IGraphicBufferProducer::attachBuffer().
          */
         int32_t slotId;
         /**
-         * Timestamp the rendering happened.
-         *
-         * The reference point for the timestamp is determined by the
-         * `BufferQueue` that performed the rendering.
+         * Timestamp of the rendering (consistent with timestamps in
+         * the associated BufferQueue).
          */
         int64_t timestampNs;
     };
 
     /**
-     * Notify the listener that frames have been rendered.
+     * Notify the listener that frames are rendered.
      *
-     * @param renderedFrames List of @ref RenderedFrame objects.
+     * @param renderedFrames List of information about renderings of frames.
      */
     oneway onFramesRendered(vec<RenderedFrame> renderedFrames);
-
-    /**
-     * Identifying information for an input buffer previously queued to the
-     * component via IComponent::queue().
-     */
-    struct InputBuffer {
-        /**
-         * This value comes from `Work::input.ordinal.frameIndex` in a `Work`
-         * object that was previously queued.
-         */
-        uint64_t frameIndex;
-        /**
-         * This value is an index into `Work::input.buffers` (which is an array)
-         * in a `Work` object that was previously queued.
-         */
-        uint32_t arrayIndex;
-    };
-
-    /**
-     * Notify the listener that some input buffers are no longer needed by the
-     * component, and hence can be released or reused by the client.
-     *
-     * Input buffers that are contained in a `Work` object returned by an
-     * earlier onWorkDone() call are assumed released, so they must not appear
-     * in any onInputBuffersReleased() calls. That means
-     * onInputBuffersReleased() must only report input buffers that are released
-     * before the output in the same `Work` item is produced. However, it is
-     * possible for an input buffer to be returned by onWorkDone() after it has
-     * been reported by onInputBuffersReleased().
-     *
-     * @note onWorkDone() and onInputBuffersReleased() both notify the client
-     * that input buffers are no longer needed. However, in order to minimize
-     * IPC calls, onInputBuffersReleased() should be called only when
-     * onWorkDone() cannot be called, e.g., the component needs more input
-     * before an output can be produced.
-     *
-     * @param inputBuffers List of `InputBuffer` objects, identifying input
-     * buffers that are no longer needed by the component.
-     */
-    oneway onInputBuffersReleased(vec<InputBuffer> inputBuffers);
 };
 
diff --git a/media/c2/1.0/IComponentStore.hal b/media/c2/1.0/IComponentStore.hal
index a027afe..d2474cc 100644
--- a/media/c2/1.0/IComponentStore.hal
+++ b/media/c2/1.0/IComponentStore.hal
@@ -23,33 +23,27 @@
 import IConfigurable;
 import IInputSurface;
 
-/**
- * Entry point for Codec2 HAL.
- *
- * All methods in `IComponentStore` must not block. If a method call cannot be
- * completed in a timely manner, it must return `TIMED_OUT` in the return
- * status. The only exceptions are getPoolClientManager() and getConfigurable(),
- * which must always return immediately.
- */
-interface IComponentStore {
+interface IComponentStore extends IConfigurable {
 
     /**
      * Creates a component by name.
      *
-     * @param name Name of the component to create. This must match one of the
-     *     names returned by listComponents().
-     * @param listener Callback receiver.
-     * @param pool `IClientManager` object of the BufferPool in the client
-     *     process. This may be null if the client does not own a BufferPool.
-     * @return status Status of the call, which may be
-     *   - `OK`        - The component was created successfully.
-     *   - `NOT_FOUND` - There is no component with the given name.
-     *   - `NO_MEMORY` - Not enough memory to create the component.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return comp The created component if @p status is `OK`.
+     * This method must return within 100ms.
      *
-     * @sa IComponentListener.
+     * @param name Name of the component to create. This should match one of the
+     *     names returned by listComponents().
+     * @param listener The component listener to use for the component.
+     * @param pool The buffer pool client manager of the component listener.
+     *     This must be null if the listener process does not own a buffer pool.
+     * @return status Status of the call, which may be
+     *   - OK        - The component was created successfully.
+     *   - NOT_FOUND - There is no component with the given name.
+     *   - NO_MEMORY - Not enough memory to create the component.
+     *   - TIMED_OUT - The component could not be created within the time limit.
+     *                 (unexpected)
+     *   - CORRUPTED - Some unknown error prevented the creation of the
+     *                 component. (unexpected)
+     * @return comp The created component if `Status = OK`.
      */
     createComponent(
             string name,
@@ -63,15 +57,19 @@
     /**
      * Creates a component interface by name.
      *
+     * This method must return within 100ms.
+     *
      * @param name Name of the component interface to create. This should match
      *     one of the names returned by listComponents().
      * @return status Status of the call, which may be
-     *   - `OK         - The component interface was created successfully.
-     *   - `NOT_FOUND` - There is no component interface with the given name.
-     *   - `NO_MEMORY` - Not enough memory to create the component interface.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return compIntf The created component interface if @p status is `OK`.
+     *   - OK        - The component interface was created successfully.
+     *   - NOT_FOUND - There is no component interface with the given name.
+     *   - NO_MEMORY - Not enough memory to create the component interface.
+     *   - TIMED_OUT - The component interface could not be created within the
+     *                 time limit. (unexpected)
+     *   - CORRUPTED - Some unknown error prevented the creation of the
+     *                 component interface. (unexpected)
+     * @return compIntf The created component interface if `Status = OK`.
      */
     createInterface(
             string name
@@ -85,49 +83,57 @@
      */
     struct ComponentTraits {
         /**
-         * Name of the component. This must be unique for each component.
-         *
-         * This name is use to identify the component to create in
-         * createComponent() and createComponentInterface().
+         * Name of the component.
          */
         string name;
 
         enum Domain : uint32_t {
-            OTHER = 0,
-            VIDEO,
             AUDIO,
-            IMAGE,
+            VIDEO,
+            OTHER = 0xffffffff,
         };
         /**
-         * Component domain.
+         * Component domain. The framework may not recognize `OTHER`.
          */
         Domain domain;
+        /**
+         * If #domain is `OTHER`, #domainOther can be used to provide additional
+         * information. Otherwise, #domainOther is ignored. The framework may
+         * not inspect this value.
+         */
+        uint32_t domainOther;
 
         enum Kind : uint32_t {
-            OTHER = 0,
             DECODER,
             ENCODER,
+            OTHER = 0xffffffff,
         };
         /**
-         * Component kind.
+         * Component kind. The framework may not recognize `OTHER`.
          */
         Kind kind;
+        /**
+         * If #kind is `OTHER`, #kindOther can be used to provide additional
+         * information. Otherwise, #kindOther is ignored. The framework may not
+         * inspect this value.
+         */
+        uint32_t kindOther;
 
         /**
-         * Rank used by `MediaCodecList` to determine component ordering. Lower
+         * Rank used by MediaCodecList to determine component ordering. Lower
          * value means higher priority.
          */
         uint32_t rank;
 
         /**
-         * MIME type.
+         * Media type.
          */
         string mediaType;
 
         /**
          * Aliases for component name for backward compatibility.
          *
-         * Multiple components can have the same alias (but not the same
+         * \note Multiple components can have the same alias (but not the same
          * component name) as long as their media types differ.
          */
         vec<string> aliases;
@@ -136,51 +142,36 @@
     /**
      * Returns the list of components supported by this component store.
      *
-     * @return status Status of the call, which may be
-     *   - `OK         - The operation was successful.
-     *   - `NO_MEMORY` - Not enough memory to complete this method.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return traits List of component traits for all components supported by
-     *     this store (in no particular order).
+     * This method must return within 500ms.
+     *
+     * @return traits List of component traits for all components supported by this store in no
+     * particular order.
      */
-    listComponents() generates (
-            Status status,
-            vec<ComponentTraits> traits
-        );
+    listComponents() generates (vec<ComponentTraits> traits);
 
     /**
      * Creates a persistent input surface that can be used as an input surface
      * for any IComponent instance
      *
-     * @return status Status of the call, which may be
-     *   - `OK         - The operation was successful.
-     *   - `NO_MEMORY` - Not enough memory to complete this method.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return surface A persistent input surface. This may be null to indicate
-     *     an error.
+     * This method must return within 100ms.
+     *
+     * @return surface A persistent input surface
      */
-    createInputSurface() generates (
-            Status status,
-            IInputSurface surface
-        );
+    createInputSurface() generates (IInputSurface surface);
 
     /**
-     * Returns a list of `StructDescriptor` objects for a set of requested
-     * C2Param structure indices that this store is aware of.
+     * Returns a list of StructDescriptor object for a set of requested
+     * structures that this store is aware of.
      *
      * This operation must be performed at best effort, e.g. the component
      * store must simply ignore all struct indices that it is not aware of.
      *
-     * @param indices Indices of C2Param structures to describe.
+     * @param indices struct indices to return des
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `NOT_FOUND` - Some indices were not known.
-     *   - `NO_MEMORY` - Not enough memory to complete this method.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return structs List of `StructDescriptor` objects.
+     *   - OK        - The operation completed successfully.
+     *   - NOT_FOUND - Some indices were not known.
+     *   - NO_MEMORY - Not enough memory to complete this method.
+     * @return structs List of StructDescriptor objects.
      */
     getStructDescriptors(
             vec<ParamIndex> indices
@@ -190,35 +181,33 @@
         );
 
     /**
-     * Copies the contents of @p src into @p dst without changing the format of
-     * @p dst.
+     * Returns information required for using BufferPool API in buffer passing.
+     * If the returned pool is not null, the client can call registerSender() to
+     * register its IAccessor instance, hence allowing the client to send
+     * buffers to components hosted by this process.
+     *
+     * @return pool If the component store supports receiving buffers via
+     *     BufferPool API, \p pool must be a valid `IClientManager` instance.
+     *     Otherwise, \p pool must be null.
+     */
+    getPoolClientManager(
+        ) generates (
+            IClientManager pool
+        );
+
+    /**
+     * The store must copy the contents of \p src into \p dst without changing
+     * the format of \p dst.
      *
      * @param src Source buffer.
      * @param dst Destination buffer.
      * @return status Status of the call, which may be
-     *   - `OK`        - The copy is successful.
-     *   - `CANNOT_DO` - @p src and @p dst are not compatible.
-     *   - `REFUSED`   - No permission to copy.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
+     *   - OK        - The copy is successful.
+     *   - CANNOT_DO - \p src and \p dst are not compatible.
+     *   - REFUSED   - No permission to copy.
+     *   - CORRUPTED - The copy cannot be done. (unexpected)
      */
     copyBuffer(Buffer src, Buffer dst) generates (Status status);
 
-    /**
-     * Returns the `IClientManager` object for the component's BufferPool.
-     *
-     * @return pool If the component store supports receiving buffers via
-     *     BufferPool API, @p pool must be a valid `IClientManager` instance.
-     *     Otherwise, @p pool must be null.
-     */
-    getPoolClientManager() generates (IClientManager pool);
-
-    /**
-     * Returns the @ref IConfigurable instance associated to this component
-     * store.
-     *
-     * @return configurable `IConfigurable` instance. This must not be null.
-     */
-    getConfigurable() generates (IConfigurable configurable);
 };
 
diff --git a/media/c2/1.0/IConfigurable.hal b/media/c2/1.0/IConfigurable.hal
index 31dc4d3..cd4dd10 100644
--- a/media/c2/1.0/IConfigurable.hal
+++ b/media/c2/1.0/IConfigurable.hal
@@ -17,78 +17,43 @@
 package android.hardware.media.c2@1.0;
 
 /**
- * Generic configuration interface presented by all configurable Codec2 objects.
+ * Generic configuration interface used by all configurable Codec 2.0
+ * components.
  *
- * This interface must be supported in all states of the owning object, and must
- * not change the state of the owning object.
+ * This interface must be supported in all states of the inheriting
+ * object, and must not change the state of the inheriting object.
  */
 interface IConfigurable {
     /**
-     * Returns the id of the object. This must be unique among all objects of
-     * the same type hosted by the same store.
+     * Returns the name of this object. This must match the name that was
+     * supplied during the creation of the object.
      *
-     * @return id Id of the object.
-     */
-    getId() generates (uint32_t id);
-
-    /**
-     * Returns the name of the object.
-     *
-     * This must match the name that was supplied during the creation of the
-     * object.
-     *
-     * @return name Name of the object.
+     * @return name Name of this object.
      */
     getName() generates (string name);
 
     /**
-     * Queries a set of parameters from the object.
+     * Queries a set of parameters from the object. Querying is performed at
+     * best effort: the object must query all supported parameters and skip
+     * unsupported ones, or parameters that could not be allocated. Any errors
+     * are communicated in the return value.
      *
-     * Querying is performed at best effort: the object must query all supported
-     * parameters and skip unsupported ones (which may include parameters that
-     * could not be allocated). Any errors are communicated in the return value.
+     * \note Parameter values do not depend on the order of query.
      *
-     * If @p mayBlock is false, this method must not block. All parameter
-     * queries that require blocking must be skipped.
+     * This method must return within 1ms if \p mayBlock is DONT_BLOCK, and
+     * within 5ms otherwise.
      *
-     * If @p mayBlock is true, a query may block, but the whole method call
-     * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
-     *
-     * If @p mayBlock is false, this method must not block. Otherwise, this
-     * method is allowed to block for a certain period of time before completing
-     * the operation. If the operation is not completed in a timely manner,
-     * `status = TIMED_OUT` is returned.
-     *
-     * @note The order of C2Param objects in @p param does not depend on the
-     *     order of C2Param structure indices in @p indices.
-     *
-     * \par For IComponent
-     *
-     * When the object type is @ref IComponent, this method must be supported in
-     * any state except released. This call must not change the state nor the
-     * internal configuration of the component.
-     *
-     * The blocking behavior of this method differs among states:
-     *   - In the stopped state, this must be non-blocking. @p mayBlock is
-     *     ignored. (The method operates as if @p mayBlock was false.)
-     *   - In any of the running states, this method may block momentarily if
-     *     @p mayBlock is true. However, if the call cannot be completed in a
-     *     timely manner, `status = TIMED_OUT` is returned.
-     *
-     * @param indices List of C2Param structure indices to query.
+     * @param indices List of param indices for params to be queried.
      * @param mayBlock Whether this call may block or not.
      * @return status Status of the call, which may be
-     *   - `OK`        - All parameters could be queried.
-     *   - `BAD_INDEX` - All supported parameters could be queried, but some
-     *                   parameters were not supported.
-     *   - `NO_MEMORY` - Could not allocate memory for a supported parameter.
-     *   - `BLOCKING`  - Querying some parameters requires blocking, but
-     *                   @p mayBlock is false.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return params Flattened representation of C2Param objects.
-     *
-     * @sa Params.
+     *   - OK        - All parameters could be queried.
+     *   - BAD_INDEX - All supported parameters could be queried, but some
+     *                 parameters were not supported.
+     *   - NO_MEMORY - Could not allocate memory for a supported parameter.
+     *   - BLOCKING  - Querying some parameters requires blocking.
+     *   - CORRUPTED - Some unknown error prevented the querying of the
+     *                 parameters. (unexpected)
+     * @return params List of params queried corresponding to \p indices.
      */
     query(
             vec<ParamIndex> indices,
@@ -99,60 +64,31 @@
         );
 
     /**
-     * Sets a set of parameters for the object.
+     * Sets a set of parameters for the object. Tuning is performed at best
+     * effort: the object must update all supported configuration at best
+     * effort and skip unsupported parameters. Any errors are communicated in
+     * the return value and in \p failures.
      *
-     * Tuning is performed at best effort: the object must update all supported
-     * configurations at best effort and skip unsupported parameters. Any errors
-     * are communicated in the return value and in @p failures.
+     * \note Parameter tuning DOES depend on the order of the tuning parameters.
+     * E.g. some parameter update may allow some subsequent parameter update.
      *
-     * A non-strict parameter update with an unsupported value shall cause an
-     * update to the closest supported value. A strict parameter update with an
-     * unsupported value shall be skipped and a failure shall be returned.
-     *
-     * If @p mayBlock is false, this method must not block. An update that
-     * requires blocking shall be skipped and a failure shall be returned.
-     *
-     * If @p mayBlock is true, an update may block, but the whole method call
-     * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
-     *
-     * The final values for all parameters set are propagated back to the caller
-     * in @p params.
-     *
-     * \par For IComponent
-     *
-     * When the object type is @ref IComponent, this method must be supported in
-     * any state except released.
-     *
-     * The blocking behavior of this method differs among states:
-     *   - In the stopped state, this must be non-blocking. @p mayBlock is
-     *     ignored. (The method operates as if @p mayBlock was false.)
-     *   - In any of the running states, this method may block momentarily if
-     *     @p mayBlock is true. However, if the call cannot be completed in a
-     *     timely manner, `status = TIMED_OUT` is returned.
-     *
-     * @note Parameter tuning @e does depend on the order of the tuning
-     * parameters, e.g., some parameter update may enable some subsequent
-     * parameter update.
+     * This method must return within 1ms if \p mayBlock is false, and within
+     * 5ms otherwise.
      *
      * @param inParams Requested parameter updates.
      * @param mayBlock Whether this call may block or not.
      * @return status Status of the call, which may be
-     *   - `OK`        - All parameters could be updated successfully.
-     *   - `BAD_INDEX` - All supported parameters could be updated successfully,
-     *                   but some parameters were not supported.
-     *   - `NO_MEMORY` - Some supported parameters could not be updated
-     *                   successfully because they contained unsupported values.
-     *                   These are returned in @p failures.
-     *   - `BLOCKING`  - Setting some parameters requires blocking, but
-     *                   @p mayBlock is false.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return failures List of update failures.
-     * @return outParams Flattened representation of configured parameters. The
-     *     order of parameters in @p outParams is based on the order of
-     *     requested updates in @p inParams.
-     *
-     * @sa SettingResult.
+     *   - OK        - All parameters could be updated successfully.
+     *   - BAD_INDEX - All supported parameters could be updated successfully,
+     *                 but some parameters were not supported.
+     *   - NO_MEMORY - Some supported parameters could not be updated
+     *                 successfully because they contained unsupported values.
+     *                 These are returned in \p failures.
+     *   - BLOCKING  - Setting some parameters requires blocking.
+     *   - CORRUPTED - Some unknown error prevented the update of the
+     *                 parameters. (unexpected)
+     * @return failures List of parameter failures.
+     * @return outParams Resulting values for the configured parameters.
      */
     config(
             Params inParams,
@@ -167,19 +103,22 @@
     // =========================================================================
 
     /**
-     * Returns a list of supported parameters within a selected range of C2Param
-     * structure indices.
+     * Returns a selected range of the set of supported parameters.
      *
-     * @param start The first index of the selected range.
-     * @param count The length of the selected range.
+     * The set of supported parameters are represented in a vector with a
+     * start index of 0, and the selected range are indices into this vector.
+     * Fewer than \p count parameters are returned if the selected range is
+     * not fully/not at all part of the available vector indices.
+     *
+     * This method must return within 1ms.
+     *
+     * @param start start index of selected range
+     * @param count size of the selected
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `NO_MEMORY` - Not enough memory to complete this method.
-     * @return params List of supported parameters in the selected range. This
-     *     list may have fewer than @p count elements if some indices in the
-     *     range are not supported.
-     *
-     * @sa ParamDescriptor.
+     *   - OK        - The operation completed successfully.
+     *   - NO_MEMORY - Not enough memory to complete this method.
+     * @return params Vector containing the selected range of supported
+     *     parameters.
      */
     querySupportedParams(
             uint32_t start,
@@ -192,42 +131,23 @@
     /**
      * Retrieves the supported values for the queried fields.
      *
-     * The object must process all fields queried even if some queries fail.
+     * Upon return the object must fill in the supported
+     * values for the fields listed as well as a status for each field.
+     * Object shall process all fields queried even if some queries fail.
      *
-     * If @p mayBlock is false, this method must not block. Otherwise, this
-     * method is allowed to block for a certain period of time before completing
-     * the operation. If the operation cannot be completed in a timely manner,
-     * `status = TIMED_OUT` is returned.
+     * This method must return within 1ms if \p mayBlock is false, and within
+     * 5ms otherwise.
      *
-     * \par For IComponent
-     *
-     * When the object type is @ref IComponent, this method must be supported in
-     * any state except released.
-     *
-     * The blocking behavior of this method differs among states:
-     *   - In the stopped state, this must be non-blocking. @p mayBlock is
-     *     ignored. (The method operates as if @p mayBlock was false.)
-     *   - In any of the running states, this method may block momentarily if
-     *     @p mayBlock is true. However, if the call cannot be completed in a
-     *     timely manner, `status = TIMED_OUT` is returned.
-     *
-     * @param inFields List of field queries.
+     * @param inFields Vector of field queries.
      * @param mayBlock Whether this call may block or not.
      * @return status Status of the call, which may be
-     *   - `OK`        - The operation completed successfully.
-     *   - `BLOCKING`  - Querying some parameters requires blocking, but
-     *                   @p mayBlock is false.
-     *   - `NO_MEMORY` - Not enough memory to complete this method.
-     *   - `BAD_INDEX` - At least one field was not recognized as a component
-     *                   field.
-     *   - `BLOCKING`  - Querying some fields requires blocking, but @p mayblock
-     *                   is false.
-     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `CORRUPTED` - Some unknown error occurred.
-     * @return outFields List of supported values and results for the
-     *     supplied queries.
-     *
-     * @sa FieldSupportedValuesQuery, FieldSupportedValuesQueryResult.
+     *   - OK        - The operation completed successfully.
+     *   - BLOCKING  - Querying some parameters requires blocking.
+     *   - NO_MEMORY - Not enough memory to complete this method.
+     *   - BAD_INDEX - At least one field was not recognized as a component
+     *                 field.
+     * @return outFields Vector containing supported values and query result
+     *     for the selected fields.
      */
     querySupportedValues(
             vec<FieldSupportedValuesQuery> inFields,
diff --git a/media/c2/1.0/IInputSurface.hal b/media/c2/1.0/IInputSurface.hal
index 25c6c8e..c083a21 100644
--- a/media/c2/1.0/IInputSurface.hal
+++ b/media/c2/1.0/IInputSurface.hal
@@ -19,33 +19,43 @@
 import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
 
 import IConfigurable;
+import IComponent;
+import IInputSurfaceConnection;
 
 /**
- * Input surface for a Codec2 component.
- *
- * An <em>input surface</em> is an instance of `IInputSurface`, which may be
- * created by calling IComponentStore::createInputSurface(). Once created, the
- * client may
- *   1. write data to it via the `IGraphicBufferProducer` interface; and
- *   2. use it as input to a Codec2 encoder.
- *
- * @sa IInputSurfaceConnection, IComponentStore::createInputSurface(),
- *     IComponent::connectToInputSurface().
+ * Input surface that can be configured for the IComponent.
  */
-interface IInputSurface {
-    /**
-     * Returns the producer interface into the internal buffer queue.
-     *
-     * @return producer `IGraphicBufferProducer` instance. This must not be
-     * null.
-     */
-    getGraphicBufferProducer() generates (IGraphicBufferProducer producer);
+interface IInputSurface extends IGraphicBufferProducer {
 
     /**
-     * Returns the @ref IConfigurable instance associated to this input surface.
+     * Connects this input surface to a component.
      *
-     * @return configurable `IConfigurable` instance. This must not be null.
+     * This call must return within 100 ms.
+     *
+     * @param component The component to connect to. This must have type
+     *     IComponent.
+     * @return status Status of the call, which may be
+     *   - OK        - The operation succeeded.
+     *   - BAD_STATE - The component is in running state.
+     *   - DUPLICATE - The surface is already connected to a component.
+     *   - NO_MEMORY - Could not allocate memory to connect to the component.
+     *   - CORRUPTED - Some unknown error prevented the connection. (unexpected)
+     * @return connection Connection object that is used to disconnect
+     *     from the component.
+     */
+    connectToComponent(
+            IComponent component
+        ) generates (
+            Status status,
+            IInputSurfaceConnection connection
+        );
+
+    /**
+     * Returns the Codec 2.0 configuration object for this surface.
+     *
+     * @return configurable The configuration object for this surface.
      */
     getConfigurable() generates (IConfigurable configurable);
+
 };
 
diff --git a/media/c2/1.0/IInputSurfaceConnection.hal b/media/c2/1.0/IInputSurfaceConnection.hal
index efd9c6e..500091d 100644
--- a/media/c2/1.0/IInputSurfaceConnection.hal
+++ b/media/c2/1.0/IInputSurfaceConnection.hal
@@ -16,22 +16,20 @@
 
 package android.hardware.media.c2@1.0;
 
-import IConfigurable;
-
-/**
- * Connection between a component and an input surface.
- *
- * An instance of `IInputSurfaceConnection` contains an `IConfigurable`
- * interface for querying and configuring properties of the connection.
- */
 interface IInputSurfaceConnection {
+
     /**
-     * Returns the @ref IConfigurable instance associated to this connection.
+     * Disconnects this input surface from the component.
      *
-     * This can be used to customize the connection.
+     * This call must return within 100 ms.
      *
-     * @return configurable `IConfigurable` instance. This must not be null.
+     * @return status Status of the call, which may be
+     *   - OK        - The operation succeeded.
+     *   - BAD_STATE - The component is not in running state.
+     *   - NOT_FOUND - The surface is not connected to a component.
+     *   - CORRUPTED - Some unknown error prevented the connection. (unexpected)
      */
-    getConfigurable() generates (IConfigurable configurable);
+    disconnect() generates (Status status);
+
 };
 
diff --git a/media/c2/1.0/types.hal b/media/c2/1.0/types.hal
index 13269d2..c06b415 100644
--- a/media/c2/1.0/types.hal
+++ b/media/c2/1.0/types.hal
@@ -18,278 +18,220 @@
 
 import android.hardware.media.bufferpool@1.0::BufferStatusMessage;
 
-/**
- * Common return values for Codec2 operations.
- */
 enum Status : int32_t {
-    /** Operation completed successfully. */
+    /** operation completed successfully */
     OK        = 0,
 
     // bad input
 
-    /** Argument has invalid value (user error). */
+    /** argument has invalid value (user error) */
     BAD_VALUE = -22,
-    /** Argument uses invalid index (user error). */
+    /** argument uses invalid index (user error) */
     BAD_INDEX = -75,
-    /** Argument/Index is valid but not possible. */
+    /** argument/index is valid but not possible */
     CANNOT_DO = -2147483646,
 
     // bad sequencing of events
 
-    /** Object already exists. */
+    /** object already exists */
     DUPLICATE = -17,
-    /** Object not found. */
+    /** object not found */
     NOT_FOUND = -2,
-    /** Operation is not permitted in the current state. */
+    /** operation is not permitted in the current state */
     BAD_STATE = -38,
-    /** Operation would block but blocking is not permitted. */
+    /** operation would block but blocking is not permitted */
     BLOCKING  = -9930,
 
     // bad environment
 
-    /** Not enough memory to complete operation. */
+    /** not enough memory to complete operation */
     NO_MEMORY = -12,
-    /** Missing permission to complete operation. */
+    /** missing permission to complete operation */
     REFUSED   = -1,
 
-    /** Operation did not complete within timeout. */
+    /** operation did not complete within timeout */
     TIMED_OUT = -110,
 
     // missing functionality
 
-    /** Operation is not implemented/supported (optional only). */
+    /** operation is not implemented/supported (optional only) */
     OMITTED   = -74,
 
     // unknown fatal
 
-    /** Some unexpected error prevented the operation. */
+    /** some unexpected error prevented the operation */
     CORRUPTED = -2147483648,
 
     // uninitialized
 
-    /** Status has not been initialized. */
+    /** status has not been initialized */
     NO_INIT   = -19,
 };
 
 /**
- * C2Param structure index.
- *
- * This is a number that is unique for each C2Param structure type.
- *
- * @sa Codec 2.0 standard.
+ * Codec 2.0 parameter index
  */
 typedef uint32_t ParamIndex;
 
 /**
- * Flattened representation of C2Param objects.
+ * Codec 2.0 parameter structure
  *
- * The `Params` type is an array of bytes made up by concatenating a list of
- * C2Param objects. The start index (offset into @ref Params) of each C2Param
- * object in the list is divisible by 8. Up to 7 padding bytes may be added
- * after each C2Param object to achieve this 64-bit alignment.
- *
- * Each C2Param object has the following layout:
- * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the
- *   type of the C2Param object.
- * - 4 bytes: size of the C2Param object (unsigned 4-byte integer).
- * - (size - 8) bytes: data of the C2Param object.
- *
- * In order to interpret each C2Param object correctly, its structure must be
- * described by IComponentStore::getStructDescriptors().
- *
- * @note Please refer to the Codec 2.0 standard for the list of standard
- * parameter structures.
- *
- * @sa Codec 2.0 standard.
+ * The description of a Params is provided by supplying a ParamIndex to
+ * IComponentStore::getStructDescriptors().
  */
 typedef vec<uint8_t> Params;
 
 /**
- * Identifying information of a field relative to a known C2Param structure.
- *
- * Within a given C2Param structure, each field is uniquely identified by @ref
- * FieldId.
+ * Struct uniquely specifying a field in an arbitrary parameter structure.
  */
 struct FieldId {
-    /** Offset of the field in bytes. */
+    /** Offset of the field in bytes */
     uint32_t offset;
-    /** Size of the field in bytes. */
+    /** Size of the field in bytes */
     uint32_t size;
 };
 
 /**
- * Reference to a field in a C2Param structure.
+ * Struct representing a location of a field in a parameter with a given index.
  */
 struct ParamField {
-    /** Index of the C2Param structure. */
+    /** Index of the parameter */
     ParamIndex index;
-    /** Identifier of the field inside the C2Param structure. */
+    /** Field identifier */
     FieldId fieldId;
 };
 
 /**
- * Usage description of a C2Param structure.
- *
- * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
+ * Struct describing basic properties of a parameter with a given index.
  */
 struct ParamDescriptor {
-    /**
-     * Index of the C2Param structure being described.
-     */
+    /** Parameter index */
     ParamIndex index;
 
     enum Attrib : uint32_t {
         /**
-         * The parameter is required to be specified.
+         * Parameter is required to be specified.
          */
         REQUIRED   = 1u << 0,
         /**
-         * The parameter retains its value.
+         * Parameter retains its value.
          */
         PERSISTENT = 1u << 1,
         /**
-         * The parameter is strict.
+         * Parameter is strict.
          */
         STRICT     = 1u << 2,
         /**
-         * The parameter is publicly read-only.
+         * Parameter is publicly read-only.
          */
         READ_ONLY  = 1u << 3,
         /**
-         * The parameter must not be visible to clients.
+         * Parameter must not be visible to clients.
          */
         HIDDEN     = 1u << 4,
         /**
-         * The parameter must not be used by framework (other than testing).
+         * Parameter must not be used by framework (other than testing).
          */
         INTERNAL   = 1u << 5,
         /**
-         * The parameter is publicly constant (hence read-only).
+         * Parameter is publicly constant (hence read-only).
          */
         CONST      = 1u << 6,
     };
+    /** Parameter attributes */
     bitfield<Attrib> attrib;
 
-    /**
-     * Name of the structure. This must be unique for each structure.
-     */
+    /** Parameter name */
     string name;
 
-    /**
-     * Indices of other C2Param structures that this C2Param structure depends
-     * on.
-     */
+    /** index of other parameters that this parameter depends on */
     vec<ParamIndex> dependencies;
 };
 
-// Generic way to describe supported numeric values for Codec2 interfaces.
+// Generic way to describe supported numeric values for Codec 2.0 interfaces.
 
 /**
- * An untyped value that can fit in 64 bits, the type of which is communicated
- * via a separate channel (@ref FieldSupportedValues.type).
+ * An untyped value that can fit on 64 bits - the type of which is communicated
+ * via a separate channel (FieldType).
  */
 typedef uint64_t PrimitiveValue;
 
 /*
- * Description of supported values for a field.
+ * Generic supported values for a field.
  *
- * This can be a continuous range or a discrete set of values.
+ * This can be either a range or a set of values. The range can be linear or
+ * geometric with clear minimum and maximum values, and can have an optional
+ * step size or geometric ratio. Values can optionally represent flags.
  */
 struct FieldSupportedValues {
-    /**
-     * Used if #type is `RANGE`.
-     *
-     * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
-     * structure represents a closed interval bounded by `min` and `max`.
-     *
-     * Otherwise, the #Range structure represents a finite sequence of numbers
-     * produced from the following recurrence relation:
-     *
-     * @code
-     * v[0] = min
-     * v[i] = v[i - 1] * num / denom + step ; i >= 1
-     * @endcode
-     *
-     * Both the ratio `num / denom` and the value `step` must be positive. The
-     * last number in the sequence described by this #Range structure is the
-     * largest number in the sequence that is smaller than or equal to `max`.
-     *
-     * @note
-     * The division in the formula may truncate the result if the data type of
-     * these values is an integral type.
-     */
     struct Range {
-        /**
-         * Lower end of the range (inclusive).
-         */
         PrimitiveValue min;
-        /**
-         * Upper end of the range (inclusive).
-         */
         PrimitiveValue max;
-        /**
-         * The non-homogeneous term in the recurrence relation.
-         */
         PrimitiveValue step;
-        /**
-         * The numerator of the scale coefficient in the recurrence relation.
-         */
         PrimitiveValue num;
-        /**
-         * The denominator of the scale coefficient in the recurrence relation.
-         */
         PrimitiveValue denom;
     };
 
     enum Type : int32_t {
         /** No supported values */
-        EMPTY = 0,
-        /** Numeric range, described in a #Range structure */
+        EMPTY,
+        /** Numeric range that can be continuous or discrete */
         RANGE,
         /** List of values */
         VALUES,
         /** List of flags that can be OR-ed */
         FLAGS,
+        /** Other representations */
+        OTHER = 0xffffffff,
     };
     /**
-     * Type of the supported values.
+     * Type of the supported values. The framework may not recognize `OTHER`.
      */
     Type type;
+    /**
+     * Codec2.0 type code of the supported values.
+     *   * If #type is `OTHER`, #typeOther can be used to give more information.
+     *     In this case, the interpretation of this structure is
+     *     implementation-defined.
+     *   * For all other values of #type, #typeOther is not used.
+     * The framework may not inspect this value.
+     */
+    int32_t typeOther;
+
+    /*
+     * If #type = EMPTY, #range and #value are unused.
+     */
 
     /**
-     * When #type is #Type.RANGE, #range shall specify the range of possible
-     * values.
+     * If #type = RANGE, #range will specify the range of possible values.
      *
-     * The intended type of members of #range shall be clear in the context
-     * where `FieldSupportedValues` is used.
+     * The intended type of members of #range will be clear in the context where
+     * FieldSupportedValues is used.
      */
     Range range;
 
     /**
-     * When #type is #Type.VALUES or #Type.FLAGS, #value shall list supported
-     * values/flags.
+     * If #type is `VALUES` or `FLAGS`, #value will list supported values.
      *
-     * The intended type of components of #value shall be clear in the context
-     * where `FieldSupportedValues` is used.
+     * The intended type of components of #value will be clear in the context
+     * where FieldSupportedValues is used.
      */
     vec<PrimitiveValue> values;
 };
 
 /**
- * Supported values for a field.
+ * Supported values for a specific field.
  *
  * This is a pair of the field specifier together with an optional supported
  * values object. This structure is used when reporting parameter configuration
  * failures and conflicts.
  */
 struct ParamFieldValues {
-    /**
-     * Reference to a field or a C2Param structure.
-     */
+    /** the field or parameter */
     ParamField paramOrField;
 
     /**
-     * Optional supported values for the field if #paramOrField specifies an
+     * optional supported values for the field if paramOrField specifies an
      * actual field that is numeric (non struct, blob or string). Supported
      * values for arrays (including string and blobs) describe the supported
      * values for each element (character for string, and bytes for blobs). It
@@ -299,18 +241,18 @@
 };
 
 /**
- * Description of a field inside a C2Param structure.
+ * Field descriptor.
  */
 struct FieldDescriptor {
 
-    /** Location of the field in the C2Param structure */
+    /** Field id */
     FieldId fieldId;
 
     /**
-     * Possible types of the field.
+     * Possible types of a field.
      */
     enum Type : uint32_t {
-        NO_INIT = 0,
+        NO_INIT,
         INT32,
         UINT32,
         CNTR32,
@@ -319,227 +261,186 @@
         CNTR64,
         FLOAT,
         /**
-         * Fixed-size string (POD).
+         * Fixed-size string (POD)
          */
         STRING = 0x100,
         /**
-         * A blob has no sub-elements and can be thought of as an array of
-         * bytes. However, bytes cannot be individually addressed by clients.
+         * blobs have no sub-elements and can be thought of as byte arrays.
+         * However, bytes cannot be individually addressed by clients.
          */
         BLOB,
         /**
-         * The field is a structure that may contain other fields.
+         * Structs. Marked with this flag in addition to their coreIndex.
          */
-        STRUCT = 0x20000,
+        STRUCT_FLAG = 0x20000,
     };
     /**
      * Type of the field.
      */
     bitfield<Type> type;
 
-    /**
-     * If #type is #Type.STRUCT, #structIndex is the C2Param structure index;
-     * otherwise, #structIndex is not used.
+    /** Extent of the field */
+    uint32_t length;
+    /*
+     * Note: the last member of a param struct can be of arbitrary length (e.g.
+     * if it is T[] array, which extends to the last byte of the parameter.)
+     * This is marked with extent 0.
      */
-    ParamIndex structIndex;
 
-    /**
-     * Extent of the field.
-     * - For a non-array field, #extent is 1.
-     * - For a fixed-length array field, #extent is the length. An array field
-     *   of length 1 is indistinguishable from a non-array field.
-     * - For a variable-length array field, #extent is 0. This can only occur as
-     *   the last member of a C2Param structure.
-     */
-    uint32_t extent;
-
-    /**
-     * Name of the field. This must be unique for each field in the same
-     * structure.
-     */
+    /** Name of the field */
     string name;
-
-    /**
-     * Named value type. This is used for defining an enum value for a numeric
-     * type.
-     */
+    /** Named value type */
     struct NamedValue {
-        /**
-         * Name of the enum value. This must be unique for each enum value in
-         * the same field.
-         */
         string name;
-        /**
-         * Underlying value of the enum value. Multiple enum names may have the
-         * same underlying value.
-         */
         PrimitiveValue value;
     };
-    /**
-     * List of enum values. This is not used when #type is not one of the
-     * numeric types.
-     */
+    /** Named values for the field */
     vec<NamedValue> namedValues;
 };
 
 /**
- * Description of a C2Param structure. It consists of an index and a list of
- * `FieldDescriptor`s.
+ * Struct descriptor.
  */
 struct StructDescriptor {
-    /**
-     * Index of the structure.
-     */
+    /** Struct type */
     ParamIndex type;
-    /**
-     * List of fields in the structure.
-     *
-     * Fields are ordered by their offsets. A field that is a structure is
-     * ordered before its members.
-     */
+    /** Field descriptors for each field */
     vec<FieldDescriptor> fields;
 };
 
 /**
- * Information describing the reason the parameter settings may fail, or may be
- * overridden.
+ * Information describing the reason a parameter settings may fail, or
+ * may be overriden.
  */
 struct SettingResult {
-    /** Failure code */
+    /** Failure code (of Codec 2.0 SettingResult failure type) */
     enum Failure : uint32_t {
+        /** Parameter is read-only and cannot be set. */
+        READ_ONLY,
+        /** Parameter mismatches input data. */
+        MISMATCH,
+        /** Parameter does not accept value. */
+        BAD_VALUE,
         /** Parameter is not supported. */
         BAD_TYPE,
         /** Parameter is not supported on the specific port. */
         BAD_PORT,
         /** Parameter is not supported on the specific stream. */
         BAD_INDEX,
-        /** Parameter is read-only and cannot be set. */
-        READ_ONLY,
-        /** Parameter mismatches input data. */
-        MISMATCH,
-        /** Strict parameter does not accept value for the field at all. */
-        BAD_VALUE,
-        /**
-         * Strict parameter field value is in conflict with an/other
-         * setting(s).
-         */
+        /** Parameter is in conflict with an/other setting(s). */
         CONFLICT,
         /**
-         * Parameter field is out of range due to other settings. (This failure
-         * mode can only be used for strict calculated parameters.)
+         * Parameter is out of range due to other settings. (This failure mode
+         * can only be used for strict parameters.)
          */
         UNSUPPORTED,
         /**
-         * Field does not access the requested parameter value at all. It has
-         * been corrected to the closest supported value. This failure mode is
-         * provided to give guidance as to what are the currently supported
-         * values for this field (which may be a subset of the at-all-potential
-         * values).
-         */
-        INFO_BAD_VALUE,
-        /**
          * Requested parameter value is in conflict with an/other setting(s)
          * and has been corrected to the closest supported value. This failure
-         * mode is given to provide guidance as to what are the currently
-         * supported values as well as to optionally provide suggestion to the
-         * client as to how to enable the requested parameter value.
-         */
+         * mode is given to provide suggestion to the client as to how to enable
+         * the requested parameter value. */
         INFO_CONFLICT,
+        /**
+         * This failure mode is reported when all the above failure modes do not
+         * apply.
+         */
+        OTHER = 0xffffffff,
     };
+    /**
+     * The failure type. The framework might not recognize `OTHER`.
+     */
     Failure failure;
+    /**
+     * The failure code.
+     *   * If #failure is `OTHER`, #failureOther can be used to give more
+     *     information.
+     *   * For all other values of #failure, #failureOther is not used.
+     * The framework may not inspect this value.
+     */
+    uint32_t failureOther;
 
     /**
-     * Failing (or corrected) field or parameter and optionally, currently
-     * supported values for the field. Values must only be set for field
-     * failures other than `BAD_VALUE`, and only if they are different from the
-     * globally supported values (e.g. due to restrictions by another parameter
-     * or input data).
+     * Failing (or corrected) field. Currently supported values for the field.
+     * This is set if different from the globally supported values (e.g. due to
+     * restrictions by another param or input data)
      */
     ParamFieldValues field;
 
     /**
-     * Conflicting parameters or fields with (optional) suggested values for any
-     * conflicting fields to avoid the conflict. Values must only be set for
-     * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code.
+     * Conflicting parameters or fields with
+     * (optional) suggested values for any conflicting fields to avoid the conflict.
      */
     vec<ParamFieldValues> conflicts;
 };
 
 /**
- * Ordering information of @ref FrameData objects. Each member is used for
- * comparing urgency: a smaller difference from a reference value indicates that
- * the associated Work object is more urgent. The reference value for each
- * member is initialized the first time it is communicated between the client
- * and the codec, and it may be updated to later values that are communicated.
- *
- * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual
- * order it represents is derived by subtracting the reference value, then
- * interpreting the result as a signed number with the same storage size (using
- * two's complement).
- *
- * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
- * Codec 2.0 standard.
+ * Data structure for ordering Work objects. Each member is used for comparing
+ * urgency in the same fashion: a smaller value indicates that the associated
+ * Work object is more urgent.
  */
 struct WorkOrdinal {
     /**
-     * Timestamp in microseconds.
+     * Timestamp in microseconds - can wrap around.
      */
     uint64_t timestampUs;
     /**
-     * Frame index.
+     * Frame index - can wrap around.
      */
     uint64_t frameIndex;
     /**
-     * Component specific frame ordinal.
+     * Component specific frame ordinal - can wrap around.
      */
     uint64_t customOrdinal;
 };
 
 /**
- * Storage type for `BaseBlock`.
- *
- * A `BaseBlock` is a representation of a codec memory block. Coded data,
- * decoded data, codec-specific data, and other codec-related data are all sent
- * in the form of BaseBlocks.
+ * A structure that holds information of a Block. There are two types of Blocks:
+ * NATIVE and POOLED. Each type has its own way of identifying blocks.
  */
-safe_union BaseBlock {
+struct BaseBlock {
+    enum Type : int32_t {
+        NATIVE,
+        POOLED,
+    };
     /**
-     * #nativeBlock is the opaque representation of a buffer.
+     * There are two types of blocks: NATIVE and POOLED.
+     */
+    Type type;
+
+    /**
+     * A "NATIVE" block is represented by a native handle.
      */
     handle nativeBlock;
-    /**
-     * #pooledBlock is a reference to a buffer handled by a BufferPool.
+
+    /*
+     * A "POOLED" block is represented by `BufferStatusMessage`.
      */
     BufferStatusMessage pooledBlock;
 };
 
 /**
- * Reference to a @ref BaseBlock within a @ref WorkBundle.
- *
- * `Block` contains additional attributes that `BaseBlock` does not. These
- * attributes may differ among `Block` objects that refer to the same
- * `BaseBlock` in the same `WorkBundle`.
+ * A Block in transfer consists of an index into an array of BaseBlock plus some
+ * extra information. One BaseBlock may occur in multiple blocks in one
+ * `WorkBundle`.
  */
 struct Block {
     /**
-     * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into
-     * #WorkBundle.baseBlocks.
+     * Identity of the BaseBlock within a WorkBundle. This is an index into the
+     * `baseBlocks` array of a `WorkBundle` object.
      */
     uint32_t index;
     /**
-     * Metadata associated with this `Block`.
+     * Metadata associated with the block.
      */
     Params meta;
     /**
-     * Fence for synchronizing `Block` access.
+     * Fence for synchronizing block access.
      */
     handle fence;
 };
 
 /**
- * A codec buffer, which is a collection of @ref Block objects and metadata.
- *
- * This is a part of @ref FrameData.
+ * Type of buffers processed by a component.
  */
 struct Buffer {
     /**
@@ -553,37 +454,23 @@
 };
 
 /**
- * An extension of @ref Buffer that also contains a C2Param structure index.
- *
- * This is a part of @ref FrameData.
+ * An extension of Buffer that also contains an index.
  */
 struct InfoBuffer {
-    /**
-     * A C2Param structure index.
-     */
     ParamIndex index;
-    /**
-     * Associated @ref Buffer object.
-     */
     Buffer buffer;
 };
 
 /**
- * Data for an input frame or an output frame.
- *
- * This structure represents a @e frame with its metadata. A @e frame consists
- * of an ordered set of buffers, configuration changes, and info buffers along
- * with some non-configuration metadata.
- *
- * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
- * standard.
+ * This structure represents a frame with its metadata. A frame consists of an
+ * ordered set of buffers, configuration changes, and info buffers along with
+ * some non-configuration metadata.
  */
 struct FrameData {
     enum Flags : uint32_t {
         /**
-         * For input frames: no output frame shall be generated when processing
+         * For input frames: no output frame will be generated when processing
          * this frame, but metadata must still be processed.
-         *
          * For output frames: this frame must be discarded but metadata is still
          * valid.
          */
@@ -595,183 +482,92 @@
         END_OF_STREAM = (1 << 1),
         /**
          * This frame must be discarded with its metadata.
-         *
-         * This flag is only set by components, e.g. as a response to the flush
+         * This flag is only set by components - e.g. as a response to the flush
          * command.
          */
         DISCARD_FRAME = (1 << 2),
         /**
-         * This frame is not the last frame produced for the input.
-         *
-         * This flag is normally set by the component - e.g. when an input frame
-         * results in multiple output frames, this flag is set on all but the
-         * last output frame.
-         *
-         * Also, when components are chained, this flag should be propagated
-         * down the work chain. That is, if set on an earlier frame of a
-         * work-chain, it should be propagated to all later frames in that
-         * chain. Additionally, components down the chain could set this flag
-         * even if not set earlier, e.g. if multiple output frames are generated
-         * at that component for the input frame.
-         */
-        FLAG_INCOMPLETE = (1 << 3),
-        /**
          * This frame contains only codec-specific configuration data, and no
          * actual access unit.
          *
-         * @deprecated Pass codec configuration with the codec-specific
+         * \deprecated Pass codec configuration with the codec-specific
          * configuration info together with the access unit.
          */
         CODEC_CONFIG  = (1u << 31),
     };
 
     /**
-     * Frame flags, as described in #Flags.
+     * Frame flags.
      */
     bitfield<Flags> flags;
 
     /**
-     * @ref WorkOrdinal of the frame.
+     * Ordinal of the frame.
      */
     WorkOrdinal ordinal;
 
     /**
-     * List of frame buffers.
+     * Frame buffers.
      */
     vec<Buffer> buffers;
 
     /**
-     * List of configuration updates.
+     * Params determining a configuration update.
      */
     Params configUpdate;
 
     /**
-     * List of info buffers.
+     * Info buffers.
      */
     vec<InfoBuffer> infoBuffers;
 };
 
 /**
- * In/out structure containing some instructions for and results from output
- * processing.
- *
- * This is a part of @ref Work. One `Worklet` corresponds to one output
- * @ref FrameData. The client must construct an original `Worklet` object inside
- * a @ref Work object for each expected output before calling
- * IComponent::queue().
+ * Struct for
  */
 struct Worklet {
     /**
-     * Component id. (Input)
-     *
-     * This is used only when tunneling is enabled.
-     *
-     * When used, this must match the return value from IConfigurable::getId().
+     * List of Params describing tunings.
      */
-    uint32_t componentId;
+    vec<Params> tunings;
 
     /**
-     * List of C2Param objects describing tunings to be applied before
-     * processing this `Worklet`. (Input)
-     */
-    Params tunings;
-
-    /**
-     * Flag determining whether this `Worklet` has output or not.
-     */
-    bool hasOutput;
-
-    /**
-     * List of failures. (Output)
+     * List of failures.
      */
     vec<SettingResult> failures;
 
     /**
-     * Output frame data. (Output)
+     * Output frame data.
      */
     FrameData output;
+
+    /* Note: Component id is not necessary as tunneling is not supported. */
 };
 
 /**
- * A collection of input data to and output data from the component.
- *
- * A `Work` object holds information about a single work item. It is created by
- * the client and passed to the component via IComponent::queue(). The component
- * has two ways of returning a `Work` object to the client:
- *   1. If the queued `Work` object has been successfully processed,
- *      IComponentListener::onWorkDone() shall be called to notify the listener,
- *      and the output shall be included in the returned `Work` object.
- *   2. If the client calls IComponent::flush(), a `Work` object that has not
- *      been processed shall be returned.
- *
- * `Work` is a part of @ref WorkBundle.
+ * This structure holds information about a single work item. It must be passed
+ * by the client to the component.
  */
 struct Work {
     /**
-     * Additional work chain info not part of this work.
-     */
-    Params chainInfo;
-
-    /**
-     * @ref FrameData for the input.
+     * FrameData for the input. Indices of Blocks inside #input refer to
+     * BaseBlocks in the member `blocks` of the containing `WorkBundle`.
      */
     FrameData input;
-
     /**
-     * The chain of `Worklet`s.
-     *
-     * The length of #worklets is 1 when tunneling is not enabled.
-     *
-     * If #worklets has more than a single element, the tunnels between
-     * successive components of the work chain must have been successfully
-     * pre-registered at the time that the `Work` is submitted. Allocating the
-     * output buffers in the `Worklet`s is the responsibility of each component
-     * in the chain.
-     *
-     * Upon `Work` submission, #worklets must be an appropriately sized vector
-     * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a
-     * successful processing, all but the final `Worklet` in the returned
-     * #worklets must have @ref Worklet.hasOutput set to `false`.
+     * Worklet. Indices of Blocks inside `worklet.output` refer to
+     * BaseBlocks in the member `blocks` of the containing `WorkBundle`.
      */
-    vec<Worklet> worklets;
-
+    Worklet worklet;
     /**
-     * The number of `Worklet`s successfully processed in this chain.
-     *
-     * This must be initialized to 0 by the client when the `Work` is submitted,
-     * and it must contain the number of `Worklet`s that were successfully
-     * processed when the `Work` is returned to the client.
-     *
-     * #workletsProcessed cannot exceed the length of #worklets. If
-     * #workletsProcessed is smaller than the length of #worklets, #result
-     * cannot be `OK`.
+     * Whether the worklet was processed or not.
      */
-    uint32_t workletsProcessed;
-
-    /**
-     * The final outcome of the `Work` (corresponding to #workletsProcessed).
-     *
-     * The value of @ref Status.OK implies that all `Worklet`s have been
-     * successfully processed.
-     */
+    bool workletProcessed;
     Status result;
 };
 
 /**
- * List of `Work` objects.
- *
- * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and
- * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of
- * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work`
- * objects together provides two benefits:
- *   1. Batching of `Work` objects can reduce the number of IPC calls.
- *   2. If multiple `Work` objects contain `Block`s that refer to the same
- *      `BaseBlock`, the number of `BaseBlock`s that is sent between processes
- *      is also reduced.
- *
- * @note `WorkBundle` is the HIDL counterpart of the vector of `C2Work` in the
- * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the
- * data transferred over an IPC.
+ * This structure holds a list of Work objects and a list of BaseBlocks.
  */
 struct WorkBundle {
     /**
@@ -785,48 +581,27 @@
 };
 
 /**
- * Query information for supported values of a field. This is used as input to
- * IConfigurable::querySupportedValues().
+ * This structure describes a query for supported values of a field. This is
+ * used as input to IConfigurable::queryFieldSupportedValues().
  */
 struct FieldSupportedValuesQuery {
-    /**
-     * Identity of the field to query.
-     */
-    ParamField field;
-
     enum Type : uint32_t {
-        /** Query all possible values regardless of other settings. */
+        /** Query all possible values regardless of other settings */
         POSSIBLE,
-        /** Query currently possible values given dependent settings. */
+        /** Query currently possible values given dependent settings */
         CURRENT,
     };
-    /**
-     * Type of the query. See #Type for more information.
-     */
+
+    ParamField field;
     Type type;
 };
 
 /**
  * This structure is used to hold the result from
- * IConfigurable::querySupportedValues().
+ * IConfigurable::queryFieldSupportedValues().
  */
 struct FieldSupportedValuesQueryResult {
-    /**
-     * Result of the query. Possible values are
-     * - `OK`: The query was successful.
-     * - `BAD_STATE`: The query was requested when the `IConfigurable` instance
-     *   was in a bad state.
-     * - `BAD_INDEX`: The requested field was not recognized.
-     * - `TIMED_OUT`: The query could not be completed in a timely manner.
-     * - `BLOCKING`: The query must block, but the parameter `mayBlock` in the
-     *   call to `querySupportedValues()` was `false`.
-     * - `CORRUPTED`: Some unknown error occurred.
-     */
     Status status;
-
-    /**
-     * Supported values. This is meaningful only when #status is `OK`.
-     */
     FieldSupportedValues values;
 };
 
diff --git a/media/omx/1.0/vts/functional/audio/Android.bp b/media/omx/1.0/vts/functional/audio/Android.bp
index f517fa1..7418bb4 100644
--- a/media/omx/1.0/vts/functional/audio/Android.bp
+++ b/media/omx/1.0/vts/functional/audio/Android.bp
@@ -21,6 +21,7 @@
         "VtsHalMediaOmxV1_0TargetAudioEncTest.cpp",
         "media_audio_hidl_test_common.cpp"
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -30,6 +31,7 @@
         "VtsHalMediaOmxV1_0TargetAudioDecTest.cpp",
         "media_audio_hidl_test_common.cpp"
     ],
+    test_suites: ["general-tests"],
 }
 
 
diff --git a/media/omx/1.0/vts/functional/component/Android.bp b/media/omx/1.0/vts/functional/component/Android.bp
index f76b6e9..970eabe 100644
--- a/media/omx/1.0/vts/functional/component/Android.bp
+++ b/media/omx/1.0/vts/functional/component/Android.bp
@@ -18,5 +18,6 @@
     name: "VtsHalMediaOmxV1_0TargetComponentTest",
     defaults: ["VtsHalMediaOmxV1_0Defaults"],
     srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp
index 4a45e69..cf3f15d 100644
--- a/media/omx/1.0/vts/functional/master/Android.bp
+++ b/media/omx/1.0/vts/functional/master/Android.bp
@@ -18,5 +18,6 @@
     name: "VtsHalMediaOmxV1_0TargetMasterTest",
     defaults: ["VtsHalMediaOmxV1_0Defaults"],
     srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/media/omx/1.0/vts/functional/video/Android.bp b/media/omx/1.0/vts/functional/video/Android.bp
index f0da2b3..c7e0424 100644
--- a/media/omx/1.0/vts/functional/video/Android.bp
+++ b/media/omx/1.0/vts/functional/video/Android.bp
@@ -21,6 +21,7 @@
         "VtsHalMediaOmxV1_0TargetVideoDecTest.cpp",
         "media_video_hidl_test_common.cpp"
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -33,4 +34,5 @@
     static_libs: [
         "libnativewindow",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/memtrack/1.0/vts/functional/Android.bp b/memtrack/1.0/vts/functional/Android.bp
index 2d833e7..d682e0b 100644
--- a/memtrack/1.0/vts/functional/Android.bp
+++ b/memtrack/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalMemtrackV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.memtrack@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 234527a..dd6f934 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -81,4 +81,5 @@
         "BasicTests.cpp",
         "GeneratedTests.cpp",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 07c9b6e..3f0c256 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -21,6 +21,7 @@
     srcs: [
         "GeneratedTestsV1_0.cpp",
     ],
+    test_suites: ["general-tests"],
 }
 
 // Tests for V1_1 models.
@@ -31,4 +32,5 @@
         "BasicTests.cpp",
         "GeneratedTests.cpp",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index 22d0002..fe9b312 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -33,15 +33,13 @@
     /**
      * A tensor of 16 bit signed integers that represent real numbers.
      *
-     * Attached to this tensor are two numbers that are used to convert the 16
-     * bit integer to the real value and vice versa. These two numbers are:
-     * - scale: a 32 bit floating point value greater than zero.
-     * - zeroPoint: a 32 bit integer, in range [-32768, 32767].
+     * Attached to this tensor is a number representing real value scale that is
+     * used to convert the 16 bit number to a real value in the following way:
+     * realValue = integerValue * scale.
      *
-     * The formula is:
-     * realValue = (integerValue - zeroPoint) * scale.
+     * scale is a 32 bit floating point with value greater then zero.
      */
-    TENSOR_QUANT16_ASYMM = 7,
+    TENSOR_QUANT16_SYMM = 7,
     /** A tensor of 16 bit floating point values. */
     TENSOR_FLOAT16 = 8,
 };
@@ -115,6 +113,8 @@
     UNIDIRECTIONAL_SEQUENCE_LSTM = 85,
     UNIDIRECTIONAL_SEQUENCE_RNN = 86,
     ROTATED_BBOX_TRANSFORM = 87,
+    ABS = 88,
+    ROI_POOLING = 89,
 };
 
 /**
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 085d5db..5b119ee 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -20,7 +20,8 @@
     defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
     srcs: [
         "GeneratedTestsV1_0.cpp",
-    ]
+    ],
+    test_suites: ["general-tests"],
 }
 
 // Tests for V1_1 models using the V1_2 HAL.
@@ -30,6 +31,7 @@
     srcs: [
         "GeneratedTestsV1_1.cpp",
     ],
+    test_suites: ["general-tests"],
 }
 
 // Tests for V1_2 models.
@@ -40,4 +42,5 @@
         "BasicTests.cpp",
         "GeneratedTests.cpp",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index e309642..c4f1b5e 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -161,7 +161,7 @@
         case OperandType::TENSOR_FLOAT32:
         case OperandType::TENSOR_INT32:
         case OperandType::TENSOR_QUANT8_ASYMM:
-        case OperandType::TENSOR_QUANT16_ASYMM:
+        case OperandType::TENSOR_QUANT16_SYMM:
             return 0;
         default:
             return 0;
@@ -193,7 +193,7 @@
         case OperandType::TENSOR_INT32:
             return -1.0f;
         case OperandType::TENSOR_QUANT8_ASYMM:
-        case OperandType::TENSOR_QUANT16_ASYMM:
+        case OperandType::TENSOR_QUANT16_SYMM:
             return 0.0f;
         default:
             return 0.0f;
@@ -225,8 +225,8 @@
             return {1};
         case OperandType::TENSOR_QUANT8_ASYMM:
             return {-1, 256};
-        case OperandType::TENSOR_QUANT16_ASYMM:
-            return {-32769, 32768};
+        case OperandType::TENSOR_QUANT16_SYMM:
+            return {-32769, -1, 1, 32768};
         default:
             return {};
     }
@@ -279,7 +279,7 @@
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_QUANT8_ASYMM:
-        case OperandType::TENSOR_QUANT16_ASYMM:
+        case OperandType::TENSOR_QUANT16_SYMM:
             newOperand.dimensions =
                 operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
diff --git a/nfc/1.0/vts/functional/Android.bp b/nfc/1.0/vts/functional/Android.bp
index 3861bd4..c2e365e 100644
--- a/nfc/1.0/vts/functional/Android.bp
+++ b/nfc/1.0/vts/functional/Android.bp
@@ -21,4 +21,5 @@
     static_libs: [
         "android.hardware.nfc@1.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/nfc/1.1/vts/functional/Android.bp b/nfc/1.1/vts/functional/Android.bp
index 0ce531f..6698c5a 100644
--- a/nfc/1.1/vts/functional/Android.bp
+++ b/nfc/1.1/vts/functional/Android.bp
@@ -22,4 +22,5 @@
         "android.hardware.nfc@1.0",
         "android.hardware.nfc@1.1",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/oemlock/1.0/vts/functional/Android.bp b/oemlock/1.0/vts/functional/Android.bp
index 20737a1..28d6bf6 100644
--- a/oemlock/1.0/vts/functional/Android.bp
+++ b/oemlock/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalOemLockV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.oemlock@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/power/1.0/vts/functional/Android.bp b/power/1.0/vts/functional/Android.bp
index 45f74fc..a716f02 100644
--- a/power/1.0/vts/functional/Android.bp
+++ b/power/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalPowerV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.power@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/power/1.1/vts/functional/Android.bp b/power/1.1/vts/functional/Android.bp
index 604cd36..de75984 100644
--- a/power/1.1/vts/functional/Android.bp
+++ b/power/1.1/vts/functional/Android.bp
@@ -22,4 +22,5 @@
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/power/1.2/vts/functional/Android.bp b/power/1.2/vts/functional/Android.bp
index d615e85..f424bfa 100644
--- a/power/1.2/vts/functional/Android.bp
+++ b/power/1.2/vts/functional/Android.bp
@@ -23,4 +23,5 @@
         "android.hardware.power@1.1",
         "android.hardware.power@1.2",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/power/1.3/vts/functional/Android.bp b/power/1.3/vts/functional/Android.bp
index 34cdb60..06f6e7a 100644
--- a/power/1.3/vts/functional/Android.bp
+++ b/power/1.3/vts/functional/Android.bp
@@ -24,4 +24,5 @@
         "android.hardware.power@1.2",
         "android.hardware.power@1.3",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/power/stats/1.0/vts/functional/Android.bp b/power/stats/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..4f0b325
--- /dev/null
+++ b/power/stats/1.0/vts/functional/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "VtsHalPowerStatsV1_0TargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults"
+    ],
+    srcs: [
+        "VtsHalPowerStatsV1_0TargetTest.cpp"
+    ],
+    static_libs: [
+        "android.hardware.power.stats@1.0"
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libhidlbase",
+        "libfmq",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+    ],
+}
diff --git a/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp b/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
new file mode 100644
index 0000000..1a1230b
--- /dev/null
+++ b/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.power.stats.vts"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <inttypes.h>
+#include <algorithm>
+#include <random>
+#include <thread>
+
+namespace android {
+namespace power {
+namespace stats {
+namespace vts {
+namespace {
+
+using android::sp;
+using android::hardware::hidl_vec;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::power::stats::V1_0::EnergyData;
+using android::hardware::power::stats::V1_0::IPowerStats;
+using android::hardware::power::stats::V1_0::RailInfo;
+using android::hardware::power::stats::V1_0::Status;
+
+}  // namespace
+
+typedef hardware::MessageQueue<EnergyData, kSynchronizedReadWrite> MessageQueueSync;
+// Test environment for Power HIDL HAL.
+class PowerStatsHidlEnv : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static PowerStatsHidlEnv* Instance() {
+        static PowerStatsHidlEnv* instance = new PowerStatsHidlEnv;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IPowerStats>(); }
+};
+
+class PowerStatsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        service_ = ::testing::VtsHalHidlTargetTestBase::getService<IPowerStats>(
+            PowerStatsHidlEnv::Instance()->getServiceName<IPowerStats>());
+        ASSERT_NE(service_, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<IPowerStats> service_;
+};
+
+TEST_F(PowerStatsHidlTest, ValidateRailInfo) {
+    hidl_vec<RailInfo> rails[2];
+    Status s;
+    auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) {
+        rails[0] = rail_subsys;
+        s = status;
+    };
+    Return<void> ret = service_->getRailInfo(cb);
+    EXPECT_TRUE(ret.isOk());
+    if (s == Status::SUCCESS) {
+        /* Rails size should be non-zero on SUCCESS*/
+        ASSERT_NE(rails[0].size(), 0);
+        /* check if indices returned are unique*/
+        set<uint32_t> ids;
+        for (auto rail : rails[0]) {
+            ASSERT_TRUE(ids.insert(rail.index).second);
+        }
+        auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) {
+            rails[1] = rail_subsys;
+            s = status;
+        };
+        Return<void> ret = service_->getRailInfo(cb);
+        EXPECT_TRUE(ret.isOk());
+        ASSERT_EQ(s, Status::SUCCESS);
+        ASSERT_EQ(rails[0].size(), rails[1].size());
+        /* check if data returned by two calls to getRailInfo is same*/
+        for (int i = 0; i < rails[0].size(); i++) {
+            ASSERT_NE(rails[0][i].railName, "");
+            ASSERT_NE(rails[0][i].subsysName, "");
+            int j = 0;
+            bool match = false;
+            for (j = 0; j < rails[1].size(); j++) {
+                if (rails[0][i].index == rails[1][j].index) {
+                    ASSERT_EQ(rails[0][i].railName, rails[1][i].railName);
+                    ASSERT_EQ(rails[0][i].subsysName, rails[1][i].subsysName);
+                    match = true;
+                    break;
+                }
+            }
+            ASSERT_TRUE(match);
+        }
+    } else if (s == Status::FILESYSTEM_ERROR) {
+        ALOGI("ValidateRailInfo returned FILESYSTEM_ERROR");
+        ASSERT_EQ(rails[0].size(), 0);
+    } else if (s == Status::NOT_SUPPORTED) {
+        ALOGI("ValidateRailInfo returned NOT_SUPPORTED");
+        ASSERT_EQ(rails[0].size(), 0);
+    } else if (s == Status::INVALID_INPUT) {
+        ALOGI("ValidateRailInfo returned INVALID_INPUT");
+        ASSERT_EQ(rails[0].size(), 0);
+    } else if (s == Status::INSUFFICIENT_RESOURCES) {
+        ALOGI("ValidateRailInfo returned INSUFFICIENT_RESOURCES");
+        ASSERT_EQ(rails[0].size(), 0);
+    }
+}
+
+TEST_F(PowerStatsHidlTest, ValidateAllPowerData) {
+    hidl_vec<EnergyData> measurements[2];
+    Status s;
+    auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) {
+        measurements[0] = measure;
+        s = status;
+    };
+    Return<void> ret = service_->getEnergyData(hidl_vec<uint32_t>(), cb);
+    EXPECT_TRUE(ret.isOk());
+    if (s == Status::SUCCESS) {
+        /*measurements size should be non-zero on SUCCESS*/
+        ASSERT_NE(measurements[0].size(), 0);
+        auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) {
+            measurements[1] = measure;
+            s = status;
+        };
+        Return<void> ret = service_->getEnergyData(hidl_vec<uint32_t>(), cb);
+        EXPECT_TRUE(ret.isOk());
+        ASSERT_EQ(s, Status::SUCCESS);
+        /*Both calls should returns same amount of data*/
+        ASSERT_EQ(measurements[0].size(), measurements[1].size());
+        /*Check is energy and timestamp are monotonically increasing*/
+        for (int i = 0; i < measurements[0].size(); i++) {
+            int j;
+            for (j = 0; j < measurements[1].size(); j++) {
+                if (measurements[0][i].index == measurements[1][j].index) {
+                    EXPECT_GE(measurements[1][j].timestamp, measurements[0][i].timestamp);
+                    EXPECT_GE(measurements[1][j].energy, measurements[0][i].energy);
+                    break;
+                }
+            }
+            /*Check is indices for two call match*/
+            ASSERT_NE(j, measurements[1].size());
+        }
+    } else if (s == Status::FILESYSTEM_ERROR) {
+        ALOGI("ValidateAllPowerData returned FILESYSTEM_ERROR");
+        ASSERT_EQ(measurements[0].size(), 0);
+    } else if (s == Status::NOT_SUPPORTED) {
+        ALOGI("ValidateAllPowerData returned NOT_SUPPORTED");
+        ASSERT_EQ(measurements[0].size(), 0);
+    } else if (s == Status::INVALID_INPUT) {
+        ALOGI("ValidateAllPowerData returned INVALID_INPUT");
+        ASSERT_EQ(measurements[0].size(), 0);
+    } else if (s == Status::INSUFFICIENT_RESOURCES) {
+        ALOGI("ValidateAllPowerData returned INSUFFICIENT_RESOURCES");
+        ASSERT_EQ(measurements[0].size(), 0);
+    }
+}
+
+TEST_F(PowerStatsHidlTest, ValidateFilteredPowerData) {
+    hidl_vec<RailInfo> rails;
+    hidl_vec<EnergyData> measurements;
+    hidl_vec<uint32_t> indices;
+    std::string debugString;
+    Status s;
+    auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) {
+        rails = rail_subsys;
+        s = status;
+    };
+    Return<void> ret = service_->getRailInfo(cb);
+    EXPECT_TRUE(ret.isOk());
+    std::time_t seed = std::time(nullptr);
+    std::srand(seed);
+    if (s == Status::SUCCESS) {
+        size_t sz = std::max(1, (int)(std::rand() % rails.size()));
+        indices.resize(sz);
+        for (int i = 0; i < sz; i++) {
+            int j = std::rand() % rails.size();
+            indices[i] = rails[j].index;
+            debugString += std::to_string(indices[i]) + ", ";
+        }
+        debugString += "\n";
+        ALOGI("ValidateFilteredPowerData for indices: %s", debugString.c_str());
+        auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) {
+            measurements = measure;
+            s = status;
+        };
+        Return<void> ret = service_->getEnergyData(indices, cb);
+        EXPECT_TRUE(ret.isOk());
+        if (s == Status::SUCCESS) {
+            /* Make sure that all the measurements are returned */
+            ASSERT_EQ(sz, measurements.size());
+            for (int i = 0; i < measurements.size(); i++) {
+                int j;
+                bool match = false;
+                /* Check that the measurement belongs to the requested index */
+                for (j = 0; j < indices.size(); j++) {
+                    if (indices[j] == measurements[i].index) {
+                        match = true;
+                        break;
+                    }
+                }
+                ASSERT_TRUE(match);
+            }
+        }
+    } else {
+        /* size should be zero is stats is NOT SUCCESS */
+        ASSERT_EQ(rails.size(), 0);
+    }
+}
+
+void readEnergy(sp<IPowerStats> service_, uint32_t timeMs) {
+    std::unique_ptr<MessageQueueSync> mQueue;
+    Status s;
+    uint32_t railsInSample;
+    uint32_t totalSamples;
+    auto cb = [&s, &mQueue, &totalSamples, &railsInSample](
+                  const hardware::MQDescriptorSync<EnergyData>& in, uint32_t numSamples,
+                  uint32_t railsPerSample, Status status) {
+        mQueue.reset(new (std::nothrow) MessageQueueSync(in));
+        s = status;
+        totalSamples = numSamples;
+        railsInSample = railsPerSample;
+    };
+    service_->streamEnergyData(timeMs, 10, cb);
+    if (s == Status::SUCCESS) {
+        ASSERT_NE(nullptr, mQueue);
+        ASSERT_TRUE(mQueue->isValid());
+        bool rc;
+        int sampleCount = 0;
+        uint32_t totalQuants = railsInSample * totalSamples;
+        uint64_t timeout_ns = 10000000000;
+        if (totalSamples > 0) {
+            uint32_t batch = std::max(1, (int)((std::rand() % totalSamples) * railsInSample));
+            ALOGI("Read energy, timsMs: %u, batch: %u", timeMs, batch);
+            std::vector<EnergyData> data(batch);
+            while (sampleCount < totalQuants) {
+                rc = mQueue->readBlocking(&data[0], batch, timeout_ns);
+                if (rc == false) {
+                    break;
+                }
+                sampleCount = sampleCount + batch;
+                if (batch > totalQuants - sampleCount) {
+                    batch = 1;
+                }
+            }
+            ASSERT_EQ(totalQuants, sampleCount);
+        }
+    } else if (s == Status::FILESYSTEM_ERROR) {
+        ASSERT_FALSE(mQueue->isValid());
+        ASSERT_EQ(totalSamples, 0);
+        ASSERT_EQ(railsInSample, 0);
+    } else if (s == Status::NOT_SUPPORTED) {
+        ASSERT_FALSE(mQueue->isValid());
+        ASSERT_EQ(totalSamples, 0);
+        ASSERT_EQ(railsInSample, 0);
+    } else if (s == Status::INVALID_INPUT) {
+        ASSERT_FALSE(mQueue->isValid());
+        ASSERT_EQ(totalSamples, 0);
+        ASSERT_EQ(railsInSample, 0);
+    } else if (s == Status::INSUFFICIENT_RESOURCES) {
+        ASSERT_FALSE(mQueue->isValid());
+        ASSERT_EQ(totalSamples, 0);
+        ASSERT_EQ(railsInSample, 0);
+    }
+}
+
+TEST_F(PowerStatsHidlTest, StreamEnergyData) {
+    std::time_t seed = std::time(nullptr);
+    std::srand(seed);
+    std::thread thread1 = std::thread(readEnergy, service_, std::rand() % 5000);
+    thread1.join();
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(PowerStatsHidlEnv::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    PowerStatsHidlEnv::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
+
+}  // namespace vts
+}  // namespace stats
+}  // namespace power
+}  // namespace android
diff --git a/radio/1.0/vts/functional/Android.bp b/radio/1.0/vts/functional/Android.bp
index afbb1c4..9dec2f2 100644
--- a/radio/1.0/vts/functional/Android.bp
+++ b/radio/1.0/vts/functional/Android.bp
@@ -33,6 +33,7 @@
     static_libs: [
         "android.hardware.radio@1.0",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -46,6 +47,7 @@
     static_libs: [
         "android.hardware.radio@1.0",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_library_static {
diff --git a/radio/1.1/vts/functional/Android.bp b/radio/1.1/vts/functional/Android.bp
index e7195ee..5695c6b 100644
--- a/radio/1.1/vts/functional/Android.bp
+++ b/radio/1.1/vts/functional/Android.bp
@@ -30,4 +30,5 @@
     header_libs: [
         "radio.util.header@1.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/radio/1.2/vts/functional/Android.bp b/radio/1.2/vts/functional/Android.bp
index a4e8c02..6782f14 100644
--- a/radio/1.2/vts/functional/Android.bp
+++ b/radio/1.2/vts/functional/Android.bp
@@ -31,4 +31,5 @@
         "android.hardware.radio@1.0",
     ],
     header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/radio/1.3/Android.bp b/radio/1.3/Android.bp
index 3c65180..30b8edf 100644
--- a/radio/1.3/Android.bp
+++ b/radio/1.3/Android.bp
@@ -7,7 +7,6 @@
         enabled: true,
     },
     srcs: [
-        "types.hal",
         "IRadio.hal",
         "IRadioIndication.hal",
         "IRadioResponse.hal",
@@ -17,20 +16,6 @@
         "android.hardware.radio@1.1",
         "android.hardware.radio@1.2",
         "android.hidl.base@1.0",
-        "android.hidl.safe_union@1.0",
-    ],
-    types: [
-        "AccessNetwork",
-        "CellConfigLte",
-        "CellInfo",
-        "CellInfoLte",
-        "DataProfileInfo",
-        "DataRegStateResult",
-        "EmergencyNumber",
-        "EmergencyNumberSource",
-        "EmergencyServiceCategory",
-        "LteVopsInfo",
-        "NetworkScanResult",
     ],
     gen_java: true,
 }
diff --git a/radio/1.3/IRadio.hal b/radio/1.3/IRadio.hal
index dde9d71..d582c71 100644
--- a/radio/1.3/IRadio.hal
+++ b/radio/1.3/IRadio.hal
@@ -16,12 +16,7 @@
 
 package android.hardware.radio@1.3;
 
-import @1.3::DataProfileInfo;
-import @1.0::Dial;
-import @1.2::DataRequestReason;
 import @1.2::IRadio;
-import @1.3::AccessNetwork;
-import @1.3::EmergencyServiceCategory;
 
 /**
  * This interface is used by telephony and telecom to talk to cellular radio.
@@ -32,94 +27,4 @@
  * setResponseFunctions must work with @1.1::IRadioResponse and @1.1::IRadioIndication.
  */
 interface IRadio extends @1.2::IRadio {
-    /**
-     * Setup a packet data connection. If DataCallResponse.status returns DataCallFailCause:NONE,
-     * the data connection must be added to data calls and a unsolDataCallListChanged() must be
-     * sent. The call remains until removed by subsequent unsolDataCallIstChanged(). It may be
-     * lost due to many factors, including deactivateDataCall() being issued, the radio powered
-     * off, reception lost or even transient factors like congestion. This data call list is
-     * returned by getDataCallList() and dataCallListChanged().
-     *
-     * The Radio is expected to:
-     *   - Create one data call context.
-     *   - Create and configure a dedicated interface for the context.
-     *   - The interface must be point to point.
-     *   - The interface is configured with one or more addresses and is capable of sending and
-     *     receiving packets. The prefix length of the addresses must be /32 for IPv4 and /128
-     *     for IPv6.
-     *   - Must not modify routing configuration related to this interface; routing management is
-     *     exclusively within the purview of the Android OS.
-     *   - Support simultaneous data call contexts up to DataRegStateResult.maxDataCalls specified
-     *     in the response of getDataRegistrationState.
-     *
-     * @param serial Serial number of request.
-     * @param accessNetwork The access network to setup the data call. If the data connection cannot
-     *     be established on the specified access network, the setup request must be failed.
-     * @param dataProfileInfo Data profile info.
-     * @param roamingAllowed Indicates whether or not data roaming is allowed by the user.
-     * @param reason The request reason. Must be DataRequestReason.NORMAL or
-     *     DataRequestReason.HANDOVER.
-     * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
-     *     addresses of the existing data connection. The format is IP address with optional "/"
-     *     prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
-     *     "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
-     *     the prefix length is absent, then the addresses are assumed to be point to point with
-     *     IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored
-     *     unless reason is DataRequestReason.HANDOVER.
-     * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
-     *     addresses of the existing data connection. The format is defined in RFC-4291 section
-     *     2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless
-     *     reason is DataRequestReason.HANDOVER.
-     *
-     * Response function is IRadioResponse.setupDataCallResponse()
-     *
-     * Note this API is same as 1.2 version except using the 1.3 AccessNetwork as the input param.
-     */
-    oneway setupDataCall_1_3(int32_t serial, AccessNetwork accessNetwork,
-            DataProfileInfo dataProfileInfo, bool roamingAllowed,
-            DataRequestReason reason, vec<string> addresses, vec<string> dnses);
-
-    /**
-     * Set an apn to initial attach network
-     *
-     * @param serial Serial number of request.
-     * @param dataProfileInfo data profile containing APN settings
-     *
-     * Response callback is IRadioResponse.setInitialAttachApnResponse()
-     */
-    oneway setInitialAttachApn_1_3(int32_t serial, DataProfileInfo dataProfileInfo);
-
-    /**
-     * Send data profiles of the current carrier to the modem.
-     *
-     * @param serial Serial number of request.
-     * @param profiles Array of DataProfile to set.
-     *
-     * Response callback is IRadioResponse.setDataProfileResponse()
-     */
-    oneway setDataProfile_1_3(int32_t serial, vec<DataProfileInfo> profiles);
-
-    /**
-     * Initiate emergency voice call, with zero or more emergency service category(s).
-     *
-     * Note this API is the same as IRadio.dial except using the
-     * @1.3::EmergencyServiceCategory as the input param.
-     *
-     * If the dialed emergency number does not have a specified emergency service category, the
-     * 'categories' field is set to @1.3::EmergencyServiceCategory#UNSPECIFIED; iff either the
-     * 'categories' field is set to @1.3::EmergencyServiceCategory#UNSPECIFIED or the underlying
-     * technology used to request emergency services does not support the emergency service
-     * category, the interpretation of the categories is defined by implementation.
-     *
-     * Reference: 3gpp TS 22.101, Section 10 - Emergency Calls
-     *
-     * @param serial Serial number of request.
-     * @param dialInfo the same @1.0::Dial information used by @1.0::IRadio.dial.
-     * @param categories bitfield<@1.3::EmergencyServiceCategory> the Emergency Service Category(s)
-     *     of the call.
-     *
-     * Response function is IRadioResponse.emergencyDialResponse()
-     */
-    oneway emergencyDial(int32_t serial, Dial dialInfo,
-            bitfield<EmergencyServiceCategory> categories);
 };
diff --git a/radio/1.3/IRadioIndication.hal b/radio/1.3/IRadioIndication.hal
index e7f26ac..b65d3f2 100644
--- a/radio/1.3/IRadioIndication.hal
+++ b/radio/1.3/IRadioIndication.hal
@@ -16,50 +16,10 @@
 
 package android.hardware.radio@1.3;
 
-import @1.0::RadioIndicationType;
 import @1.2::IRadioIndication;
 
 /**
  * Interface declaring unsolicited radio indications.
  */
 interface IRadioIndication extends @1.2::IRadioIndication {
-    /**
-     * Report the current list of emergency numbers
-     *
-     * Each emergency number (@1.3::EmergencyNumber) in the emergency number list contains a
-     * dialing number, zero or more service category(s), mobile country code, and source(s) that
-     * indicate where it comes from.
-     *
-     * Radio must report all the valid emergency numbers with known mobile country code and
-     * emergency service categories from all available sources including network signaling, sim,
-     * modem/oem configuration, and default configuration (112 and 911 must be always available;
-     * additionally, 000, 08, 110, 999, 118 and 119 must be available when sim is not present).
-     * Radio shall not report emergency numbers that are invalid in the current locale. The
-     * reported emergency number list must not have duplicate @1.3::EmergencyNumber entries. Please
-     * refer the documentation of @1.3::EmergencyNumber to construct each emergency number to
-     * report.
-     *
-     * Radio must report the complete list of emergency numbers whenever the emergency numbers in
-     * the list are changed or whenever the client and the radio server are connected.
-     *
-     * Reference: 3gpp 22.101, Section 10 - Emergency Calls
-     *
-     * @param type Type of radio indication
-     * @param emergencyNumberList Current list of emergency numbers known to radio.
-     */
-    oneway currentEmergencyNumberList(RadioIndicationType type,
-            vec<EmergencyNumber> emergencyNumberList);
-
-    /**
-     * Request all of the current cell information known to the radio.
-     *
-     * @param type Type of radio indication
-     * @param records Current cell information
-     */
-    oneway cellInfoList_1_3(RadioIndicationType type, vec<CellInfo> records);
-
-    /**
-     * Incremental network scan results
-     */
-    oneway networkScanResult_1_3(RadioIndicationType type, NetworkScanResult result);
 };
diff --git a/radio/1.3/IRadioResponse.hal b/radio/1.3/IRadioResponse.hal
index 75d1501..2bcdd02 100644
--- a/radio/1.3/IRadioResponse.hal
+++ b/radio/1.3/IRadioResponse.hal
@@ -16,60 +16,10 @@
 
 package android.hardware.radio@1.3;
 
-import @1.0::RadioResponseInfo;
 import @1.2::IRadioResponse;
 
 /**
  * Interface declaring response functions to solicited radio requests.
  */
 interface IRadioResponse extends @1.2::IRadioResponse {
-    /**
-     * @param info Response info struct containing response type, serial no. and error
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
-     *   RadioError:DIAL_MODIFIED_TO_USSD
-     *   RadioError:DIAL_MODIFIED_TO_SS
-     *   RadioError:DIAL_MODIFIED_TO_DIAL
-     *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:NO_MEMORY
-     *   RadioError:NO_RESOURCES
-     *   RadioError:INTERNAL_ERR
-     *   RadioError:FDN_CHECK_FAILURE
-     *   RadioError:MODEM_ERR
-     *   RadioError:NO_SUBSCRIPTION
-     *   RadioError:NO_NETWORK_FOUND
-     *   RadioError:INVALID_CALL_ID
-     *   RadioError:DEVICE_IN_USE
-     *   RadioError:ABORTED
-     *   RadioError:INVALID_MODEM_STATE
-     *   RadioError:CANCELLED
-     */
-    oneway emergencyDialResponse(RadioResponseInfo info);
-
-    /**
-     * @param info Response info struct containing response type, serial no. and error
-     * @param cellInfo List of current cell information known to radio
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:INTERNAL_ERR
-     */
-    oneway getCellInfoListResponse_1_3(RadioResponseInfo info, vec<CellInfo> cellInfo);
-
-    /**
-     * @param info Response info struct containing response type, serial no. and error
-     * @param dataRegResponse Current Data registration response as defined by DataRegStateResult in
-     *        types.hal
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:INTERNAL_ERR
-     *   RadioError:NOT_PROVISIONED
-     */
-    oneway getDataRegistrationStateResponse_1_3(RadioResponseInfo info,
-            DataRegStateResult dataRegResponse);
 };
diff --git a/radio/1.4/Android.bp b/radio/1.4/Android.bp
new file mode 100644
index 0000000..02c6cad
--- /dev/null
+++ b/radio/1.4/Android.bp
@@ -0,0 +1,43 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.radio@1.4",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IRadio.hal",
+        "IRadioIndication.hal",
+        "IRadioResponse.hal",
+    ],
+    interfaces: [
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    types: [
+        "AccessNetwork",
+        "CellConfigLte",
+        "CellInfo",
+        "CellInfoLte",
+        "CardStatus",
+        "DataProfileInfo",
+        "DataRegStateResult",
+        "EmergencyNumber",
+        "EmergencyNumberSource",
+        "EmergencyServiceCategory",
+        "FrequencyRange",
+        "RadioFrequencyInfo",
+        "RadioTechnology",
+        "PhysicalChannelConfig",
+        "LteVopsInfo",
+        "NetworkScanResult",
+    ],
+    gen_java: true,
+}
+
diff --git a/radio/1.4/IRadio.hal b/radio/1.4/IRadio.hal
new file mode 100644
index 0000000..1b6d9a6
--- /dev/null
+++ b/radio/1.4/IRadio.hal
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio@1.4;
+
+import @1.4::DataProfileInfo;
+import @1.0::Dial;
+import @1.2::DataRequestReason;
+import @1.3::IRadio;
+import @1.4::AccessNetwork;
+import @1.4::EmergencyServiceCategory;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ * setResponseFunctions must work with @1.1::IRadioResponse and @1.1::IRadioIndication.
+ */
+interface IRadio extends @1.3::IRadio {
+    /**
+     * Setup a packet data connection. If DataCallResponse.status returns DataCallFailCause:NONE,
+     * the data connection must be added to data calls and a unsolDataCallListChanged() must be
+     * sent. The call remains until removed by subsequent unsolDataCallIstChanged(). It may be
+     * lost due to many factors, including deactivateDataCall() being issued, the radio powered
+     * off, reception lost or even transient factors like congestion. This data call list is
+     * returned by getDataCallList() and dataCallListChanged().
+     *
+     * The Radio is expected to:
+     *   - Create one data call context.
+     *   - Create and configure a dedicated interface for the context.
+     *   - The interface must be point to point.
+     *   - The interface is configured with one or more addresses and is capable of sending and
+     *     receiving packets. The prefix length of the addresses must be /32 for IPv4 and /128
+     *     for IPv6.
+     *   - Must not modify routing configuration related to this interface; routing management is
+     *     exclusively within the purview of the Android OS.
+     *   - Support simultaneous data call contexts up to DataRegStateResult.maxDataCalls specified
+     *     in the response of getDataRegistrationState.
+     *
+     * @param serial Serial number of request.
+     * @param accessNetwork The access network to setup the data call. If the data connection cannot
+     *     be established on the specified access network, the setup request must be failed.
+     * @param dataProfileInfo Data profile info.
+     * @param roamingAllowed Indicates whether or not data roaming is allowed by the user.
+     * @param reason The request reason. Must be DataRequestReason.NORMAL or
+     *     DataRequestReason.HANDOVER.
+     * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
+     *     addresses of the existing data connection. The format is IP address with optional "/"
+     *     prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
+     *     "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
+     *     the prefix length is absent, then the addresses are assumed to be point to point with
+     *     IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored
+     *     unless reason is DataRequestReason.HANDOVER.
+     * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
+     *     addresses of the existing data connection. The format is defined in RFC-4291 section
+     *     2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless
+     *     reason is DataRequestReason.HANDOVER.
+     *
+     * Response function is IRadioResponse.setupDataCallResponse()
+     *
+     * Note this API is same as 1.2 version except using the 1.4 AccessNetwork as the input param.
+     */
+    oneway setupDataCall_1_4(int32_t serial, AccessNetwork accessNetwork,
+            DataProfileInfo dataProfileInfo, bool roamingAllowed,
+            DataRequestReason reason, vec<string> addresses, vec<string> dnses);
+
+    /**
+     * Set an apn to initial attach network
+     *
+     * @param serial Serial number of request.
+     * @param dataProfileInfo data profile containing APN settings
+     *
+     * Response callback is IRadioResponse.setInitialAttachApnResponse()
+     */
+    oneway setInitialAttachApn_1_4(int32_t serial, DataProfileInfo dataProfileInfo);
+
+    /**
+     * Send data profiles of the current carrier to the modem.
+     *
+     * @param serial Serial number of request.
+     * @param profiles Array of DataProfile to set.
+     *
+     * Response callback is IRadioResponse.setDataProfileResponse()
+     */
+    oneway setDataProfile_1_4(int32_t serial, vec<DataProfileInfo> profiles);
+
+    /**
+     * Initiate emergency voice call, with zero or more emergency service category(s).
+     *
+     * Note this API is the same as IRadio.dial except using the
+     * @1.4::EmergencyServiceCategory as the input param.
+     *
+     * If the dialed emergency number does not have a specified emergency service category, the
+     * 'categories' field is set to @1.4::EmergencyServiceCategory#UNSPECIFIED; iff either the
+     * 'categories' field is set to @1.4::EmergencyServiceCategory#UNSPECIFIED or the underlying
+     * technology used to request emergency services does not support the emergency service
+     * category, the interpretation of the categories is defined by implementation.
+     *
+     * Reference: 3gpp TS 22.101, Section 10 - Emergency Calls
+     *
+     * @param serial Serial number of request.
+     * @param dialInfo the same @1.0::Dial information used by @1.0::IRadio.dial.
+     * @param categories bitfield<@1.4::EmergencyServiceCategory> the Emergency Service Category(s)
+     *     of the call.
+     *
+     * Response function is IRadioResponse.emergencyDialResponse()
+     */
+    oneway emergencyDial(int32_t serial, Dial dialInfo,
+            bitfield<EmergencyServiceCategory> categories);
+};
diff --git a/radio/1.4/IRadioIndication.hal b/radio/1.4/IRadioIndication.hal
new file mode 100644
index 0000000..fac77f7
--- /dev/null
+++ b/radio/1.4/IRadioIndication.hal
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio@1.4;
+
+import @1.0::RadioIndicationType;
+import @1.3::IRadioIndication;
+
+/**
+ * Interface declaring unsolicited radio indications.
+ */
+interface IRadioIndication extends @1.3::IRadioIndication {
+    /**
+     * Report the current list of emergency numbers
+     *
+     * Each emergency number (@1.4::EmergencyNumber) in the emergency number list contains a
+     * dialing number, zero or more service category(s), mobile country code, and source(s) that
+     * indicate where it comes from.
+     *
+     * Radio must report all the valid emergency numbers with known mobile country code and
+     * emergency service categories from all available sources including network signaling, sim,
+     * modem/oem configuration, and default configuration (112 and 911 must be always available;
+     * additionally, 000, 08, 110, 999, 118 and 119 must be available when sim is not present).
+     * Radio shall not report emergency numbers that are invalid in the current locale. The
+     * reported emergency number list must not have duplicate @1.4::EmergencyNumber entries. Please
+     * refer the documentation of @1.4::EmergencyNumber to construct each emergency number to
+     * report.
+     *
+     * Radio must report the complete list of emergency numbers whenever the emergency numbers in
+     * the list are changed or whenever the client and the radio server are connected.
+     *
+     * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+     *
+     * @param type Type of radio indication
+     * @param emergencyNumberList Current list of emergency numbers known to radio.
+     */
+    oneway currentEmergencyNumberList(RadioIndicationType type,
+            vec<EmergencyNumber> emergencyNumberList);
+
+    /**
+     * Request all of the current cell information known to the radio.
+     *
+     * @param type Type of radio indication
+     * @param records Current cell information
+     */
+    oneway cellInfoList_1_4(RadioIndicationType type, vec<CellInfo> records);
+
+    /**
+     * Incremental network scan results
+     */
+    oneway networkScanResult_1_4(RadioIndicationType type, NetworkScanResult result);
+
+    /**
+     * Indicates physical channel configurations.
+     *
+     * An empty configs list indicates that the radio is in idle mode.
+     *
+     * @param type Type of radio indication
+     * @param configs Vector of PhysicalChannelConfigs
+     */
+    oneway currentPhysicalChannelConfigs_1_4(RadioIndicationType type,
+            vec<PhysicalChannelConfig> configs);
+};
\ No newline at end of file
diff --git a/radio/1.4/IRadioResponse.hal b/radio/1.4/IRadioResponse.hal
new file mode 100644
index 0000000..d971850
--- /dev/null
+++ b/radio/1.4/IRadioResponse.hal
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio@1.4;
+
+import @1.0::RadioResponseInfo;
+import @1.3::IRadioResponse;
+
+/**
+ * Interface declaring response functions to solicited radio requests.
+ */
+interface IRadioResponse extends @1.3::IRadioResponse {
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
+     *   RadioError:DIAL_MODIFIED_TO_USSD
+     *   RadioError:DIAL_MODIFIED_TO_SS
+     *   RadioError:DIAL_MODIFIED_TO_DIAL
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_MEMORY
+     *   RadioError:NO_RESOURCES
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:FDN_CHECK_FAILURE
+     *   RadioError:MODEM_ERR
+     *   RadioError:NO_SUBSCRIPTION
+     *   RadioError:NO_NETWORK_FOUND
+     *   RadioError:INVALID_CALL_ID
+     *   RadioError:DEVICE_IN_USE
+     *   RadioError:ABORTED
+     *   RadioError:INVALID_MODEM_STATE
+     *   RadioError:CANCELLED
+     */
+    oneway emergencyDialResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param cellInfo List of current cell information known to radio
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    oneway getCellInfoListResponse_1_4(RadioResponseInfo info, vec<CellInfo> cellInfo);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param dataRegResponse Current Data registration response as defined by DataRegStateResult in
+     *        types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NOT_PROVISIONED
+     */
+    oneway getDataRegistrationStateResponse_1_4(RadioResponseInfo info,
+            DataRegStateResult dataRegResponse);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param cardStatus ICC card status as defined by CardStatus in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NO_MEMORY
+     *   RadioError:NO_RESOURCES
+     *   RadioError:CANCELLED
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    oneway getIccCardStatusResponse_1_4(RadioResponseInfo info, CardStatus cardStatus);
+};
\ No newline at end of file
diff --git a/radio/1.3/types.hal b/radio/1.4/types.hal
similarity index 79%
rename from radio/1.3/types.hal
rename to radio/1.4/types.hal
index b161e0e..ea3c53f 100644
--- a/radio/1.3/types.hal
+++ b/radio/1.4/types.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.radio@1.3;
+package android.hardware.radio@1.4;
 
 import @1.0::ApnAuthType;
 import @1.0::ApnTypes;
@@ -23,6 +23,7 @@
 import @1.0::DataProfileInfoType;
 import @1.0::RadioAccessFamily;
 import @1.0::RadioError;
+import @1.0::RadioTechnology;
 import @1.0::RegState;
 import @1.0::TimeStampType;
 import @1.1::ScanStatus;
@@ -33,8 +34,10 @@
 import @1.2::CellInfoLte;
 import @1.2::CellInfoTdscdma;
 import @1.2::CellInfoWcdma;
+import @1.2::CardStatus;
 import @1.2::CellIdentity;
 import @1.2::DataRegStateResult;
+import @1.2::PhysicalChannelConfig;
 
 import android.hidl.safe_union@1.0::Monostate;
 
@@ -53,7 +56,7 @@
  * provided; otherwise the field ‘mcc’ must be an empty string.
  *
  * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’ and 'categories' fields.
- * Multiple @1.3::EmergencyNumberSource should be merged into the bitfield for the same
+ * Multiple @1.4::EmergencyNumberSource should be merged into the bitfield for the same
  * EmergencyNumber.
  *
  * Reference: 3GPP TS 22.101 version 9.1.0 Release 9
@@ -69,12 +72,12 @@
      */
     string mcc;
     /**
-     * The bitfield of @1.3::EmergencyServiceCategory(s). See @1.3::EmergencyServiceCategory for
+     * The bitfield of @1.4::EmergencyServiceCategory(s). See @1.4::EmergencyServiceCategory for
      * the value of each bit.
      */
     bitfield<EmergencyServiceCategory> categories;
     /**
-     * The bitfield of @1.3::EmergencyNumberSource(s). See @1.3::EmergencyNumberSource for the
+     * The bitfield of @1.4::EmergencyNumberSource(s). See @1.4::EmergencyNumberSource for the
      * value of each bit.
      */
     bitfield<EmergencyNumberSource> sources;
@@ -117,7 +120,7 @@
 };
 
 /**
- * The source to tell where the corresponding @1.3::EmergencyNumber comes from.
+ * The source to tell where the corresponding @1.4::EmergencyNumber comes from.
  *
  * Reference: 3gpp 22.101, Section 10 - Emergency Calls
  */
@@ -142,6 +145,65 @@
     DEFAULT = 1 << 3,
 };
 
+enum RadioTechnology : @1.0::RadioTechnology {
+    /** 5G NR. */
+    NR = 20,
+};
+
+/** Mapping the frequency to a rough range. */
+enum FrequencyRange : int32_t {
+    /** Indicates the frequency range is below 1GHz. */
+    LOW = 1,
+
+    /** Indicates the frequency range is between 1GHz and 3GHz. */
+    MID = 2,
+
+    /** Indicates the frequency range is between 3GHz and 6GHz. */
+    HIGH = 3,
+
+    /** Indicates the frequency range is above 6GHz (millimeter wave frequency). */
+    MMWAVE = 4,
+};
+
+safe_union RadioFrequencyInfo {
+    /** A rough frequency range. */
+    FrequencyRange range;
+
+    /** The Absolute Radio Frequency Channel Number. */
+    int32_t channelNumber;
+};
+
+struct PhysicalChannelConfig {
+    @1.2::PhysicalChannelConfig base;
+
+    /** The radio technology for this physical channel. */
+    RadioTechnology rat;
+
+    /** The radio frequency info. */
+    RadioFrequencyInfo rfInfo;
+
+    /**
+     * A list of data calls mapped to this physical channel. The context id must match the cid of
+     * @1.0::SetupDataCallResult. An empty list means the physical channel has no data call mapped
+     * to it.
+     */
+    vec<int32_t> contextIds;
+
+    /**
+     * The physical cell identifier for this cell.
+     *
+     * In UTRAN, this value is primary scrambling code. The range is [0, 511].
+     * Reference: 3GPP TS 25.213 section 5.2.2.
+     *
+     * In EUTRAN, this value is physical layer cell identity. The range is [0, 503].
+     * Reference: 3GPP TS 36.211 section 6.11.
+     *
+     * In 5G RAN, this value is physical layer cell identity. The range is [0, 1008].
+     * Reference: 3GPP TS 38.211 section 7.4.2.1.
+     */
+    uint32_t physicalCellId;
+};
+
 /**
  * Type to define the LTE specific network capabilities for voice over PS including
  * emergency and normal voice calls.
@@ -213,7 +275,7 @@
     CellConfigLte cellConfig;
 };
 
-/** Overwritten from @1.2::CellInfo in order to update the CellInfoLte to 1.3 version. */
+/** Overwritten from @1.2::CellInfo in order to update the CellInfoLte to 1.4 version. */
 struct CellInfo {
     /** Cell type for selecting from union CellInfo. */
     CellInfoType cellInfoType;
@@ -234,7 +296,7 @@
     } info;
 };
 
-/** Overwritten from @1.2::NetworkScanResult in order to update the CellInfo to 1.3 version. */
+/** Overwritten from @1.2::NetworkScanResult in order to update the CellInfo to 1.4 version. */
 struct NetworkScanResult {
     /**
      * The status of the scan.
@@ -325,3 +387,15 @@
      */
     bool persistent;
 };
+
+struct CardStatus {
+    @1.2::CardStatus base;
+    /**
+     * The EID is the eUICC identifier. The EID shall be stored within the ECASD and can be
+     * retrieved by the Device at any time using the standard GlobalPlatform GET DATA command.
+     *
+     * This data is mandatory and applicable only when cardState is CardState:PRESENT and SIM card
+     * supports eUICC.
+     */
+    string eid;
+};
diff --git a/radio/config/1.0/vts/functional/Android.bp b/radio/config/1.0/vts/functional/Android.bp
index aa8266e..9c96030 100644
--- a/radio/config/1.0/vts/functional/Android.bp
+++ b/radio/config/1.0/vts/functional/Android.bp
@@ -29,4 +29,5 @@
         "android.hardware.radio.config@1.0",
     ],
     header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/radio/config/1.1/Android.bp b/radio/config/1.1/Android.bp
index 8dc0f27..f228704 100644
--- a/radio/config/1.1/Android.bp
+++ b/radio/config/1.1/Android.bp
@@ -7,7 +7,6 @@
         enabled: true,
     },
     srcs: [
-        "types.hal",
         "IRadioConfigIndication.hal",
         "IRadioConfigResponse.hal",
     ],
@@ -16,8 +15,5 @@
         "android.hardware.radio.config@1.0",
         "android.hidl.base@1.0",
     ],
-    types: [
-        "SimSlotStatus",
-    ],
     gen_java: true,
 }
diff --git a/radio/config/1.1/IRadioConfigIndication.hal b/radio/config/1.1/IRadioConfigIndication.hal
index 53eaa4d..f919201 100644
--- a/radio/config/1.1/IRadioConfigIndication.hal
+++ b/radio/config/1.1/IRadioConfigIndication.hal
@@ -17,23 +17,9 @@
 package android.hardware.radio.config@1.1;
 
 import @1.0::IRadioConfigIndication;
-import android.hardware.radio@1.0::RadioIndicationType;
 
 /**
  * Interface declaring unsolicited radio config indications.
  */
 interface IRadioConfigIndication extends @1.0::IRadioConfigIndication {
-
-    /**
-     * Indicates SIM slot status change.
-     *
-     * This indication must be sent by the modem whenever there is any slot status change, even the
-     * slot is inactive. For example, this indication must be triggered if a SIM card is inserted
-     * into an inactive slot.
-     *
-     * @param type Type of radio indication
-     * @param slotStatus new slot status info with size equals to the number of physical slots on
-     *        the device
-     */
-    oneway simSlotsStatusChanged_1_1(RadioIndicationType type, vec<SimSlotStatus> slotStatus);
 };
diff --git a/radio/config/1.1/IRadioConfigResponse.hal b/radio/config/1.1/IRadioConfigResponse.hal
index 6f543ab..5d75600 100644
--- a/radio/config/1.1/IRadioConfigResponse.hal
+++ b/radio/config/1.1/IRadioConfigResponse.hal
@@ -16,26 +16,10 @@
 
 package android.hardware.radio.config@1.1;
 
-import android.hardware.radio@1.0::RadioResponseInfo;
 import @1.0::IRadioConfigResponse;
-import @1.1::SimSlotStatus;
 
 /**
  * Interface declaring response functions to solicited radio config requests.
  */
 interface IRadioConfigResponse extends @1.0::IRadioConfigResponse {
-
-    /**
-     * @param info Response info struct containing response type, serial no. and error
-     * @param slotStatus Sim slot struct containing all the physical SIM slots info with size
-     *        equal to the number of physical slots on the device
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:NO_MEMORY
-     *   RadioError:INTERNAL_ERR
-     *   RadioError:MODEM_ERR
-     */
-    oneway getSimSlotsStatusResponse_1_1(RadioResponseInfo info, vec<SimSlotStatus> slotStatus);
 };
diff --git a/radio/config/1.2/Android.bp b/radio/config/1.2/Android.bp
new file mode 100644
index 0000000..c1eeb35
--- /dev/null
+++ b/radio/config/1.2/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.radio.config@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IRadioConfigIndication.hal",
+        "IRadioConfigResponse.hal",
+    ],
+    interfaces: [
+        "android.hardware.radio@1.0",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "SimSlotStatus",
+    ],
+    gen_java: true,
+}
diff --git a/radio/config/1.2/IRadioConfigIndication.hal b/radio/config/1.2/IRadioConfigIndication.hal
new file mode 100644
index 0000000..a3ae558
--- /dev/null
+++ b/radio/config/1.2/IRadioConfigIndication.hal
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.config@1.2;
+
+import android.hardware.radio@1.0::RadioIndicationType;
+import @1.1::IRadioConfigIndication;
+
+/**
+ * Interface declaring unsolicited radio config indications.
+ */
+interface IRadioConfigIndication extends @1.1::IRadioConfigIndication {
+
+    /**
+     * Indicates SIM slot status change.
+     *
+     * This indication must be sent by the modem whenever there is any slot status change, even the
+     * slot is inactive. For example, this indication must be triggered if a SIM card is inserted
+     * into an inactive slot.
+     *
+     * @param type Type of radio indication
+     * @param slotStatus new slot status info with size equals to the number of physical slots on
+     *        the device
+     */
+    oneway simSlotsStatusChanged_1_2(RadioIndicationType type, vec<SimSlotStatus> slotStatus);
+};
\ No newline at end of file
diff --git a/radio/config/1.2/IRadioConfigResponse.hal b/radio/config/1.2/IRadioConfigResponse.hal
new file mode 100644
index 0000000..dbc3bc5
--- /dev/null
+++ b/radio/config/1.2/IRadioConfigResponse.hal
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.hardware.radio.config@1.2;
+
+import android.hardware.radio@1.0::RadioResponseInfo;
+import @1.1::IRadioConfigResponse;
+import @1.2::SimSlotStatus;
+
+/**
+ * Interface declaring response functions to solicited radio config requests.
+ */
+interface IRadioConfigResponse extends @1.1::IRadioConfigResponse {
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param slotStatus Sim slot struct containing all the physical SIM slots info with size
+     *        equal to the number of physical slots on the device
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:NO_MEMORY
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:MODEM_ERR
+     */
+    oneway getSimSlotsStatusResponse_1_2(RadioResponseInfo info, vec<SimSlotStatus> slotStatus);
+};
\ No newline at end of file
diff --git a/radio/config/1.1/types.hal b/radio/config/1.2/types.hal
similarity index 95%
rename from radio/config/1.1/types.hal
rename to radio/config/1.2/types.hal
index 0c9d11e..5b809a7 100644
--- a/radio/config/1.1/types.hal
+++ b/radio/config/1.2/types.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.config@1.1;
+package android.hardware.radio.config@1.2;
 
 import android.hardware.radio@1.0::CardState;
 import @1.0::SimSlotStatus;
@@ -29,4 +29,4 @@
      * supports eUICC.
      */
     string eid;
-};
+};
\ No newline at end of file
diff --git a/renderscript/1.0/vts/functional/Android.bp b/renderscript/1.0/vts/functional/Android.bp
index bf011e6..87e62f1 100644
--- a/renderscript/1.0/vts/functional/Android.bp
+++ b/renderscript/1.0/vts/functional/Android.bp
@@ -28,4 +28,5 @@
         "android.hardware.renderscript@1.0",
         "libnativewindow",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/secure_element/1.0/vts/functional/Android.bp b/secure_element/1.0/vts/functional/Android.bp
index 752df9e..2b2b73e 100644
--- a/secure_element/1.0/vts/functional/Android.bp
+++ b/secure_element/1.0/vts/functional/Android.bp
@@ -21,4 +21,5 @@
     static_libs: [
         "android.hardware.secure_element@1.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 6563e3c..d4c5f32 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -27,5 +27,6 @@
         "android.hardware.sensors@1.0",
         "VtsHalSensorsTargetTestUtils",
     ],
+    test_suites: ["general-tests"],
 }
 
diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp
index 11612d3..db0b148 100644
--- a/sensors/2.0/default/Android.bp
+++ b/sensors/2.0/default/Android.bp
@@ -32,6 +32,7 @@
         "libhidlbase",
         "libhidltransport",
         "liblog",
+        "libpower",
         "libutils",
     ],
 }
diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/2.0/default/Sensor.cpp
index d3e3f7e..168b402 100644
--- a/sensors/2.0/default/Sensor.cpp
+++ b/sensors/2.0/default/Sensor.cpp
@@ -29,14 +29,20 @@
 using ::android::hardware::sensors::V1_0::SensorStatus;
 
 Sensor::Sensor(ISensorsEventCallback* callback)
-    : mIsEnabled(false), mSamplingPeriodNs(0), mLastSampleTimeNs(0), mCallback(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();
 }
 
@@ -60,6 +66,7 @@
 
 void Sensor::activate(bool enable) {
     if (mIsEnabled != enable) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
         mIsEnabled = enable;
         mWaitCV.notify_all();
     }
@@ -79,7 +86,7 @@
     ev.sensorType = SensorType::ADDITIONAL_INFO;
     ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
     std::vector<Event> evs{ev};
-    mCallback->postEvents(evs);
+    mCallback->postEvents(evs, isWakeUpSensor());
 
     return Result::OK;
 }
@@ -89,13 +96,14 @@
 }
 
 void Sensor::run() {
-    std::mutex runMutex;
-    std::unique_lock<std::mutex> runLock(runMutex);
+    std::unique_lock<std::mutex> runLock(mRunMutex);
     constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
 
     while (!mStopThread) {
-        if (!mIsEnabled) {
-            mWaitCV.wait(runLock, [&] { return mIsEnabled || mStopThread; });
+        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+            mWaitCV.wait(runLock, [&] {
+                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+            });
         } else {
             timespec curTime;
             clock_gettime(CLOCK_REALTIME, &curTime);
@@ -105,7 +113,7 @@
             if (now >= nextSampleTime) {
                 mLastSampleTimeNs = now;
                 nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
-                mCallback->postEvents(readEvents());
+                mCallback->postEvents(readEvents(), isWakeUpSensor());
             }
 
             mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
@@ -113,6 +121,10 @@
     }
 }
 
+bool Sensor::isWakeUpSensor() {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
 std::vector<Event> Sensor::readEvents() {
     std::vector<Event> events;
     Event event;
@@ -127,6 +139,33 @@
     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>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+    Result result = Result::OK;
+    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+        // environment data into the device.
+    } else if (!supportsDataInjection()) {
+        result = Result::INVALID_OPERATION;
+    } else if (mMode == OperationMode::DATA_INJECTION) {
+        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+    } else {
+        result = Result::BAD_VALUE;
+    }
+    return result;
+}
+
 AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
     mSensorInfo.sensorHandle = sensorHandle;
     mSensorInfo.name = "Accel Sensor";
@@ -142,7 +181,8 @@
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+    mSensorInfo.flags =
+        static_cast<uint32_t>(SensorFlagBits::WAKE_UP | SensorFlagBits::DATA_INJECTION);
 };
 
 }  // namespace implementation
diff --git a/sensors/2.0/default/Sensor.h b/sensors/2.0/default/Sensor.h
index 75d9aab..3ab2299 100644
--- a/sensors/2.0/default/Sensor.h
+++ b/sensors/2.0/default/Sensor.h
@@ -21,10 +21,12 @@
 
 #include <condition_variable>
 #include <memory>
+#include <mutex>
 #include <thread>
 #include <vector>
 
 using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
 using ::android::hardware::sensors::V1_0::Result;
 using ::android::hardware::sensors::V1_0::SensorInfo;
 using ::android::hardware::sensors::V1_0::SensorType;
@@ -38,7 +40,7 @@
 class ISensorsEventCallback {
    public:
     virtual ~ISensorsEventCallback(){};
-    virtual void postEvents(const std::vector<Event>& events) = 0;
+    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
 };
 
 class Sensor {
@@ -51,11 +53,17 @@
     void activate(bool enable);
     Result flush();
 
+    void setOperationMode(OperationMode mode);
+    bool supportsDataInjection() const;
+    Result injectEvent(const Event& event);
+
    protected:
     void run();
     virtual std::vector<Event> readEvents();
     static void startThread(Sensor* sensor);
 
+    bool isWakeUpSensor();
+
     bool mIsEnabled;
     int64_t mSamplingPeriodNs;
     int64_t mLastSampleTimeNs;
@@ -63,9 +71,12 @@
 
     std::atomic_bool mStopThread;
     std::condition_variable mWaitCV;
+    std::mutex mRunMutex;
     std::thread mRunThread;
 
     ISensorsEventCallback* mCallback;
+
+    OperationMode mMode;
 };
 
 class AccelSensor : public Sensor {
diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp
index cceb7d5..efc8b05 100644
--- a/sensors/2.0/default/Sensors.cpp
+++ b/sensors/2.0/default/Sensors.cpp
@@ -30,8 +30,16 @@
 using ::android::hardware::sensors::V1_0::RateLevel;
 using ::android::hardware::sensors::V1_0::Result;
 using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_0::SensorTimeout;
 
-Sensors::Sensors() : mEventQueueFlag(nullptr) {
+constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
+
+Sensors::Sensors()
+    : mEventQueueFlag(nullptr),
+      mOutstandingWakeUpEvents(0),
+      mReadWakeLockQueueRun(false),
+      mAutoReleaseWakeLockTime(0),
+      mHasWakeLock(false) {
     std::shared_ptr<AccelSensor> accel =
         std::make_shared<AccelSensor>(1 /* sensorHandle */, this /* callback */);
     mSensors[accel->getSensorInfo().sensorHandle] = accel;
@@ -39,6 +47,8 @@
 
 Sensors::~Sensors() {
     deleteEventFlag();
+    mReadWakeLockQueueRun = false;
+    mWakeLockThread.join();
 }
 
 // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
@@ -54,9 +64,11 @@
     return Void();
 }
 
-Return<Result> Sensors::setOperationMode(OperationMode /* mode */) {
-    // TODO implement
-    return Result{};
+Return<Result> Sensors::setOperationMode(OperationMode mode) {
+    for (auto sensor : mSensors) {
+        sensor.second->setOperationMode(mode);
+    }
+    return Result::OK;
 }
 
 Return<Result> Sensors::activate(int32_t sensorHandle, bool enabled) {
@@ -99,6 +111,10 @@
         result = Result::BAD_VALUE;
     }
 
+    // Start the thread to read events from the Wake Lock FMQ
+    mReadWakeLockQueueRun = true;
+    mWakeLockThread = std::thread(startReadWakeLockThread, this);
+
     return result;
 }
 
@@ -120,14 +136,18 @@
     return Result::BAD_VALUE;
 }
 
-Return<Result> Sensors::injectSensorData(const Event& /* event */) {
-    // TODO implement
-    return Result{};
+Return<Result> Sensors::injectSensorData(const Event& event) {
+    auto sensor = mSensors.find(event.sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->injectEvent(event);
+    }
+
+    return Result::BAD_VALUE;
 }
 
 Return<void> Sensors::registerDirectChannel(const SharedMemInfo& /* mem */,
                                             registerDirectChannel_cb _hidl_cb) {
-    _hidl_cb(Result::INVALID_OPERATION, 0 /* channelHandle */);
+    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
     return Return<void>();
 }
 
@@ -141,15 +161,67 @@
     return Return<void>();
 }
 
-void Sensors::postEvents(const std::vector<Event>& events) {
-    std::lock_guard<std::mutex> l(mLock);
+void Sensors::postEvents(const std::vector<Event>& events, bool wakeup) {
+    std::lock_guard<std::mutex> lock(mWriteLock);
+    if (mEventQueue->write(events.data(), events.size())) {
+        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
 
-    // TODO: read events from the Wake Lock FMQ in the right place
-    std::vector<uint32_t> tmp(mWakeLockQueue->availableToRead());
-    mWakeLockQueue->read(tmp.data(), mWakeLockQueue->availableToRead());
+        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 */);
+        }
+    }
+}
 
-    mEventQueue->write(events.data(), events.size());
-    mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+void Sensors::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>(SensorTimeout::WAKE_LOCK_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",
+                  SensorTimeout::WAKE_LOCK_SECONDS);
+            mOutstandingWakeUpEvents = 0;
+        }
+
+        if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
+            mHasWakeLock = false;
+        }
+    }
+}
+
+void Sensors::readWakeLockFMQ() {
+    while (mReadWakeLockQueueRun.load()) {
+        constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000;  // 500 ms
+        uint32_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 */, kReadTimeoutNs);
+        updateWakeLock(0 /* eventsWritten */, eventsHandled);
+    }
+}
+
+void Sensors::startReadWakeLockThread(Sensors* sensors) {
+    sensors->readWakeLockFMQ();
 }
 
 void Sensors::deleteEventFlag() {
diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h
index f543935..eba3f97 100644
--- a/sensors/2.0/default/Sensors.h
+++ b/sensors/2.0/default/Sensors.h
@@ -21,10 +21,13 @@
 
 #include <android/hardware/sensors/2.0/ISensors.h>
 #include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
+#include <atomic>
 #include <memory>
+#include <thread>
 
 namespace android {
 namespace hardware {
@@ -80,7 +83,7 @@
     Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
                                     configDirectReport_cb _hidl_cb) override;
 
-    void postEvents(const std::vector<Event>& events) override;
+    void postEvents(const std::vector<Event>& events, bool wakeup) override;
 
    private:
     /**
@@ -88,6 +91,18 @@
      */
     void deleteEventFlag();
 
+    /**
+     * Function to read the Wake Lock FMQ and release the wake lock when appropriate
+     */
+    void readWakeLockFMQ();
+
+    static void startReadWakeLockThread(Sensors* sensors);
+
+    /**
+     * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
+     */
+    void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled);
+
     using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
     using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
 
@@ -117,9 +132,39 @@
     std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
 
     /**
-     * Lock to protect writes and reads to the FMQs
+     * Lock to protect writes to the FMQs
      */
-    std::mutex mLock;
+    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 implementation
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 3e5837b..ac020ad 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -18,6 +18,7 @@
 
 #include "SensorsHidlEnvironmentV2_0.h"
 #include "sensors-vts-utils/SensorsHidlTestBase.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.h"
 
 #include <android/hardware/sensors/2.0/ISensors.h>
 #include <android/hardware/sensors/2.0/types.h>
@@ -26,6 +27,7 @@
 
 #include <cinttypes>
 #include <condition_variable>
+#include <cstring>
 #include <map>
 #include <vector>
 
@@ -34,7 +36,9 @@
 using ::android::hardware::Void;
 using ::android::hardware::sensors::V1_0::MetaDataEventType;
 using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
 using ::android::hardware::sensors::V1_0::SensorStatus;
+using ::android::hardware::sensors::V1_0::SharedMemType;
 using ::android::hardware::sensors::V1_0::Vec3;
 
 class EventCallback : public IEventCallback {
@@ -164,7 +168,17 @@
     void activateAllSensors(bool enable);
     std::vector<SensorInfo> getNonOneShotSensors();
     std::vector<SensorInfo> getOneShotSensors();
+    std::vector<SensorInfo> getInjectEventSensors();
     int32_t getInvalidSensorHandle();
+    void verifyDirectChannel(SharedMemType memType);
+    void verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+                                     std::shared_ptr<SensorsTestSharedMemory> mem,
+                                     int32_t* directChannelHandle);
+    void verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
+                         int32_t directChannelHandle);
+    void verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+                                       int32_t directChannelHandle);
+    void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
 };
 
 Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -243,6 +257,16 @@
     return sensors;
 }
 
+std::vector<SensorInfo> SensorsHidlTest::getInjectEventSensors() {
+    std::vector<SensorInfo> sensors;
+    for (const SensorInfo& info : getSensorsList()) {
+        if (info.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION)) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
 int32_t SensorsHidlTest::getInvalidSensorHandle() {
     // Find a sensor handle that does not exist in the sensor list
     int32_t maxHandle = 0;
@@ -297,63 +321,71 @@
     });
 }
 
-// Test if sensor list returned is valid
+// Test that SetOperationMode returns the expected value
 TEST_F(SensorsHidlTest, SetOperationMode) {
-    std::vector<SensorInfo> sensorList = getSensorsList();
-
-    bool needOperationModeSupport =
-        std::any_of(sensorList.begin(), sensorList.end(),
-                    [](const auto& s) { return (s.flags & SensorFlagBits::DATA_INJECTION) != 0; });
-    if (!needOperationModeSupport) {
-        return;
+    std::vector<SensorInfo> sensors = getInjectEventSensors();
+    if (getInjectEventSensors().size() > 0) {
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+    } else {
+        ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
     }
-
-    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
-    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
-    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
 }
 
-// Test if sensor list returned is valid
+// Test that an injected event is written back to the Event FMQ
 TEST_F(SensorsHidlTest, InjectSensorEventData) {
-    std::vector<SensorInfo> sensorList = getSensorsList();
-    std::vector<SensorInfo> sensorSupportInjection;
-
-    bool needOperationModeSupport =
-        std::any_of(sensorList.begin(), sensorList.end(), [&sensorSupportInjection](const auto& s) {
-            bool ret = (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
-            if (ret) {
-                sensorSupportInjection.push_back(s);
-            }
-            return ret;
-        });
-    if (!needOperationModeSupport) {
+    std::vector<SensorInfo> sensors = getInjectEventSensors();
+    if (sensors.size() == 0) {
         return;
     }
 
-    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
     ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
 
-    for (const auto& s : sensorSupportInjection) {
-        switch (s.type) {
-            case SensorType::ACCELEROMETER:
-            case SensorType::GYROSCOPE:
-            case SensorType::MAGNETIC_FIELD: {
-                usleep(100000);  // sleep 100ms
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
 
-                Event dummy;
-                dummy.timestamp = android::elapsedRealtimeNano();
-                dummy.sensorType = s.type;
-                dummy.sensorHandle = s.sensorHandle;
-                Vec3 v = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
-                dummy.u.vec3 = v;
+    // AdditionalInfo event should not be sent to Event FMQ
+    Event additionalInfoEvent;
+    additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO;
+    additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
 
-                EXPECT_EQ(Result::OK, getSensors()->injectSensorData(dummy));
-                break;
-            }
-            default:
-                break;
-        }
+    Event injectedEvent;
+    injectedEvent.timestamp = android::elapsedRealtimeNano();
+    Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+    injectedEvent.u.vec3 = data;
+
+    for (const auto& s : sensors) {
+        additionalInfoEvent.sensorHandle = s.sensorHandle;
+        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent));
+
+        injectedEvent.sensorType = s.type;
+        injectedEvent.sensorHandle = s.sensorHandle;
+        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent));
     }
+
+    // Wait for events to be written back to the Event FMQ
+    callback.waitForEvents(sensors, 1000 /* timeoutMs */);
+
+    for (const auto& s : sensors) {
+        auto events = callback.getEvents(s.sensorHandle);
+        auto lastEvent = events.back();
+
+        // 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.sensorType, s.type);
+        ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp);
+        ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x);
+        ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y);
+        ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z);
+        ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status);
+    }
+
+    getEnvironment()->unregisterCallback();
     ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
 }
 
@@ -789,6 +821,128 @@
     getEnvironment()->unregisterCallback();
 }
 
+void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
+                                     RateLevel rateLevel) {
+    configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel,
+                       [&](Result result, int32_t reportToken) {
+                           if (isDirectReportRateSupported(sensor, rateLevel)) {
+                               ASSERT_EQ(result, Result::OK);
+                               ASSERT_GT(reportToken, 0);
+                           } else {
+                               ASSERT_EQ(result, Result::BAD_VALUE);
+                           }
+                       });
+}
+
+void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+                                                  std::shared_ptr<SensorsTestSharedMemory> mem,
+                                                  int32_t* directChannelHandle) {
+    char* buffer = mem->getBuffer();
+    memset(buffer, 0xff, mem->getSize());
+
+    registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
+        if (isDirectChannelTypeSupported(sensor, memType)) {
+            ASSERT_EQ(result, Result::OK);
+            ASSERT_GT(channelHandle, 0);
+
+            // Verify that the memory has been zeroed
+            for (size_t i = 0; i < mem->getSize(); i++) {
+                ASSERT_EQ(buffer[i], 0x00);
+            }
+        } else {
+            ASSERT_EQ(result, Result::INVALID_OPERATION);
+            ASSERT_EQ(channelHandle, -1);
+        }
+        *directChannelHandle = channelHandle;
+    });
+}
+
+void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
+                                      int32_t directChannelHandle) {
+    if (isDirectChannelTypeSupported(sensor, memType)) {
+        // Verify that each rate level is properly supported
+        checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::FAST);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::STOP);
+
+        // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
+        configDirectReport(
+            -1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL,
+            [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); });
+        configDirectReport(
+            -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
+            [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
+    } else {
+        // Direct channel is not supported for this SharedMemType
+        configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
+                           [](Result result, int32_t /* reportToken */) {
+                               ASSERT_EQ(result, Result::INVALID_OPERATION);
+                           });
+    }
+}
+
+void SensorsHidlTest::verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+                                                    int32_t directChannelHandle) {
+    Result result = unregisterDirectChannel(directChannelHandle);
+    if (isDirectChannelTypeSupported(sensor, memType)) {
+        ASSERT_EQ(result, Result::OK);
+    } else {
+        ASSERT_EQ(result, Result::INVALID_OPERATION);
+    }
+}
+
+void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
+    constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+    constexpr size_t kNumEvents = 1;
+    constexpr size_t kMemSize = kNumEvents * kEventSize;
+
+    std::shared_ptr<SensorsTestSharedMemory> mem(
+        SensorsTestSharedMemory::create(memType, kMemSize));
+    ASSERT_NE(mem, nullptr);
+
+    for (const SensorInfo& sensor : getSensorsList()) {
+        int32_t directChannelHandle = 0;
+        verifyRegisterDirectChannel(sensor, memType, mem, &directChannelHandle);
+        verifyConfigure(sensor, memType, directChannelHandle);
+        verifyUnregisterDirectChannel(sensor, memType, directChannelHandle);
+    }
+}
+
+TEST_F(SensorsHidlTest, DirectChannelAshmem) {
+    verifyDirectChannel(SharedMemType::ASHMEM);
+}
+
+TEST_F(SensorsHidlTest, DirectChannelGralloc) {
+    verifyDirectChannel(SharedMemType::GRALLOC);
+}
+
+TEST_F(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
+    for (const SensorInfo& sensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(sensor, SharedMemType::ASHMEM) ||
+            isDirectChannelTypeSupported(sensor, SharedMemType::GRALLOC)) {
+            // Find a supported rate level
+            RateLevel rate = RateLevel::STOP;
+            if (isDirectReportRateSupported(sensor, RateLevel::NORMAL)) {
+                rate = RateLevel::NORMAL;
+            } else if (isDirectReportRateSupported(sensor, RateLevel::FAST)) {
+                rate = RateLevel::FAST;
+            } else if (isDirectReportRateSupported(sensor, RateLevel::VERY_FAST)) {
+                rate = RateLevel::VERY_FAST;
+            }
+
+            // Ensure that at least one rate level is supported
+            ASSERT_NE(rate, RateLevel::STOP);
+
+            // Verify that an invalid channel handle produces a BAD_VALUE result
+            configDirectReport(sensor.sensorHandle, -1, rate,
+                               [](Result result, int32_t /* reportToken */) {
+                                   ASSERT_EQ(result, Result::BAD_VALUE);
+                               });
+        }
+    }
+}
+
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV2_0::Instance());
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
index 5096498..819e297 100644
--- a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
+++ b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
@@ -35,6 +35,10 @@
     return mBuffer;
 }
 
+size_t SensorsTestSharedMemory::getSize() const {
+    return mSize;
+}
+
 std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
     constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
     constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
index 055b8e7..002f42c 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
@@ -33,6 +33,7 @@
     static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
     SharedMemInfo getSharedMemInfo() const;
     char* getBuffer() const;
+    size_t getSize() const;
     std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
     virtual ~SensorsTestSharedMemory();
 
diff --git a/soundtrigger/2.0/vts/functional/Android.bp b/soundtrigger/2.0/vts/functional/Android.bp
index be6b3a8..f6207c4 100644
--- a/soundtrigger/2.0/vts/functional/Android.bp
+++ b/soundtrigger/2.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalSoundtriggerV2_0TargetTest.cpp"],
     static_libs: ["android.hardware.soundtrigger@2.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/soundtrigger/2.1/vts/functional/Android.bp b/soundtrigger/2.1/vts/functional/Android.bp
index 925a17c..f1eb35d 100644
--- a/soundtrigger/2.1/vts/functional/Android.bp
+++ b/soundtrigger/2.1/vts/functional/Android.bp
@@ -25,4 +25,5 @@
                  "android.hardware.soundtrigger@2.1",
                  "libhidlmemory"
                  ],
+    test_suites: ["general-tests"],
 }
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
index 6bbca24..6c8be6c 100644
--- a/tests/msgq/1.0/default/Android.bp
+++ b/tests/msgq/1.0/default/Android.bp
@@ -54,6 +54,7 @@
         "libutils",
         "android.hardware.tests.msgq@1.0"
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -80,4 +81,5 @@
     // libs should be used on device.
     static_libs: ["android.hardware.tests.msgq@1.0"],
     whole_static_libs: ["android.hardware.tests.msgq@1.0-impl"],
+    test_suites: ["general-tests"],
 }
diff --git a/tetheroffload/config/1.0/vts/functional/Android.bp b/tetheroffload/config/1.0/vts/functional/Android.bp
index dc95eaa..52b9810 100644
--- a/tetheroffload/config/1.0/vts/functional/Android.bp
+++ b/tetheroffload/config/1.0/vts/functional/Android.bp
@@ -17,4 +17,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalTetheroffloadConfigV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.tetheroffload.config@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/tetheroffload/control/1.0/vts/functional/Android.bp b/tetheroffload/control/1.0/vts/functional/Android.bp
index c6216a2..e8e1414 100644
--- a/tetheroffload/control/1.0/vts/functional/Android.bp
+++ b/tetheroffload/control/1.0/vts/functional/Android.bp
@@ -20,4 +20,5 @@
         "android.hardware.tetheroffload.config@1.0",
         "android.hardware.tetheroffload.control@1.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/thermal/1.0/vts/functional/Android.bp b/thermal/1.0/vts/functional/Android.bp
index f661f1e..6bda558 100644
--- a/thermal/1.0/vts/functional/Android.bp
+++ b/thermal/1.0/vts/functional/Android.bp
@@ -19,5 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalThermalV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.thermal@1.0"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/thermal/1.1/vts/functional/Android.bp b/thermal/1.1/vts/functional/Android.bp
index f5f01fa..9a16c30 100644
--- a/thermal/1.1/vts/functional/Android.bp
+++ b/thermal/1.1/vts/functional/Android.bp
@@ -22,5 +22,6 @@
         "android.hardware.thermal@1.0",
         "android.hardware.thermal@1.1",
     ],
+    test_suites: ["general-tests"],
 }
 
diff --git a/tv/input/1.0/vts/functional/Android.bp b/tv/input/1.0/vts/functional/Android.bp
index 978830c..29181b0 100644
--- a/tv/input/1.0/vts/functional/Android.bp
+++ b/tv/input/1.0/vts/functional/Android.bp
@@ -19,5 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalTvInputV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.tv.input@1.0"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/usb/1.0/vts/functional/Android.bp b/usb/1.0/vts/functional/Android.bp
index 96d3c0e..683ee17 100644
--- a/usb/1.0/vts/functional/Android.bp
+++ b/usb/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalUsbV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.usb@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/usb/1.1/vts/functional/Android.bp b/usb/1.1/vts/functional/Android.bp
index 4bb3203..1f0972f 100644
--- a/usb/1.1/vts/functional/Android.bp
+++ b/usb/1.1/vts/functional/Android.bp
@@ -22,5 +22,6 @@
         "android.hardware.usb@1.0",
         "android.hardware.usb@1.1",
     ],
+    test_suites: ["general-tests"],
 }
 
diff --git a/vibrator/1.0/vts/functional/Android.bp b/vibrator/1.0/vts/functional/Android.bp
index 016d627..391d3d4 100644
--- a/vibrator/1.0/vts/functional/Android.bp
+++ b/vibrator/1.0/vts/functional/Android.bp
@@ -19,5 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalVibratorV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.vibrator@1.0"],
+    test_suites: ["general-tests"],
 }
 
diff --git a/vibrator/1.1/vts/functional/Android.bp b/vibrator/1.1/vts/functional/Android.bp
index 4f6454b..c65ff41 100644
--- a/vibrator/1.1/vts/functional/Android.bp
+++ b/vibrator/1.1/vts/functional/Android.bp
@@ -22,5 +22,6 @@
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
     ],
+    test_suites: ["general-tests"],
 }
 
diff --git a/vibrator/1.2/vts/functional/Android.bp b/vibrator/1.2/vts/functional/Android.bp
index 3a4e2ef..1e3ec97 100644
--- a/vibrator/1.2/vts/functional/Android.bp
+++ b/vibrator/1.2/vts/functional/Android.bp
@@ -23,5 +23,6 @@
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
     ],
+    test_suites: ["general-tests"],
 }
 
diff --git a/vr/1.0/vts/functional/Android.bp b/vr/1.0/vts/functional/Android.bp
index 4029137..958cce7 100644
--- a/vr/1.0/vts/functional/Android.bp
+++ b/vr/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalVrV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.vr@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/weaver/1.0/vts/functional/Android.bp b/weaver/1.0/vts/functional/Android.bp
index 0089d89..9fdbb18 100644
--- a/weaver/1.0/vts/functional/Android.bp
+++ b/weaver/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalWeaverV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.weaver@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index d0dd915..3189db4 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -48,6 +48,7 @@
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -61,4 +62,5 @@
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 1b0c12d..78d7a85 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -25,4 +25,5 @@
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index c5a6e84..a969f65 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -28,6 +28,7 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -43,4 +44,5 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/wifi/1.3/Android.bp b/wifi/1.3/Android.bp
index 5e87c1c..163a870 100644
--- a/wifi/1.3/Android.bp
+++ b/wifi/1.3/Android.bp
@@ -9,6 +9,7 @@
     srcs: [
         "types.hal",
         "IWifi.hal",
+        "IWifiChip.hal",
         "IWifiStaIface.hal",
     ],
     interfaces: [
diff --git a/wifi/1.3/IWifiChip.hal b/wifi/1.3/IWifiChip.hal
new file mode 100644
index 0000000..74d527d
--- /dev/null
+++ b/wifi/1.3/IWifiChip.hal
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.3;
+
+import @1.0::WifiStatus;
+import @1.2::IWifiChip;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+interface IWifiChip extends @1.2::IWifiChip {
+
+    /**
+     * Capabilities exposed by this chip.
+     */
+    enum ChipCapabilityMask : @1.2::IWifiChip.ChipCapabilityMask {
+        /**
+         * Set Latency Mode.
+         */
+         SET_LATENCY_MODE = 1 << 12
+    };
+
+    /**
+     * Get the capabilities supported by this chip.
+     *
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return capabilities Bitset of |ChipCapabilityMask| values.
+     */
+    getCapabilities_1_3()
+      generates (WifiStatus status, bitfield<ChipCapabilityMask> capabilities);
+
+    /**
+     * This enum represents the different latency modes that can be set through
+     * setLatencyMode()
+     */
+    enum LatencyMode : uint32_t {
+        NORMAL    = 0,
+        LOW       = 1
+    };
+
+    /**
+     * API to set the wifi latency mode
+     *
+     * Latency mode determines whether or not to optimize for reducing wifi
+     * latency as a tradeoff with other wifi functionality such as scanning,
+     * roaming, etc. This optimization is suitable for some applications such
+     * as gaming and virtual reality applications.
+     */
+    setLatencyMode(LatencyMode mode) generates (WifiStatus status);
+};
diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp
index 7a920b4..79c5183 100644
--- a/wifi/hostapd/1.0/vts/functional/Android.bp
+++ b/wifi/hostapd/1.0/vts/functional/Android.bp
@@ -49,4 +49,5 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/wifi/offload/1.0/vts/functional/Android.bp b/wifi/offload/1.0/vts/functional/Android.bp
index 140e45e..de15aa7 100644
--- a/wifi/offload/1.0/vts/functional/Android.bp
+++ b/wifi/offload/1.0/vts/functional/Android.bp
@@ -19,4 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalWifiOffloadV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.wifi.offload@1.0"],
+    test_suites: ["general-tests"],
 }
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index ee6a68e..bdccac1 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -39,7 +39,6 @@
     srcs: [
         "VtsHalWifiSupplicantV1_0TargetTest.cpp",
         "supplicant_hidl_test.cpp",
-        "supplicant_p2p_iface_hidl_test.cpp",
         "supplicant_sta_iface_hidl_test.cpp",
         "supplicant_sta_network_hidl_test.cpp",
     ],
@@ -54,4 +53,25 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
+    test_suites: ["general-tests"],
+}
+
+cc_test {
+    name: "VtsHalWifiSupplicantP2pV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiSupplicantV1_0TargetTest.cpp",
+        "supplicant_p2p_iface_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi@1.0",
+        "libcrypto",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
 }
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
index adf2a85..6ca0546 100644
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
@@ -44,7 +44,10 @@
     ::testing::AddGlobalTestEnvironment(gEnv);
     ::testing::InitGoogleTest(&argc, argv);
     gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        int status = RUN_ALL_TESTS();
+        LOG(INFO) << "Test result = " << status;
+    }
     return status;
 }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
index c6ac03c..436b88b 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
@@ -30,6 +30,8 @@
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 
+extern WifiSupplicantHidlEnvironment* gEnv;
+
 class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    public:
     virtual void SetUp() override {
@@ -72,10 +74,13 @@
               std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
                   return iface.type == IfaceType::STA;
               }));
-    EXPECT_NE(ifaces.end(),
-              std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
-                  return iface.type == IfaceType::P2P;
-              }));
+    if (gEnv->isP2pOn) {
+        EXPECT_NE(
+            ifaces.end(),
+            std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
+                return iface.type == IfaceType::P2P;
+            }));
+    }
 }
 
 /*
@@ -178,8 +183,10 @@
         IfaceType::STA, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
         });
-    supplicant_->setConcurrencyPriority(
-        IfaceType::P2P, [](const SupplicantStatus& status) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-        });
+    if (gEnv->isP2pOn) {
+        supplicant_->setConcurrencyPriority(
+            IfaceType::P2P, [](const SupplicantStatus& status) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            });
+    }
 }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index bdedfba..47c3056 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -225,7 +225,9 @@
     // For 1.1 supplicant, we need to add interfaces at initialization.
     if (is_1_1(supplicant)) {
         addSupplicantStaIface_1_1(supplicant);
-        addSupplicantP2pIface_1_1(supplicant);
+        if (gEnv->isP2pOn) {
+            addSupplicantP2pIface_1_1(supplicant);
+        }
     }
     return supplicant;
 }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index d4a768f..21a1ae6 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -23,6 +23,8 @@
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
 
+#include <getopt.h>
+
 #include <VtsHalHidlTargetTestEnvBase.h>
 
 // Used to stop the android wifi framework before every test.
@@ -50,11 +52,48 @@
 
 class WifiSupplicantHidlEnvironment
     : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
+   protected:
     virtual void HidlSetUp() override { stopSupplicant(); }
     virtual void HidlTearDown() override {
         startSupplicantAndWaitForHidlService();
     }
+
+   public:
+    // Whether P2P feature is supported on the device.
+    bool isP2pOn = true;
+
+    void usage(char* me, char* arg) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --p2p_on: Whether P2P feature is supported\n",
+                arg, me);
+    }
+
+    int initFromOptions(int argc, char** argv) {
+        static struct option options[] = {{"p2p_off", no_argument, 0, 'P'},
+                                          {0, 0, 0, 0}};
+
+        int c;
+        while ((c = getopt_long(argc, argv, "P", options, NULL)) >= 0) {
+            switch (c) {
+                case 'P':
+                    isP2pOn = false;
+                    break;
+                default:
+                    usage(argv[0], argv[optind]);
+                    return 2;
+            }
+        }
+
+        if (optind < argc) {
+            usage(argv[0], argv[optind]);
+            return 2;
+        }
+
+        return 0;
+    }
 };
 
 #endif /* SUPPLICANT_HIDL_TEST_UTILS_H */
diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
index 3e65453..353ae4b 100644
--- a/wifi/supplicant/1.1/vts/functional/Android.bp
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -56,4 +56,5 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
index 3d24fc3..9063a3b 100644
--- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
+++ b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
@@ -30,8 +30,11 @@
         return instance;
     }
     virtual void registerTestServices() override {
+        registerTestService<::android::hardware::wifi::V1_0::IWifi>();
         registerTestService<::android::hardware::wifi::V1_1::IWifi>();
         registerTestService<
+            ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
+        registerTestService<
             ::android::hardware::wifi::supplicant::V1_1::ISupplicant>();
     }
 
@@ -46,7 +49,10 @@
     ::testing::AddGlobalTestEnvironment(gEnv);
     ::testing::InitGoogleTest(&argc, argv);
     gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        int status = RUN_ALL_TESTS();
+        LOG(INFO) << "Test result = " << status;
+    }
     return status;
 }
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
index 7e773d6..28f980c 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
@@ -33,6 +33,8 @@
 using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
 using ::android::sp;
 
+extern WifiSupplicantHidlEnvironment* gEnv;
+
 class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    public:
     virtual void SetUp() override {
@@ -81,6 +83,7 @@
  * AddP2pInterface
  */
 TEST_F(SupplicantHidlTest, AddP2pInterface) {
+    if (!gEnv->isP2pOn) return;
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getP2pIfaceName();
     iface_info.type = IfaceType::P2P;
@@ -120,6 +123,7 @@
  * RemoveP2pInterface
  */
 TEST_F(SupplicantHidlTest, RemoveP2pInterface) {
+    if (!gEnv->isP2pOn) return;
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getP2pIfaceName();
     iface_info.type = IfaceType::P2P;
diff --git a/wifi/supplicant/1.2/Android.bp b/wifi/supplicant/1.2/Android.bp
index bafd148..93ce573 100644
--- a/wifi/supplicant/1.2/Android.bp
+++ b/wifi/supplicant/1.2/Android.bp
@@ -7,6 +7,8 @@
         enabled: true,
     },
     srcs: [
+        "ISupplicant.hal",
+        "ISupplicantStaIface.hal",
         "ISupplicantStaNetwork.hal",
     ],
     interfaces: [
diff --git a/wifi/supplicant/1.2/ISupplicant.hal b/wifi/supplicant/1.2/ISupplicant.hal
new file mode 100644
index 0000000..b0ec65d
--- /dev/null
+++ b/wifi/supplicant/1.2/ISupplicant.hal
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.2;
+
+import @1.1::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.2 features you must cast specific interfaces returned from the
+ * 1.1 HAL. For example V1_1::ISupplicant::addIface() adds V1_1::ISupplicantIface,
+ * which can be cast to V1_2::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.1::ISupplicant {
+};
diff --git a/wifi/supplicant/1.2/ISupplicantStaIface.hal b/wifi/supplicant/1.2/ISupplicantStaIface.hal
new file mode 100644
index 0000000..a338c6a
--- /dev/null
+++ b/wifi/supplicant/1.2/ISupplicantStaIface.hal
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.2;
+
+import @1.0::SupplicantStatus;
+import @1.1::ISupplicantStaIface;
+import @1.2::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+interface ISupplicantStaIface extends @1.1::ISupplicantStaIface {
+
+    /**
+     * Get Key management capabilities of the device
+     *
+     * @return status Status of the operation, and a bitmap of key management mask.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    getKeyMgmtCapabilities()
+        generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+};
+
diff --git a/wifi/supplicant/1.2/ISupplicantStaNetwork.hal b/wifi/supplicant/1.2/ISupplicantStaNetwork.hal
index 85b233d..6fd0d51 100644
--- a/wifi/supplicant/1.2/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.2/ISupplicantStaNetwork.hal
@@ -256,17 +256,4 @@
      */
     setSaePasswordId(string saePasswordId)
         generates (SupplicantStatus status);
-
-    /**
-     * Get Key management capabilities of the device
-     *
-     * @return status Status of the operation, and a string.
-     *         Possible status codes:
-     *         |SupplicantStatusCode.SUCCESS|,
-     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
-     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
-     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
-     */
-    getKeyMgmtCapabilities()
-        generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
 };